PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

355 lines
11KB

  1. // Talkie library
  2. // Copyright 2011 Peter Knight
  3. // This code is released under GPLv2 license.
  4. #if (ARDUINO >= 100)
  5. #include "Arduino.h"
  6. #else
  7. #include <avr/io.h>
  8. #include "WProgram.h"
  9. #endif
  10. #include "Talkie.h"
  11. #define FS 8000 // Speech engine sample rate
  12. static void timerInterrupt();
  13. static uint8_t synthPeriod;
  14. static uint16_t synthEnergy;
  15. static int16_t synthK1,synthK2;
  16. static int8_t synthK3,synthK4,synthK5,synthK6,synthK7,synthK8,synthK9,synthK10;
  17. static void sayisr();
  18. static Talkie *isrTalkptr;
  19. static uint8_t nextData=0;
  20. const uint8_t spStopSay[] PROGMEM = { 0x0F}; // This is a special sound to cleanly: Silence the synthesiser
  21. //Setup config for teensy
  22. uint8_t _pwmPIN;
  23. bool _hasPShield = false;
  24. static const uint8_t tmsEnergy[0x10] = {0x00,0x02,0x03,0x04,0x05,0x07,0x0a,0x0f,0x14,0x20,0x29,0x39,0x51,0x72,0xa1,0xff};
  25. static const uint8_t tmsPeriod[0x40] = {0x00,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2D,0x2F,0x31,0x33,0x35,0x36,0x39,0x3B,0x3D,0x3F,0x42,0x45,0x47,0x49,0x4D,0x4F,0x51,0x55,0x57,0x5C,0x5F,0x63,0x66,0x6A,0x6E,0x73,0x77,0x7B,0x80,0x85,0x8A,0x8F,0x95,0x9A,0xA0};
  26. static const uint16_t tmsK1[0x20] = {0x82C0,0x8380,0x83C0,0x8440,0x84C0,0x8540,0x8600,0x8780,0x8880,0x8980,0x8AC0,0x8C00,0x8D40,0x8F00,0x90C0,0x92C0,0x9900,0xA140,0xAB80,0xB840,0xC740,0xD8C0,0xEBC0,0x0000,0x1440,0x2740,0x38C0,0x47C0,0x5480,0x5EC0,0x6700,0x6D40};
  27. static const uint16_t tmsK2[0x20] = {0xAE00,0xB480,0xBB80,0xC340,0xCB80,0xD440,0xDDC0,0xE780,0xF180,0xFBC0,0x0600,0x1040,0x1A40,0x2400,0x2D40,0x3600,0x3E40,0x45C0,0x4CC0,0x5300,0x5880,0x5DC0,0x6240,0x6640,0x69C0,0x6CC0,0x6F80,0x71C0,0x73C0,0x7580,0x7700,0x7E80};
  28. static const uint8_t tmsK3[0x10] = {0x92,0x9F,0xAD,0xBA,0xC8,0xD5,0xE3,0xF0,0xFE,0x0B,0x19,0x26,0x34,0x41,0x4F,0x5C};
  29. static const uint8_t tmsK4[0x10] = {0xAE,0xBC,0xCA,0xD8,0xE6,0xF4,0x01,0x0F,0x1D,0x2B,0x39,0x47,0x55,0x63,0x71,0x7E};
  30. static const uint8_t tmsK5[0x10] = {0xAE,0xBA,0xC5,0xD1,0xDD,0xE8,0xF4,0xFF,0x0B,0x17,0x22,0x2E,0x39,0x45,0x51,0x5C};
  31. static const uint8_t tmsK6[0x10] = {0xC0,0xCB,0xD6,0xE1,0xEC,0xF7,0x03,0x0E,0x19,0x24,0x2F,0x3A,0x45,0x50,0x5B,0x66};
  32. static const uint8_t tmsK7[0x10] = {0xB3,0xBF,0xCB,0xD7,0xE3,0xEF,0xFB,0x07,0x13,0x1F,0x2B,0x37,0x43,0x4F,0x5A,0x66};
  33. static const uint8_t tmsK8[0x08] = {0xC0,0xD8,0xF0,0x07,0x1F,0x37,0x4F,0x66};
  34. static const uint8_t tmsK9[0x08] = {0xC0,0xD4,0xE8,0xFC,0x10,0x25,0x39,0x4D};
  35. static const uint8_t tmsK10[0x08] = {0xCD,0xDF,0xF1,0x04,0x16,0x20,0x3B,0x4D};
  36. void Talkie::beginPWM(uint8_t pinPWM){
  37. _pwmPIN = pinPWM;
  38. _hasPShield = false;
  39. }
  40. void Talkie::beginPropShield(){
  41. _hasPShield = true;
  42. }
  43. bool Talkie::setPtr(const uint8_t * addr) {
  44. ptrAddr = addr;
  45. ptrBit = 0;
  46. if ( addr ) return(true);
  47. else return(false);
  48. }
  49. uint8_t Talkie::active() {
  50. yield();
  51. if ( 0 == ptrAddr ) return 0; // Nothing playing!
  52. else return( 1 + (SAY_BUFFER_SIZE - free) ); // 1 active plus X in queue
  53. } // active()
  54. // The ROMs used with the TI speech were serial, not byte wide.
  55. // Here's a handy routine to flip ROM data which is usually reversed.
  56. uint8_t Talkie::rev(uint8_t a) {
  57. // 76543210
  58. a = (a>>4) | (a<<4); // Swap in groups of 4
  59. // 32107654
  60. a = ((a & 0xcc)>>2) | ((a & 0x33)<<2); // Swap in groups of 2
  61. // 10325476
  62. a = ((a & 0xaa)>>1) | ((a & 0x55)<<1); // Swap bit pairs
  63. // 01234567
  64. return a;
  65. }
  66. uint8_t Talkie::getBits(uint8_t bits) {
  67. uint8_t value;
  68. uint16_t data;
  69. data = rev(pgm_read_byte(ptrAddr))<<8;
  70. if (ptrBit+bits > 8) {
  71. data |= rev(pgm_read_byte(ptrAddr+1));
  72. }
  73. data <<= ptrBit;
  74. value = data >> (16-bits);
  75. ptrBit += bits;
  76. if (ptrBit >= 8) {
  77. ptrBit -= 8;
  78. ptrAddr++;
  79. }
  80. return value;
  81. }
  82. void Talkie::say(const uint8_t * addr) {
  83. sayQ( addr );
  84. while ( active() );
  85. } // say()
  86. bool Talkie::say_add( const uint8_t *addr ) {
  87. if ( addr && free ) {
  88. free--;
  89. say_buffer[head] = addr;
  90. if (++head >= SAY_BUFFER_SIZE) head = 0;
  91. return true;
  92. }
  93. return false; // Do not add on ZERO addr or ZERO free queue
  94. } // say_add()
  95. const uint8_t * Talkie::say_remove() {
  96. const uint8_t *addr = 0; // Return 0 on empty
  97. if ( free < SAY_BUFFER_SIZE ) {
  98. free++;
  99. addr = say_buffer[tail];
  100. if (++tail >= SAY_BUFFER_SIZE) tail = 0;
  101. }
  102. else if ( ( ptrAddr ) && ( spStopSay != ptrAddr ) ) {
  103. addr = spStopSay;
  104. }
  105. return addr;
  106. } // say_remove()
  107. int8_t Talkie::sayQ(const uint8_t * addr) {
  108. if (!setup) {
  109. // Auto-setup.
  110. //
  111. // Enable the speech system whenever say() is called.
  112. #if defined(__AVR__)
  113. #if F_CPU != 16000000L
  114. #error "F_CPU must be 16 MHz"
  115. #endif
  116. pinMode(_pwmPIN,OUTPUT);
  117. // Timer 2 set up as a 62500Hz PWM.
  118. //
  119. // The PWM 'buzz' is well above human hearing range and is
  120. // very easy to filter out.
  121. //
  122. TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  123. TCCR2B = _BV(CS20);
  124. TIMSK2 = 0;
  125. // Unfortunately we can't calculate the next sample every PWM cycle
  126. // as the routine is too slow. So use Timer 1 to trigger that.
  127. // Timer 1 set up as a 8000Hz sample interrupt
  128. TCCR1A = 0;
  129. TCCR1B = _BV(WGM12) | _BV(CS10);
  130. TCNT1 = 0;
  131. OCR1A = F_CPU / FS;
  132. TIMSK1 = _BV(OCIE1A);
  133. #define ISR_RATIO (25000/ (F_CPU / FS) )
  134. #elif defined(__arm__) && defined(CORE_TEENSY)
  135. #define ISR(f) void f(void)
  136. IntervalTimer *t = new IntervalTimer();
  137. t->begin(timerInterrupt, 1000000.0f / (float)FS);
  138. if(!_hasPShield)
  139. analogWriteFrequency(_pwmPIN,62500);
  140. #define ISR_RATIO (25000/ (1000000.0f / (float)FS) )
  141. #endif
  142. isrTalkptr = this;
  143. head = 0;
  144. tail = 0;
  145. free = SAY_BUFFER_SIZE;
  146. setup = 1;
  147. }
  148. if ( 0 == addr ) { // Caller asked to have queue made empty and sound stopped
  149. head = 0;
  150. tail = 0;
  151. free = SAY_BUFFER_SIZE;
  152. setPtr(spStopSay); // Force this NOP sound to play to turn off the output on next timerinterrupt()
  153. nextData=ISR_RATIO;
  154. }
  155. else if ( !active() ) {
  156. if ( setPtr(addr) ) { // START the sound on this address : on zero addr just return free count
  157. nextData=0; // This tracks the timing of the call to sayisr()
  158. sayisr(); // Get first data now
  159. }
  160. }
  161. else { // Still active queue this addr when there is room
  162. while ( (0==free) && active() );
  163. say_add( addr );
  164. }
  165. return(free); // return free count after adding
  166. } // sayQ()
  167. #define CHIRP_SIZE 41
  168. static uint8_t chirp[CHIRP_SIZE] = {0x00,0x2a,0xd4,0x32,0xb2,0x12,0x25,0x14,0x02,0xe1,0xc5,0x02,0x5f,0x5a,0x05,0x0f,0x26,0xfc,0xa5,0xa5,0xd6,0xdd,0xdc,0xfc,0x25,0x2b,0x22,0x21,0x0f,0xff,0xf8,0xee,0xed,0xef,0xf7,0xf6,0xfa,0x00,0x03,0x02,0x01};
  169. ISR(TIMER1_COMPA_vect) {
  170. timerInterrupt();
  171. }
  172. static void timerInterrupt() {
  173. static uint8_t nextPwm;
  174. static uint8_t periodCounter;
  175. static int16_t x0,x1,x2,x3,x4,x5,x6,x7,x8,x9;
  176. Talkie *o = isrTalkptr;
  177. int16_t u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10;
  178. #if defined(__AVR__)
  179. OCR2B = nextPwm;
  180. sei();
  181. #elif defined(__arm__) && defined(CORE_TEENSY)
  182. if(_hasPShield) {
  183. #if defined(__MKL26Z64__)
  184. analogWrite(A12, nextPwm);
  185. #elif defined(__MK20DX128__) || defined(__MK20DX256__)
  186. analogWrite(A14, nextPwm);
  187. #elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
  188. analogWrite(A21, nextPwm);
  189. #elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
  190. Serial.println("Board does not support Propshield");
  191. exit(0);
  192. #else
  193. #error "Unknown Teensy" // dont like this line
  194. #endif
  195. pinMode(5, OUTPUT);
  196. digitalWrite(5, HIGH);//Enable Amplified PROP shield
  197. } else {
  198. #if defined(__IMXRT1052__) || defined(__IMXRT1062__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) \
  199. || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
  200. analogWrite(_pwmPIN, nextPwm);
  201. #else
  202. #error "Unknown Teensy"
  203. #endif
  204. }
  205. #endif
  206. if (synthPeriod) {
  207. // Voiced source
  208. if (periodCounter < synthPeriod) {
  209. periodCounter++;
  210. } else {
  211. periodCounter = 0;
  212. }
  213. if (periodCounter < CHIRP_SIZE) {
  214. u10 = ((chirp[periodCounter]) * (uint32_t) synthEnergy) >> 8;
  215. } else {
  216. u10 = 0;
  217. }
  218. } else {
  219. // Unvoiced source
  220. static uint16_t synthRand = 1;
  221. synthRand = (synthRand >> 1) ^ ((synthRand & 1) ? 0xB800 : 0);
  222. u10 = (synthRand & 1) ? synthEnergy : -synthEnergy;
  223. }
  224. // Lattice filter forward path
  225. u9 = u10 - (((int16_t)synthK10*x9) >> 7);
  226. u8 = u9 - (((int16_t)synthK9*x8) >> 7);
  227. u7 = u8 - (((int16_t)synthK8*x7) >> 7);
  228. u6 = u7 - (((int16_t)synthK7*x6) >> 7);
  229. u5 = u6 - (((int16_t)synthK6*x5) >> 7);
  230. u4 = u5 - (((int16_t)synthK5*x4) >> 7);
  231. u3 = u4 - (((int16_t)synthK4*x3) >> 7);
  232. u2 = u3 - (((int16_t)synthK3*x2) >> 7);
  233. u1 = u2 - (((int32_t)synthK2*x1) >> 15);
  234. u0 = u1 - (((int32_t)synthK1*x0) >> 15);
  235. // Output clamp
  236. if (u0 > 511) u0 = 511;
  237. if (u0 < -512) u0 = -512;
  238. // Lattice filter reverse path
  239. x9 = x8 + (((int16_t)synthK9*u8) >> 7);
  240. x8 = x7 + (((int16_t)synthK8*u7) >> 7);
  241. x7 = x6 + (((int16_t)synthK7*u6) >> 7);
  242. x6 = x5 + (((int16_t)synthK6*u5) >> 7);
  243. x5 = x4 + (((int16_t)synthK5*u4) >> 7);
  244. x4 = x3 + (((int16_t)synthK4*u3) >> 7);
  245. x3 = x2 + (((int16_t)synthK3*u2) >> 7);
  246. x2 = x1 + (((int32_t)synthK2*u1) >> 15);
  247. x1 = x0 + (((int32_t)synthK1*u0) >> 15);
  248. x0 = u0;
  249. nextPwm = (u0>>2)+0x80;
  250. if ( o->ptrAddr ) nextData++; // if no sound don't run toward calling sayisr()
  251. if (ISR_RATIO <= nextData) { nextData=0; sayisr(); }
  252. }
  253. static void sayisr() {
  254. uint8_t energy;
  255. Talkie *o = isrTalkptr;
  256. if ( !(o->ptrAddr) ) {
  257. // Non Active :: try START the sound on say_remove() address
  258. if ( o->setPtr(o->say_remove()) ) nextData=ISR_RATIO; // This tracks the timing of the call to sayisr() :: Force nextData next timerInterrupt()
  259. return;
  260. }
  261. energy = o->getBits(4);
  262. uint8_t repeat;
  263. // Read speech data, processing the variable size frames.
  264. if (energy == 0) {
  265. // Energy = 0: rest frame
  266. synthEnergy = 0;
  267. } else if (energy == 0xf) { // Energy = 15: stop frame. Silence the synthesiser.
  268. synthEnergy = 0;
  269. synthK1 = 0;
  270. synthK2 = 0;
  271. synthK3 = 0;
  272. synthK4 = 0;
  273. synthK5 = 0;
  274. synthK6 = 0;
  275. synthK7 = 0;
  276. synthK8 = 0;
  277. synthK9 = 0;
  278. synthK10 = 0;
  279. // Going Non Active :: START the sound on say_remove() address
  280. if ( o->setPtr(o->say_remove()) ) nextData=ISR_RATIO; // This tracks the timing of the call to sayisr() :: Force nextData next timerInterrupt()
  281. else nextData=0;
  282. } else {
  283. synthEnergy = tmsEnergy[energy];
  284. repeat = o->getBits(1);
  285. synthPeriod = tmsPeriod[o->getBits(6)];
  286. // A repeat frame uses the last coefficients
  287. if (!repeat) {
  288. // All frames use the first 4 coefficients
  289. synthK1 = tmsK1[o->getBits(5)];
  290. synthK2 = tmsK2[o->getBits(5)];
  291. synthK3 = tmsK3[o->getBits(4)];
  292. synthK4 = tmsK4[o->getBits(4)];
  293. if (synthPeriod) {
  294. // Voiced frames use 6 extra coefficients.
  295. synthK5 = tmsK5[o->getBits(4)];
  296. synthK6 = tmsK6[o->getBits(4)];
  297. synthK7 = tmsK7[o->getBits(4)];
  298. synthK8 = tmsK8[o->getBits(3)];
  299. synthK9 = tmsK9[o->getBits(3)];
  300. synthK10 = tmsK10[o->getBits(3)];
  301. }
  302. }
  303. }
  304. } // sayisr()
  305. /*
  306. >> When sayQ brings new addr - if not .active() then start it { 'current code' } return (free);
  307. if ( active() && free ) :: then ADD it :: return (free);
  308. else do a say() type while block until it can be added, then return
  309. >> when timerInterrupt() completes :: if say_buffer_queued then start REMOVE
  310. setPtr( say_remove );
  311. // RACE CONDITION :: sayQ : During Add - one active - none queued - on timerInterrupt() it completes before item queued it won;t start next
  312. >> solution when sayisr() is entered if ptrAddris zero do a check for set_remove() in case one comes in un announced
  313. // Calling sayQ() will play or buffer and return free and if !free it will block like say() until room
  314. // Calling say() with queued sayQ() items will block until queued and the queue is empty
  315. */