wavface.pde 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. // 'wavface' example sketch for Adafruit I2C 8x8 LED backpacks
  2. // and Wave Shield:
  3. //
  4. // www.adafruit.com/products/870 www.adafruit.com/products/1049
  5. // www.adafruit.com/products/871 www.adafruit.com/products/1050
  6. // www.adafruit.com/products/872 www.adafruit.com/products/1051
  7. // www.adafruit.com/products/959 www.adafruit.com/products/1052
  8. // www.adafruit.com/products/94
  9. //
  10. // Requires Adafruit_LEDBackpack, Adafruit_GFX libraries and WaveHC
  11. // libraries.
  12. //
  13. // This sketch shows animation roughly synchronized to prerecorded
  14. // speech. It's fairly complex and may be overwhelming to novice
  15. // programmers, who may want to start with the 'matrix8x8' example
  16. // and then 'roboface' before working through this code. Also, much
  17. // of the comments relating to the face animation have been stripped
  18. // here for brevity...refer to the 'roboface' sketch if you have any
  19. // questions how that part works.
  20. //
  21. // Additional hardware required: sounds are triggered using three
  22. // normally-open momentary buttons connected to Digital pins 6, 7, 8
  23. // and GND. (e.g. www.adafruit.com/products/1009 )
  24. //
  25. // Adafruit invests time and resources providing this open source code,
  26. // please support Adafruit and open-source hardware by purchasing
  27. // products from Adafruit!
  28. //
  29. // Written by P. Burgess for Adafruit Industries, parts adapted from
  30. // 'PiSpeakHC' sketch included with WaveHC library.
  31. // BSD license, all text above must be included in any redistribution.
  32. #include <Arduino.h>
  33. #include <Wire.h>
  34. #include <Adafruit_GFX.h>
  35. #include <WaveHC.h>
  36. #include <WaveUtil.h>
  37. #include "Adafruit_LEDBackpack.h"
  38. // These WAV files should be in the root level of the SD card:
  39. static const char PROGMEM
  40. wav0[] = "beware_i.wav",
  41. wav1[] = "ihunger.wav",
  42. wav2[] = "run_cowd.wav";
  43. static const char * const wavname[] PROGMEM = { wav0, wav1, wav2 };
  44. // PROGMEM makes frequent appearances throughout this code, reason being that
  45. // the SD card library requires gobs of precious RAM (leaving very little to
  46. // our own sketch). PROGMEM lets us put fixed data into program flash memory,
  47. // which is considerably more spacious. String tables are paritcularly nasty.
  48. // See www.arduino.cc/en/Reference/PROGMEM for more info.
  49. SdReader card; // This object holds the information for the card
  50. FatVolume vol; // This holds the information for the partition on the card
  51. FatReader root; // This holds the information for the volumes root directory
  52. FatReader file; // This object represent the WAV file for a phrase
  53. WaveHC wave; // A single wave object -- only one sound is played at a time
  54. // Because the two eye matrices share the same address, only four
  55. // matrix objects are needed for the five displays:
  56. #define MATRIX_EYES 0
  57. #define MATRIX_MOUTH_LEFT 1
  58. #define MATRIX_MOUTH_MIDDLE 2
  59. #define MATRIX_MOUTH_RIGHT 3
  60. Adafruit_8x8matrix matrix[4] = { // Array of Adafruit_8x8matrix objects
  61. Adafruit_8x8matrix(), Adafruit_8x8matrix(),
  62. Adafruit_8x8matrix(), Adafruit_8x8matrix() };
  63. // Rather than assigning matrix addresses sequentially in a loop, each
  64. // has a spot in this array. This makes it easier if you inadvertently
  65. // install one or more matrices in the wrong physical position --
  66. // re-order the addresses in this table and you can still refer to
  67. // matrices by index above, no other code or wiring needs to change.
  68. static const uint8_t PROGMEM matrixAddr[] = { 0x70, 0x71, 0x72, 0x73 };
  69. static const uint8_t PROGMEM // Bitmaps are stored in program memory
  70. blinkImg[][8] = { // Eye animation frames
  71. { B00111100, // Fully open eye
  72. B01111110,
  73. B11111111,
  74. B11111111,
  75. B11111111,
  76. B11111111,
  77. B01111110,
  78. B00111100 },
  79. { B00000000,
  80. B01111110,
  81. B11111111,
  82. B11111111,
  83. B11111111,
  84. B11111111,
  85. B01111110,
  86. B00111100 },
  87. { B00000000,
  88. B00000000,
  89. B00111100,
  90. B11111111,
  91. B11111111,
  92. B11111111,
  93. B00111100,
  94. B00000000 },
  95. { B00000000,
  96. B00000000,
  97. B00000000,
  98. B00111100,
  99. B11111111,
  100. B01111110,
  101. B00011000,
  102. B00000000 },
  103. { B00000000, // Fully closed eye
  104. B00000000,
  105. B00000000,
  106. B00000000,
  107. B10000001,
  108. B01111110,
  109. B00000000,
  110. B00000000 } },
  111. mouthImg[][24] = { // Mouth animation frames
  112. { B00000000, B00000000, B00000000, // Mouth position A
  113. B00000000, B00000000, B00000000,
  114. B01111111, B11111111, B11111110,
  115. B00000000, B00000000, B00000000,
  116. B00000000, B00000000, B00000000,
  117. B00000000, B00000000, B00000000,
  118. B00000000, B00000000, B00000000,
  119. B00000000, B00000000, B00000000 },
  120. { B00000000, B00000000, B00000000, // Mouth position B
  121. B00000000, B00000000, B00000000,
  122. B00111111, B11111111, B11111100,
  123. B00000111, B00000000, B11100000,
  124. B00000000, B11111111, B00000000,
  125. B00000000, B00000000, B00000000,
  126. B00000000, B00000000, B00000000,
  127. B00000000, B00000000, B00000000 },
  128. { B00000000, B00000000, B00000000, // Mouth position C
  129. B00000000, B00000000, B00000000,
  130. B00111111, B11111111, B11111100,
  131. B00001000, B00000000, B00010000,
  132. B00000110, B00000000, B01100000,
  133. B00000001, B11000011, B10000000,
  134. B00000000, B00111100, B00000000,
  135. B00000000, B00000000, B00000000 },
  136. { B00000000, B00000000, B00000000, // Mouth position D
  137. B00000000, B00000000, B00000000,
  138. B00111111, B11111111, B11111100,
  139. B00100000, B00000000, B00000100,
  140. B00010000, B00000000, B00001000,
  141. B00001100, B00000000, B00110000,
  142. B00000011, B10000001, B11000000,
  143. B00000000, B01111110, B00000000 },
  144. { B00000000, B00000000, B00000000, // Mouth position E
  145. B00000000, B00111100, B00000000,
  146. B00011111, B11000011, B11111000,
  147. B00000011, B10000001, B11000000,
  148. B00000000, B01111110, B00000000,
  149. B00000000, B00000000, B00000000,
  150. B00000000, B00000000, B00000000,
  151. B00000000, B00000000, B00000000 },
  152. { B00000000, B00111100, B00000000, // Mouth position F
  153. B00000000, B11000011, B00000000,
  154. B00001111, B00000000, B11110000,
  155. B00000001, B00000000, B10000000,
  156. B00000000, B11000011, B00000000,
  157. B00000000, B00111100, B00000000,
  158. B00000000, B00000000, B00000000,
  159. B00000000, B00000000, B00000000 } };
  160. // Animation sequences corresponding to each WAV. First number in
  161. // each pair is a mouth bitmap index. Second number is the hold
  162. // time (in frames). 255 marks end of list.
  163. // There is no 'magic' here, the software is NOT deriving mouth
  164. // position from the sound...the tables were determined by hand,
  165. // just as animators do it. Further explanation here:
  166. // http://www.idleworm.com/how/anm/03t/talk1.shtml
  167. static const uint8_t PROGMEM
  168. seq1[] = { 0, 2, 2, 5, 5, 3, 3, 7, // "Beware, I live!"
  169. 4, 5, 3, 4, 2, 5, 4, 3,
  170. 3, 4, 1, 5, 3, 5, 255 },
  171. seq2[] = { 0, 1, 3, 5, 1, 5, 4, 2, // "I hunger!"
  172. 3, 2, 1, 2, 4, 4, 1, 3,
  173. 4, 2, 255 },
  174. seq3[] = { 0, 1, 1, 2, 3, 6, 2, 5, // "Run, coward!"
  175. 0, 1, 4, 4, 5, 2, 1, 5,
  176. 3, 6, 1, 4, 255 };
  177. static const uint8_t * const anim[] = { seq1, seq2, seq3 };
  178. const uint8_t
  179. blinkIndex[] PROGMEM = { 1, 2, 3, 4, 3, 2, 1 }; // Blink bitmap sequence
  180. uint8_t
  181. blinkCountdown = 100, // Countdown to next blink (in frames)
  182. gazeCountdown = 75, // Countdown to next eye movement
  183. gazeFrames = 50, // Duration of eye movement (smaller = faster)
  184. mouthPos = 0, // Current image number for mouth
  185. mouthCountdown = 10, // Countdown to next mouth change
  186. newPos = 255, // New mouth position for current frame
  187. *seq, // Animation sequence currently being played back
  188. idx, // Current array index within animation sequence
  189. prevBtn = 99, // Button # pressed on last loop() iteration
  190. btnCount = 0; // Number of iterations same button has been held
  191. int8_t
  192. eyeX = 3, eyeY = 3, // Current eye position
  193. newX = 3, newY = 3, // Next eye position
  194. dX = 0, dY = 0; // Distance from prior to new position
  195. void setup() {
  196. Serial.begin(9600);
  197. Serial.println(F("WAV face"));
  198. if(!card.init()) Serial.println(F("Card init. failed!"));
  199. if(!vol.init(card)) Serial.println(F("No partition!"));
  200. if(!root.openRoot(vol)) Serial.println(F("Couldn't open dir"));
  201. Serial.println(F("Files found:"));
  202. root.ls();
  203. // Seed random number generator from an unused analog input:
  204. randomSeed(analogRead(A0));
  205. // Initialize each matrix object:
  206. for(uint8_t i=0; i<4; i++) {
  207. matrix[i].begin(pgm_read_byte(&matrixAddr[i]));
  208. // If using 'small' (1.2") displays vs. 'mini' (0.8"), enable this:
  209. // matrix[i].setRotation(3);
  210. }
  211. // Enable pull-up resistors on three button inputs.
  212. // Other end of each button then connects to GND.
  213. for(uint8_t i=6; i<=8; i++) {
  214. pinMode(i, INPUT);
  215. digitalWrite(i, HIGH); // Enable pullup
  216. }
  217. }
  218. void loop() {
  219. uint8_t i;
  220. // Draw eyeball in current state of blinkyness (no pupil).
  221. matrix[MATRIX_EYES].clear();
  222. matrix[MATRIX_EYES].drawBitmap(0, 0,
  223. blinkImg[
  224. (blinkCountdown < sizeof(blinkIndex)) ? // Currently blinking?
  225. pgm_read_byte(&blinkIndex[blinkCountdown]) : // Yes, look up bitmap #
  226. 0 // No, show bitmap 0
  227. ], 8, 8, LED_ON);
  228. // Decrement blink counter. At end, set random time for next blink.
  229. if(--blinkCountdown == 0) blinkCountdown = random(5, 180);
  230. if(--gazeCountdown <= gazeFrames) {
  231. // Eyes are in motion - draw pupil at interim position
  232. matrix[MATRIX_EYES].fillRect(
  233. newX - (dX * gazeCountdown / gazeFrames),
  234. newY - (dY * gazeCountdown / gazeFrames),
  235. 2, 2, LED_OFF);
  236. if(gazeCountdown == 0) { // Last frame?
  237. eyeX = newX; eyeY = newY; // Yes. What's new is old, then...
  238. do { // Pick random positions until one is within the eye circle
  239. newX = random(7); newY = random(7);
  240. dX = newX - 3; dY = newY - 3;
  241. } while((dX * dX + dY * dY) >= 10); // Thank you Pythagoras
  242. dX = newX - eyeX; // Horizontal distance to move
  243. dY = newY - eyeY; // Vertical distance to move
  244. gazeFrames = random(3, 15); // Duration of eye movement
  245. gazeCountdown = random(gazeFrames, 120); // Count to end of next movement
  246. }
  247. } else {
  248. // Not in motion yet -- draw pupil at current static position
  249. matrix[MATRIX_EYES].fillRect(eyeX, eyeY, 2, 2, LED_OFF);
  250. }
  251. // Scan buttons 6, 7, 8 looking for first button pressed...
  252. for(i=0; (i<3) && (digitalRead(i+6) == HIGH); i++);
  253. if(i < 3) { // Anything pressed? Yes!
  254. if(i == prevBtn) { // Same as last time we checked? Good!
  255. if(++btnCount == 3) { // 3 passes to 'debounce' button input
  256. playfile((char *)pgm_read_word(&wavname[i])); // Start WAV
  257. // Look up animation sequence # corresponding to this WAV...
  258. seq = (uint8_t *)pgm_read_word(&anim[i]);
  259. idx = 0; // Begin at first byte of data
  260. newPos = pgm_read_byte(&seq[idx++]); // Initial mouth pos
  261. mouthCountdown = pgm_read_byte(&seq[idx++]); // Hold time for pos
  262. }
  263. } else btnCount = 0; // Different button than before - start count over
  264. prevBtn = i;
  265. } else prevBtn = 99; // No buttons pressed
  266. if(newPos != 255) { // Is the mouth in motion?
  267. if(--mouthCountdown == 0) { // Count down frames to next position
  268. newPos = pgm_read_byte(&seq[idx++]); // New mouth position
  269. if(newPos == 255) { // End of list?
  270. mouthPos = 0; // Yes, set mouth to neutral position
  271. } else {
  272. mouthPos = newPos; // Set mouth to new position
  273. mouthCountdown = pgm_read_byte(&seq[idx++]); // Read hold time
  274. }
  275. }
  276. } else mouthPos = 0; // Mouth not in motion -- set to neutral position
  277. drawMouth(mouthImg[mouthPos]);
  278. // Refresh all matrices in one quick pass
  279. for(uint8_t i=0; i<4; i++) matrix[i].writeDisplay();
  280. delay(20);
  281. }
  282. // Draw mouth image across three adjacent displays
  283. void drawMouth(const uint8_t *img) {
  284. for(uint8_t i=0; i<3; i++) {
  285. matrix[MATRIX_MOUTH_LEFT + i].clear();
  286. matrix[MATRIX_MOUTH_LEFT + i].drawBitmap(i * -8, 0, img, 24, 8, LED_ON);
  287. }
  288. }
  289. // Open and start playing a WAV file
  290. void playfile(const char *name) {
  291. char filename[13]; // 8.3+NUL
  292. if(wave.isplaying) wave.stop(); // Stop any currently-playing WAV
  293. strcpy_P(filename, name); // Copy name out of PROGMEM into RAM
  294. if(!file.open(root, filename)) {
  295. Serial.print(F("Couldn't open file "));
  296. Serial.println(filename);
  297. return;
  298. }
  299. if(!wave.create(file)) {
  300. Serial.println(F("Not a valid WAV"));
  301. return;
  302. }
  303. wave.play();
  304. }