2012-02-15 85 views
6

在我的一個應用程序中,我有一個語音合成字母數字參考字符串,字母/數字,字母/數字的活動,例如「ABC123」聽起來像「Ay,bee,sea,one two three」 。由於這是一組有限的聲音,我認爲通過使用playEarcon方法播放預先錄製的數字和字母的.wav文件,可以使TTS引擎在沒有互聯網連接的情況下工作。TextToSpeech,playEarcon和.wav文件

我已經將所有36個wav文件放在res/raw文件夾中,並在初始化TTS引擎時將資源id映射到字母。這效果很好,但是.apk現在更大,因爲wav文件在apk中未壓縮存儲。我想使apk的大小更小。

the answer to another question它聲明wav文件從壓縮中排除。 (我不明白爲什麼,因爲它們通常會壓縮到原來的大約40%)。一次檢查apk的內部,這看起來是真的。

由於代碼中沒有引用資源文件的擴展名,我嘗試將wavs重命名爲各種.waw,.abc,.spc。所有這些都得到壓縮,但不幸的是playEarcon方法在調用時不產生聲音,除非擴展名是.wav。

總之我想強制TTS引擎播放沒有wav擴展名的文件,或者說服它壓縮.wav文件。

所有的建議將受到感謝。我發佈了下面最小的可展示代碼示例,值得一提。我的工作文件被命名爲gb_a.wav,gb_b.wav等。如果擴展名被改變,他們停止發聲。

public class WavSpeakerActivity extends Activity implements 
     RadioGroup.OnCheckedChangeListener, TextToSpeech.OnInitListener { 

    static final int mGBLetterResIds[] = { R.raw.gb_a, R.raw.gb_b, R.raw.gb_c, 
      R.raw.gb_d, R.raw.gb_e, R.raw.gb_f, R.raw.gb_g, R.raw.gb_h, 
      R.raw.gb_i, R.raw.gb_j, R.raw.gb_k, R.raw.gb_l, R.raw.gb_m, 
      R.raw.gb_n, R.raw.gb_o, R.raw.gb_p, R.raw.gb_q, R.raw.gb_r, 
      R.raw.gb_s, R.raw.gb_t, R.raw.gb_u, R.raw.gb_v, R.raw.gb_w, 
      R.raw.gb_x, R.raw.gb_y, R.raw.gb_z }; 
    static final int mGBNumberResIds[] = { R.raw.gb_zero, R.raw.gb_one, 
      R.raw.gb_two, R.raw.gb_three, R.raw.gb_four, R.raw.gb_five, 
      R.raw.gb_six, R.raw.gb_seven, R.raw.gb_eight, R.raw.gb_nine }; 

    static final String mGbStr = "GB"; 
    static final String mAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
    static final String mNumbers = ""; 
    private String mPpackageName = null; 
    private String mTextToSpeak = null; 
    private RadioGroup mRadioGroup = null;// two buttons one sets letters, the other numbers 
    private TextToSpeech mTts = null; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     mTts = new TextToSpeech(this, this); 
     mRadioGroup = (RadioGroup) findViewById(R.id.radioGroup1); 
     mRadioGroup.setOnCheckedChangeListener(this); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     RadioGroup rg = (RadioGroup) findViewById(R.id.radioGroup1); 
     switchText(rg); 
     mPpackageName = getPackageName(); 
    } 

    @Override 
    public void onDestroy() { 
     // Don't forget to shutdown speech engine 
     if (mTts != null) { 
      mTts.stop(); 
      mTts.shutdown(); 
     } 
     super.onDestroy(); 
    } 

    private void switchText(RadioGroup rg) { 
     // select letters or digits as the String to speak 
     int checkedButton = rg.getCheckedRadioButtonId(); 
     switch (checkedButton) { 
      case R.id.alphabet: 
       mTextToSpeak = mAlphabet; 
       break; 
      case R.id.numbers: 
       mTextToSpeak = mNumbers; 
       break; 
     } 
    } 

    public void myClickHandler(View target) { 
     // Just the one button has been clicked - the 'Speak' one 
     String earconKey; 
     String lang = Locale.UK.getCountry(); // will be "GB", just have UK in this small example 
     mTts.setLanguage(Locale.UK); // skip error checking for brevity's sake 
     String text = mTextToSpeak.replaceAll("\\s", "");// remove spaces (if any) 
     char c; 
     for (int i = 0; i < text.length(); i++) { 
      c = text.charAt(i); 
      if (Character.isLetter(c) || Character.isDigit(c)) { 
       earconKey = lang + Character.toString(c); // GBA, GBB..GBZ, GB0.. GB9 
       mTts.playEarcon(earconKey, TextToSpeech.QUEUE_ADD, null); 
      } 
     } 
    } 

    @Override 
    public void onInit(int status) { 
     // doesn't seem we need to check status or setLanguage if we're just playing earcons 
     mapEarCons(); // map letter/digit sounds to resource ids 
    } 

    private void mapEarCons() { 
     String key; 
     for (char c = 'A'; c <= 'Z' ; c++){ 
      key = mGbStr + Character.toString(c); // GBA, GBB .. GBZ 
      mTts.addEarcon(key, mPpackageName, mGBLetterResIds[c - 'A']);// add it 
     } 
     for (int i = 0 ; i <= 9; i++){ 
      key = mGbStr + Integer.toString(i); // GB0, GB1 .. GB9 
      mTts.addEarcon(key, mPpackageName, mGBNumberResIds[i]); 
     } 
    } 

    @Override 
    public void onCheckedChanged(RadioGroup rg, int arg1) { switchText(rg); } 
} 

。 。

回答

1
  1. 爲什麼wav文件沒有試圖壓縮:according wikipedia wav文件是數據的容器。大多數情況下,它用於未壓縮的PCM聲音,但也可用於存儲使用各種編解碼器壓縮的數據(可找到wFormatTags(存儲數據的類型)的可能值,例如here)。
  2. 您可以將資源保存到本地文件系統,並使用addEarcon(String earcon, String filename)而不是addEarcon(String earcon, String packagename, int resourceId)
  3. 您可以使用帶有-0 wav cmd行開關的aapt來製作apk,其中包含從壓縮類型中排除的wav文件。
+0

重申您的觀點(1) - 這是Android構建過程,它們將它們從壓縮中排除(請參閱我引用的鏈接),我想找到一種方法來覆蓋它。 (2)我想在我的apk中打包wavs(3)爲什麼我想要將它們從壓縮中排除?他們已經被排除在外,這就是這個問題的要點 - 我想壓縮它們! (3)關於 – NickT 2012-02-23 16:21:39

+0

,對不起我的錯誤。那麼,我認爲,您可以下載aapt工具源碼,將wav從默認情況下不壓縮的類型中排除,重新構建它並使用這個新工具創建適配器。但是我沒有嘗試這個 - 所以AssetManager可能會拒絕加載這樣的資源。 – 2012-02-23 16:36:08

0

您應該嘗試將wav文件轉換爲ogg文件,然後您將獲得最佳的聲音文件壓縮率。