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