Skip to content

Commit 0c85bfb

Browse files
IhorShevchukIhor Shevchuk
andauthored
feat: add pinyin support (chaowen, xiao_ya) (#46)
* feat: add pinyin support (chaowen, xiao_ya) - bump piper-objc to 0.2.35 for piper_create_with_options + PiperCreateOptions - use PiperCreateOptions with dataDir/g2pwModelDir from model folder to enable Chinese pinyin voices - remove chaowen/xiao_ya from unsupportedVoices now that piper-objc supports them Requires piper-objc PR #10 merged (dadde0b) which is in 0.2.35 * feat: on-demand g2pw Phase 1 for Chinese pinyin (2MB lean) - Add phoneme_type to ModelInfo with isPinyin flag to detect pinyin voices - Add shared g2pw folder in App Group (group.pipertts.data/g2pw) for on-demand 2MB Phase 1 dicts - Add G2PWDataManager: copies from bundle (offline) or downloads 3 files from GitHub release g2pw-mini-v1 (MONOPHONIC_CHARS.txt 118K, char_bopomofo_dict.json 1.8M, bopomofo_to_pinyin_wo_tune_dict.json 7.6K) - VoiceLoader: ensure g2pw installed on first Chinese voice download (pinyin) - PiperTTSAudioUnit: use shared g2pw folder for pinyin voices, fallback to model folder - Bundle mini dicts in PiperAppUtils/Resources/g2pw for offline CI and fast first-copy (2MB, no RAM until used) - Hosted assets: https://github.com/IhorShevchuk/piper-app/releases/tag/g2pw-mini-v1 - Keeps IPA lean, RAM tiny (no 152M onnx), covers 95% monophonic chars for chaowen/xiao_ya * feat: pure on-demand g2pw download (0 IPA) - Remove bundled g2pw dicts from IPA (1.9M) – keep IPA lean per user request - G2PWDataManager now pure download from GitHub release g2pw-mini-v1 (3 files: MONOPHONIC_CHARS.txt, char_bopomofo_dict.json, bopomofo_to_pinyin_wo_tune_dict.json) - Voice install already requires network, so no extra failure mode - Once cached in group.pipertts.data/g2pw, synthesis works offline - PiperTTSAudioUnit uses shared g2pw folder for pinyin voices, fallback to model folder - Keeps RAM tiny (no 152M onnx), covers 95% monophonic chars for chaowen/xiao_ya * feat: isolate pinyin g2pw changes to PiperApp folder (pure on-demand 0 IPA) - Keep all new logic in PiperApp/Sources/Utils/G2PWDataManager.swift (pure download from GitHub release g2pw-mini-v1) - VoiceLoader in PiperApp detects zh voices via language code + JSON phoneme_type, ensures g2pw on first zh install - FileManager.install in PiperApp copies shared g2pw dicts into voice folder for offline synthesis - PiperAppUtils/FileManager/FIleConstants.swift: add shared g2pwFolderURL + required files (minimal shared) - PiperTTS: use modern PiperCreateOptions with dataDir/g2pwModelDir for zh voices (prefers shared g2pw folder, fallback to model folder) - Revert ModelInfo isPinyin (detect via JSON directly in VoiceLoader to keep PiperAppUtils unchanged) - Remove bundled g2pw resources – 0 IPA hit, RAM tiny, covers 95% monophonic chars for chaowen/xiao_ya - Comments updated to explain on-demand download (voice install already needs network, so no extra failure mode) * feat: option 5 – xcassets compressed g2pw (300K IPA, offline, no server) - Add PiperApp/Resources/G2PW.xcassets with 3 data assets: MONOPHONIC_CHARS.txt (118K), char_bopomofo_dict.json (1.8M), bopomofo_to_pinyin_wo_tune_dict.json (7.6K) - Asset catalog compresses to ~300K in IPA (vs 1.9M raw), lazy-loaded via NSDataAsset (zero RAM until first zh voice) - G2PWDataManager now primary copies from xcassets NSDataAsset to App Group g2pw/ (offline, no network) - Fallback to GitHub release download if asset not found (tests) - VoiceLoader + FileManager.install keep same flow: ensure g2pw in shared folder, copy into voice folder for offline synthesis - Project.swift: include G2PW.xcassets in PiperApp target resources - Keeps changes isolated to PiperApp folder (plus minimal shared constants in PiperAppUtils for App Group) - No external server, no download failures, works offline, covers 95% monophonic chars for chaowen/xiao_ya * feat: drop fallback download – pure xcassets offline (option 5) - Remove GitHub release download fallback from G2PWDataManager - ensureInstalled() now only copies from NSDataAsset in G2PW.xcassets to shared g2pw/ - No network, no URLSession, no GitHub dependency – pure offline, 300K compressed IPA - VoiceLoader calls synchronous ensureInstalled() (no await) on first zh voice install - Keeps RAM tiny, covers 95% monophonic chars for chaowen/xiao_ya * chore: remove duplicate G2PWDataManager – keep only PiperApp version - Delete PiperAppUtils/G2PW/G2PWDataManager.swift (duplicate) - Keep single source of truth in PiperApp/Sources/Utils/G2PWDataManager.swift (option 5 xcassets) - PiperAppUtils only keeps shared FileManager.Constants.g2pwFolderURL + required files * chore: update outdated comments for option 5 xcassets - VoiceLoader: remove 'download 2MB' wording, now xcassets offline - FileManager.install: simplify comment (no longer mentions isolating to PiperApp) - PiperTTSAudioUnit: update to xcassets wording, not on-demand download - FIleConstants: update MARK comment from 0 IPA to 300K IPA xcassets compressed * chore: drop unneeded comments to avoid staleness - Remove explanatory comments in G2PWDataManager, VoiceLoader, FileManager, PiperTTSAudioUnit, FIleConstants - Keep code self-explanatory, no option numbers or IPA size in comments - Prevents stale docs as implementation evolves * fix: build + simplify pinyin detection - Fix G2PW.xcassets dataset Contents.json: idiom universal (was invalid universal:true causing exit 65) - Rename fm to fileManager, fix implicit optional init, vertical whitespace - Simplify isPinyinVoice to just language code check (zh prefix), drop Data(contentsOf:) + JSONSerialization - Reduce VoiceLoader function_body_length via helper extraction * fix: remaining fm identifier_name - Fix copyToModelFolder still using let fm (was causing fileManager not found) - Now zero fm violations in PR files * refactor: use Decodable VoiceConfig for pinyin detection - Add Models/VoiceConfig.swift Decodable with phoneme_type - Replace JSONSerialization/Any cast closure with JSONDecoder decode - Keep zh prefix fast path, fallback to decoded phonemeType == pinyin - Addresses fm identifier_name warning by removing manual parsing clutter * fix: increase audio buffer from 5s to 120s to prevent middle-drop on long utterances - 5s max caused FloatRingBuffer to drop oldest unread samples when Piper synthesizes faster than AU consumes, leading to 'starts then skips to end' on long sentences/paragraphs (#24, reported on pinyin branch) - Increase maxBufferDurationSeconds to 120s (~2.6M floats, ~10MB worst case) to hold typical long Speak Screen / VoiceOver continuous reading - Keeps max enforcement for OOM safety but large enough for real use * Fixed a few build errors * chore: bump piper-objc to 0.2.37 for relaxed poly fallback, restore full Package.swift * chore: update Package.resolved for piper-objc 0.2.37 * fix: Samples.json zh_CN to simplified, only piper-readable symbols * chore: bump piper-objc to 0.2.38 for linker fix (chinese_phonemizer) * added missed new line --------- Co-authored-by: Ihor Shevchuk <ihor@ihor-shevchuk.dev>
1 parent d02035a commit 0c85bfb

20 files changed

Lines changed: 145767 additions & 61 deletions

File tree

Package.resolved

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import PackageDescription
1818
let package = Package(
1919
name: "Piper",
2020
dependencies: [
21-
.package(url: "https://github.com/IhorShevchuk/piper-objc", from: "0.2.36")
21+
.package(url: "https://github.com/IhorShevchuk/piper-objc", from: "0.2.38")
2222
],
2323
targets: [] // Tuist uses this only to resolve deps; targets are in Project.swift via .external()
2424
)

PiperApp/Resources/Assets.xcassets/Samples.dataset/Samples.json

Lines changed: 43 additions & 43 deletions
Large diffs are not rendered by default.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"info" : {
3+
"author" : "xcode",
4+
"version" : 1
5+
}
6+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"data" : [
3+
{
4+
"filename" : "MONOPHONIC_CHARS.txt",
5+
"idiom" : "universal"
6+
}
7+
],
8+
"info" : {
9+
"author" : "xcode",
10+
"version" : 1
11+
}
12+
}

0 commit comments

Comments
 (0)