2012-02-15 16 views
6

En una de mis aplicaciones tengo una actividad en la que el habla sintetiza cadenas de referencia alfanuméricas, letra/número por letra/número, por ejemplo, "ABC123" suena como "Ay, bee, sea, one two three" . Como se trata de un conjunto limitado de sonidos, pensé que sería bueno habilitar el motor TTS para trabajar sin una conexión a Internet al reproducir archivos .wav pregrabados de los números y letras utilizando el método playEarcon.TextToSpeech, playEarcon y archivos .wav

He colocado todos los 36 archivos wav en la carpeta res/raw y asigné los ID de recursos a las letras al inicializar el motor TTS. Esto funciona bien, sin embargo el .apk ahora es mucho más grande ya que los archivos wav se almacenan sin comprimir en la apk. Me gustaría reducir el tamaño del apk.

En the answer to another question indica que los archivos wav están excluidos de la compresión. (No veo por qué, ya que normalmente se comprimen hasta aproximadamente el 40% del original). Al inspeccionar las partes internas de la aplicación, esto parece ser cierto.

Como la extensión de los archivos de recursos no se menciona en el código, traté de cambiar el nombre de los wavs, a varios .waw, .abc, .spc. Todos estos se comprimen, pero desafortunadamente el método playEarcon no produce ningún sonido cuando se invoca a menos que la extensión sea .wav.

En resumen, me gustaría obligar al motor TTS a reproducir archivos sin una extensión wav, o persuadirlo para que comprima los archivos .wav.

Todas las sugerencias serán recibidas con gratitud. Por lo que vale, estoy publicando el ejemplo de código demostrable más pequeño a continuación. Mis archivos de trabajo se llaman gb_a.wav, gb_b.wav, etc. Si se modifica la extensión, dejan de sonar.

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

. .

Respuesta

1
  1. Por qué los archivos wav no se intentan comprimir: according wikipedia wav file es un contenedor de datos. Más frecuentemente se usa para sonido PCM sin comprimir, pero también se puede usar para almacenar datos comprimidos con varios códecs (puede encontrar valores posibles para wFormatTags (escriba para datos almacenados) por ejemplo here).
  2. Puede guardar su recurso en el sistema de archivos local y usar addEarcon(String earcon, String filename) en lugar de addEarcon(String earcon, String packagename, int resourceId).
  3. Puede usar aapt con el interruptor de línea -0 wav cmd para hacer apk con archivos wav excluidos de los tipos comprimidos.
+0

Re your points (1) - es el proceso de compilación de Android que los excluye de la compresión (ver el enlace que cité), quería encontrar una manera de anular esto. (2) Quiero empaquetar los wavs en mi apk (3) ¿Por qué querría excluirlos de la compresión? Ya están excluidos, ese es el punto de esta pregunta: ¡quiero comprimirlos! – NickT

+0

sobre (3), lo siento, mi error. Bueno, creo que puedes descargar las fuentes de herramienta aapt, excluir wav de tipos no comprimidos por defecto, reconstruirlo y hacer tu apt con esta nueva herramienta. Pero no probé esto, por lo que es posible que AssetManager se niegue a cargar dicho recurso. –

0

Debe intentar convertir el archivo wav en un archivo ogg, luego obtendrá la mejor tasa de compresión para el archivo de sonido.