2012-02-15 14 views
6

W jednej z moich aplikacji mam aktywność, która syntetyzuje alfanumeryczne ciągi referencyjne, litera/liczba za literę/cyfrę np. "ABC123" brzmi "Ay, bee, sea, one two three" . Ponieważ jest to ograniczony zestaw dźwięków, pomyślałem, że dobrze byłoby włączyć silnik TTS do pracy bez połączenia z Internetem, odtwarzając nagrane pliki .wav liczb i liter za pomocą metody playEarcon.TextToSpeech, playEarcon i pliki .wav

Umieściłem wszystkie 36 plików WAV w folderze res/raw i zmapowałem identyfikatory zasobów na litery podczas inicjowania silnika TTS. Działa to dobrze, jednak .apk jest teraz znacznie większy, ponieważ pliki wav są przechowywane nieskompresowane w apk. Chciałbym zmniejszyć rozmiar apk'a.

W pliku the answer to another question stwierdza, że ​​pliki wav są wykluczone z kompresji. (Nie rozumiem, dlaczego, ponieważ zwykle sprowadzają się one do około 40% oryginału). Sprawdzając elementy wewnętrzne apk, wydaje się to prawdą.

Ponieważ rozszerzenie plików zasobów nie jest wymienione w kodzie, próbowałem zmienić nazwę wavs, na różne .waw, .abc, .spc. Wszystkie te kompresują się, ale metoda playEarcon nie generuje dźwięku po wywołaniu, chyba że rozszerzeniem jest .wav.

W skrócie, chciałbym przymusić silnik TTS do odtwarzania plików bez rozszerzenia wav, lub przekonać go do kompresji plików .wav.

Wszystkie sugestie zostaną przyjęte z wdzięcznością. O ile warto, zamieszczam poniżej najmniejszy możliwy przykład kodu. Moje pliki robocze mają nazwę gb_a.wav, gb_b.wav itd. Jeśli rozszerzenie zostało zmienione, przestają one brzmieć.

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); } 
} 

. .

Odpowiedz

1
  1. Dlaczego wav nie starał się być skompresowane: according wikipedia wav jest kontenerem dla danych. Najczęściej jest używany do nieskompresowanego dźwięku PCM, ale może być również używany do przechowywania danych skompresowanych za pomocą różnych kodeków (można znaleźć możliwe wartości dla wFormatTags (typ dla zapisanych danych), na przykład here).
  2. Możesz zapisać swój zasób w lokalnym systemie plików i użyć addEarcon(String earcon, String filename) zamiast addEarcon(String earcon, String packagename, int resourceId).
  3. Możesz użyć aapt z przełącznikiem linii poleceń -0 wav, aby zrobić apk z plikami wav wykluczonymi ze skompresowanych typów.
+0

Re your points (1) - to proces budowania systemu Android, który wyklucza ich z kompresji (patrz link cytowany), chciałem znaleźć sposób, aby to zmienić. (2) Chcę spakować pliki WAV w moim apk (3) Dlaczego chciałbym wykluczyć je z kompresji? Oni już są wykluczeni, to jest sedno tego pytania - chcę je skompresować! – NickT

+0

about (3), przepraszam, mój błąd. Cóż, myślę, że możesz pobrać źródła narzędzi Aapt, wykluczyć wav z typów domyślnie nieskompresowanych, przebudować go i zrobić apt za pomocą tego nowego narzędzia. Ale nie próbowałem tego - więc jest możliwe, że AssetManager odmawia załadowania takiego zasobu. –

0

Powinieneś spróbować przekonwertować plik wav na plik ogg, wtedy uzyskasz najlepszą kompresję dla pliku dźwiękowego.