PageRenderTime 50ms CodeModel.GetById 2ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 0ms

/androidsays/src/com/google/marvin/androidsays/SfxController.java

http://eyes-free.googlecode.com/
Java | 281 lines | 224 code | 24 blank | 33 comment | 55 complexity | 68e4d197b0d786e5d50aca3f6bda2e0a MD5 | raw file
  1/*
  2 * Copyright (C) 2008 Google Inc.
  3 * 
  4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5 * use this file except in compliance with the License. You may obtain a copy of
  6 * the License at
  7 * 
  8 * http://www.apache.org/licenses/LICENSE-2.0
  9 * 
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 13 * License for the specific language governing permissions and limitations under
 14 * the License.
 15 */
 16package com.google.marvin.androidsays;
 17
 18import android.content.Context;
 19import android.media.MediaPlayer;
 20import android.media.MediaPlayer.OnCompletionListener;
 21import android.net.Uri;
 22
 23import java.util.ArrayList;
 24import java.util.HashMap;
 25import java.util.concurrent.locks.ReentrantLock;
 26
 27/**
 28 * Controls the playback of sound effects.
 29 * 
 30 * @author clchen@google.com (Charles L. Chen)
 31 */
 32public class SfxController implements OnCompletionListener {
 33
 34  private ArrayList<String> soundQueue;
 35  private MediaPlayer player;
 36  private HashMap<String, SoundResource> sounds;
 37  private boolean isPlaying;
 38  private Context ctx;
 39
 40  private final ReentrantLock soundQueueLock = new ReentrantLock();
 41
 42  public SfxController(Context contextObject) {
 43    ctx = contextObject;
 44    soundQueue = new ArrayList<String>();
 45    sounds = new HashMap<String, SoundResource>();
 46    player = null;
 47    isPlaying = false;
 48    sounds.put("[right]", new SoundResource(R.raw.right_snd));
 49    sounds.put("[wrong]", new SoundResource(R.raw.wrong_snd));
 50    sounds.put("Game over. Your score is:", new SoundResource(R.raw.game_over));
 51    sounds.put("Android says:", new SoundResource(R.raw.android_says));
 52    sounds.put("0", new SoundResource(R.raw.num0_robot_));
 53    sounds.put("1", new SoundResource(R.raw.num1_robot_));
 54    sounds.put("2", new SoundResource(R.raw.num2_robot_));
 55    sounds.put("3", new SoundResource(R.raw.num3_robot_));
 56    sounds.put("4", new SoundResource(R.raw.num4_robot_));
 57    sounds.put("5", new SoundResource(R.raw.num5_robot_));
 58    sounds.put("6", new SoundResource(R.raw.num6_robot_));
 59    sounds.put("7", new SoundResource(R.raw.num7_robot_));
 60    sounds.put("8", new SoundResource(R.raw.num8_robot_));
 61    sounds.put("9", new SoundResource(R.raw.num9_robot_));
 62    sounds.put("10", new SoundResource(R.raw.num10_robot_));
 63    sounds.put("11", new SoundResource(R.raw.num11_robot_));
 64    sounds.put("12", new SoundResource(R.raw.num12_robot_));
 65    sounds.put("13", new SoundResource(R.raw.num13_robot_));
 66    sounds.put("14", new SoundResource(R.raw.num14_robot_));
 67    sounds.put("15", new SoundResource(R.raw.num15_robot_));
 68    sounds.put("16", new SoundResource(R.raw.num16_robot_));
 69    sounds.put("17", new SoundResource(R.raw.num17_robot_));
 70    sounds.put("18", new SoundResource(R.raw.num18_robot_));
 71    sounds.put("19", new SoundResource(R.raw.num19_robot_));
 72    sounds.put("20", new SoundResource(R.raw.num20_robot_));
 73    sounds.put("30", new SoundResource(R.raw.num30_robot_));
 74    sounds.put("40", new SoundResource(R.raw.num40_robot_));
 75    sounds.put("50", new SoundResource(R.raw.num50_robot_));
 76    sounds.put("60", new SoundResource(R.raw.num60_robot_));
 77    sounds.put("70", new SoundResource(R.raw.num70_robot_));
 78    sounds.put("80", new SoundResource(R.raw.num80_robot_));
 79    sounds.put("90", new SoundResource(R.raw.num90_robot_));
 80    sounds.put("hundred", new SoundResource(R.raw.hundred_robot_));
 81    sounds.put("[slnc]", new SoundResource(R.raw.slnc_snd));
 82    sounds.put("[red]", new SoundResource(R.raw.red_snd));
 83    sounds.put("[green]", new SoundResource(R.raw.green_snd));
 84    sounds.put("[yellow]", new SoundResource(R.raw.yellow_snd));
 85    sounds.put("[blue]", new SoundResource(R.raw.blue_snd));
 86  }
 87
 88
 89  public void play(String soundName, int queueMode) {
 90    if (!sounds.containsKey(soundName)) {
 91      if (soundName.length() > 1) {
 92        // Flush the queue first if needed
 93        if (queueMode == 0) {
 94          play("", 0);
 95        }
 96        // Decompose this into a number if possible.
 97        // Remove this once full-fledged TTS is available.
 98        if (spokenAsNumber(soundName)) {
 99          return;
100        }
101        for (int i = 0; i < soundName.length(); i++) {
102          String currentCharacter = soundName.substring(i, i + 1);
103          if (currentCharacter.length() == 1) {
104            play(currentCharacter, 1);
105          }
106        }
107      }
108      return;
109    }
110
111    if (isPlaying && (queueMode == 0)) {
112      stop();
113    }
114
115    soundQueue.add(soundName);
116
117    if (!isPlaying) {
118      processSoundQueue();
119    }
120  }
121
122
123  // Special algorithm to decompose numbers into speakable parts.
124  // This will handle positive numbers up to 999.
125  private boolean spokenAsNumber(String text) {
126    try {
127      int number = Integer.parseInt(text);
128      // Handle cases that are between 100 and 999, inclusive
129      if ((number > 99) && (number < 1000)) {
130        int remainder = number % 100;
131        number = number / 100;
132        play(Integer.toString(number), 1);
133        play("[slnc]", 1);
134        play("[slnc]", 1);
135        play("hundred", 1);
136        play("[slnc]", 1);
137        play("[slnc]", 1);
138        if (remainder > 0) {
139          play(Integer.toString(remainder), 1);
140        }
141        return true;
142      }
143
144      // Handle cases that are less than 100
145      int digit = 0;
146      if ((number > 20) && (number < 100)) {
147        if ((number > 20) && (number < 30)) {
148          play(Integer.toString(20), 1);
149          play("[slnc]", 1);
150          play("[slnc]", 1);
151          digit = number - 20;
152        } else if ((number > 30) && (number < 40)) {
153          play(Integer.toString(30), 1);
154          play("[slnc]", 1);
155          play("[slnc]", 1);
156          digit = number - 30;
157        } else if ((number > 40) && (number < 50)) {
158          play(Integer.toString(40), 1);
159          play("[slnc]", 1);
160          play("[slnc]", 1);
161          digit = number - 40;
162        } else if ((number > 50) && (number < 60)) {
163          play(Integer.toString(50), 1);
164          play("[slnc]", 1);
165          play("[slnc]", 1);
166          digit = number - 50;
167        } else if ((number > 60) && (number < 70)) {
168          play(Integer.toString(60), 1);
169          play("[slnc]", 1);
170          play("[slnc]", 1);
171          digit = number - 60;
172        } else if ((number > 70) && (number < 80)) {
173          play(Integer.toString(70), 1);
174          play("[slnc]", 1);
175          play("[slnc]", 1);
176          digit = number - 70;
177        } else if ((number > 80) && (number < 90)) {
178          play(Integer.toString(80), 1);
179          play("[slnc]", 1);
180          play("[slnc]", 1);
181          digit = number - 80;
182        } else if ((number > 90) && (number < 100)) {
183          play(Integer.toString(90), 1);
184          play("[slnc]", 1);
185          play("[slnc]", 1);
186          digit = number - 90;
187        }
188        if (digit > 0) {
189          play(Integer.toString(digit), 1);
190          return true;
191        }
192      }
193      // Any other cases are either too large to handle
194      // or have an utterance that is directly mapped.
195      return false;
196    } catch (NumberFormatException nfe) {
197      return false;
198    }
199  }
200
201  public void stop() {
202    soundQueue.clear();
203    isPlaying = false;
204    if (player != null) {
205      try {
206        player.stop();
207      } catch (IllegalStateException e) {
208        // Do nothing, the player is already stopped.
209      }
210    }
211  }
212
213  public void loadSoundFile(String soundName, String fileName) {
214    sounds.put(soundName, new SoundResource(fileName));
215  }
216
217  public void loadSoundResource(String soundName, int resId) {
218    sounds.put(soundName, new SoundResource(resId));
219  }
220
221  public void onCompletion(MediaPlayer arg0) {
222    if (soundQueue.size() > 0) {
223      processSoundQueue();
224    } else {
225      isPlaying = false;
226    }
227  }
228
229  private void processSoundQueue() {
230    boolean speechQueueAvailable = soundQueueLock.tryLock();
231    if (!speechQueueAvailable) {
232      return;
233    }
234    String soundName = soundQueue.get(0);
235    isPlaying = true;
236    if (sounds.containsKey(soundName)) {
237      SoundResource sr = sounds.get(soundName);
238      cleanUpPlayer();
239
240      if (sr.resId != -1) {
241        player = MediaPlayer.create(ctx, sr.resId);
242      } else {
243        player = MediaPlayer.create(ctx, Uri.parse(sr.filename));
244      }
245
246      // Check for if Media Server is dead;
247      // if it is, clear the queue and give
248      // up for now - hopefully, it will recover itself.
249      if (player == null) {
250        soundQueue.clear();
251        isPlaying = false;
252        soundQueueLock.unlock();
253        return;
254      }
255      player.setOnCompletionListener(this);
256      try {
257        player.start();
258      } catch (IllegalStateException e) {
259        soundQueue.clear();
260        isPlaying = false;
261        cleanUpPlayer();
262        soundQueueLock.unlock();
263        return;
264      }
265      isPlaying = true;
266    }
267
268    if (soundQueue.size() > 0) {
269      soundQueue.remove(0);
270    }
271    soundQueueLock.unlock();
272  }
273
274  private void cleanUpPlayer() {
275    if (player != null) {
276      player.release();
277      player = null;
278    }
279  }
280
281}