In one of my applications I have an activity which speech synthesises alphanumeric reference strings, letter/number by letter/number e.g "ABC123" sounds as "Ay, bee, sea, one two three". As this is a limited set of sounds I thought it would be good to enable the TTS engine to work without an internet connection by playing prerecorded .wav files of the numbers and letters using the playEarcon method.
I have placed all 36 wav files in the res/raw folder and mapped the resource ids to the letters when initialising the TTS engine. This works well, however the .apk is now much larger as the wav files are stored uncompressed in the apk. I would like to make the apk's size smaller.
In the answer to another question it states that wav files are excluded from compression. ( I don't see why, as they typically zip down to about 40% of the original) One inspecting the apk's internals, this appears to be true.
As the extension of the resource files is not referred to in the code, I tried renaming the wavs, to variously .waw, .abc, .spc. All of these get compressed but unfortunately the playEarcon method produces no sound when invoked unless the extension is .wav.
In short I would like to coerce the TTS engine into playing files without a wav extension, or persuade it to compress the .wav files.
All suggestions will be gratefully received. For what it's worth I'm posting the smallest demonstrable code sample below. My working files are named gb_a.wav, gb_b.wav etc. If the extension is changed, they stop sounding.
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 = "0123456789";
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); }
}
. .
wFormatTags
( type for stored data ) for example here ).addEarcon(String earcon, String filename)
instead of addEarcon(String earcon, String packagename, int resourceId)
.-0 wav
cmd line switch to make apk with wav files excluded from compressed types.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With