Advertisement
Guest User

Arduino audio Gaga

a guest
Oct 26th, 2016
292
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.12 KB | None | 0 0
  1. /*
  2.    speaker_pcm
  3.  
  4.    Plays 8-bit PCM audio on pin 11 using pulse-width modulation (PWM).
  5.    For Arduino with Atmega168 at 16 MHz.
  6.  
  7.    Uses two timers. The first changes the sample value 8000 times a second.
  8.    The second holds pin 11 high for 0-255 ticks out of a 256-tick cycle,
  9.    depending on sample value. The second timer repeats 62500 times per second
  10.    (16000000 / 256), much faster than the playback rate (8000 Hz), so
  11.    it almost sounds halfway decent, just really quiet on a PC speaker.
  12.  
  13.    Takes over Timer 1 (16-bit) for the 8000 Hz timer. This breaks PWM
  14.    (analogWrite()) for Arduino pins 9 and 10. Takes Timer 2 (8-bit)
  15.    for the pulse width modulation, breaking PWM for pins 11 & 3.
  16.  
  17.    References:
  18.        http://www.uchobby.com/index.php/2007/11/11/arduino-sound-part-1/
  19.        http://www.atmel.com/dyn/resources/prod_documents/doc2542.pdf
  20.        http://www.evilmadscientist.com/article.php/avrdac
  21.        http://gonium.net/md/2006/12/27/i-will-think-before-i-code/
  22.        http://fly.cc.fer.hr/GDM/articles/sndmus/speaker2.html
  23.        http://www.gamedev.net/reference/articles/article442.asp
  24.  
  25.    Michael Smith <michael@hurts.ca>
  26. */
  27.  
  28.  
  29. #include <stdint.h>
  30. #include <avr/interrupt.h>
  31. #include <avr/io.h>
  32. #include <avr/pgmspace.h>
  33.  
  34. #define SAMPLE_RATE 8000
  35. #define SAMPLE_RATEF (float)SAMPLE_RATE
  36.  
  37. #define BUFLEN 450
  38.  
  39. /*
  40.    The audio data needs to be unsigned, 8-bit, 8000 Hz, and small enough
  41.    to fit in flash. 10000-13000 samples is about the limit.
  42.  
  43.    sounddata.h should look like this:
  44.        const int sounddata_length=10000;
  45.        const unsigned char sounddata_data[] PROGMEM = { ..... };
  46.  
  47.    You can use wav2c from GBA CSS:
  48.        http://thieumsweb.free.fr/english/gbacss.html
  49.    Then add "PROGMEM" in the right place. I hacked it up to dump the samples
  50.    as unsigned rather than signed, but it shouldn't matter.
  51.  
  52.    http://musicthing.blogspot.com/2005/05/tiny-music-makers-pt-4-mac-startup.html
  53.    mplayer -ao pcm macstartup.mp3
  54.    sox audiodump.wav -v 1.32 -c 1 -r 8000 -u -1 macstartup-8000.wav
  55.    sox macstartup-8000.wav macstartup-cut.wav trim 0 10000s
  56.    wav2c macstartup-cut.wav sounddata.h sounddata
  57.  
  58.    (starfox) nb. under sox 12.18 (distributed in CentOS 5), i needed to run
  59.    the following command to convert my wav file to the appropriate format:
  60.    sox audiodump.wav -c 1 -r 8000 -u -b macstartup-8000.wav
  61. */
  62.  
  63. int ledPin = 13;
  64. int speakerPin = 11;
  65.  
  66. byte sin_pc[BUFLEN];
  67. int scnt = 0, ncnt = 0;
  68. float osc_phase = 0;
  69. float phaselen = 1.0;
  70.  
  71. // gaga telephone intro
  72. byte notes[] = {
  73.   15, 8, 13, 8, 11, 8, 10, 11,
  74.   6, 11, 15, 17, 18, 15, 20, 18,
  75.   17, 8, 13, 5, 8, 1, 10, 8,
  76.   11, 8, 3, 11, 8, 3, 11, 8
  77. };
  78.  
  79. void stopPlayback()
  80. {
  81.   // Disable playback per-sample interrupt.
  82.   TIMSK1 &= ~_BV(OCIE1A);
  83.  
  84.   // Disable the per-sample timer completely.
  85.   TCCR1B &= ~_BV(CS10);
  86.  
  87.   // Disable the PWM timer.
  88.   TCCR2B &= ~_BV(CS10);
  89.  
  90.   digitalWrite(speakerPin, LOW);
  91. }
  92.  
  93. // This is called at every SAMPLE_RATE
  94. ISR(TIMER1_COMPA_vect) {
  95.   int tsnd;
  96.  
  97.   tsnd = sin_pc[(uint16_t)osc_phase];
  98.   tsnd -= 128;
  99.   //tsnd = tsnd * sin_pc[scnt/6]/256;
  100.   tsnd = tsnd * 32 / (scnt / 24 + 32);
  101.   tsnd += 128;
  102.   OCR2A = (byte)tsnd;
  103.  
  104.   osc_phase += phaselen;
  105.   if (osc_phase > BUFLEN - 1) {
  106.     while (osc_phase > BUFLEN - 1)
  107.       osc_phase -= BUFLEN;
  108.   }
  109.  
  110.   if (++scnt > 2000) {
  111.     phaselen = BUFLEN / 14.0 * pow(2, 1.0 + (float)notes[ncnt] / 12.0);
  112.     ncnt = (++ncnt) % 32;
  113.     scnt = 0;
  114.   }
  115. }
  116.  
  117. void calcTables() {
  118.   for (int i = 0; i < BUFLEN; i++) {
  119.     sin_pc[i] = (byte)(sin((float)i * 3.14159265359 * 2.0 / (float)BUFLEN) * 120 + 128);
  120.   }
  121. }
  122.  
  123. void startPlayback()
  124. {
  125.   pinMode(speakerPin, OUTPUT);
  126.  
  127.   // Set up Timer 2 to do pulse width modulation on the speaker pin.
  128.  
  129.   // Use internal clock (datasheet p.160)
  130.   ASSR &= ~(_BV(EXCLK) | _BV(AS2));
  131.  
  132.   // Set fast PWM mode  (p.157)
  133.   TCCR2A |= _BV(WGM21) | _BV(WGM20);
  134.   TCCR2B &= ~_BV(WGM22);
  135.  
  136.   if (speakerPin == 11) {
  137.     // Do non-inverting PWM on pin OC2A (p.155)
  138.     // On the Arduino this is pin 11.
  139.     TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
  140.     TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
  141.     // No prescaler (p.158)
  142.     TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
  143.  
  144.     // Set initial pulse width to the first sample.
  145.     //OCR2A = pgm_read_byte(&sounddata_data[0]);
  146.   }
  147.  
  148.   // Set up Timer 1 to send a sample every interrupt.
  149.  
  150.   cli();
  151.  
  152.   // Set CTC mode (Clear Timer on Compare Match) (p.133)
  153.   // Have to set OCR1A *after*, otherwise it gets reset to 0!
  154.   TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
  155.   TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
  156.  
  157.   // No prescaler (p.134)
  158.   TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
  159.  
  160.   // Set the compare register (OCR1A).
  161.   // OCR1A is a 16-bit register, so we have to do this with
  162.   // interrupts disabled to be safe.
  163.   OCR1A = F_CPU / SAMPLE_RATE;    // 16e6 / 8000 = 2000
  164.  
  165.   // Enable interrupt when TCNT1 == OCR1A (p.136)
  166.   TIMSK1 |= _BV(OCIE1A);
  167.  
  168.   sei();
  169. }
  170.  
  171.  
  172. void setup()
  173. {
  174.   calcTables();
  175.   pinMode(ledPin, OUTPUT);
  176.   digitalWrite(ledPin, HIGH);
  177.   startPlayback();
  178. }
  179.  
  180. void loop()
  181. {
  182.   delay(100);
  183. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement