SSブログ

202duino w/ ATtiny412 で 指定波形で音楽再生<DAC版> [Arduino]

波形を指定および、DACで出力をしてみました。
ATtiny412使用です。
ダイレクトにスピーカにつなぐと音が割れました。
可変抵抗で割れないところに調整。
録音にはセラミックコンデンサーを挟んでみました。いいのか悪いのかは不明。

202sqsaw.jpg




// megaTinyCore ATtiny212/412 Score Replay Sketch (waveform, DAC)
#include "notes2.h"                     // Definition data of notes ( pitch (scale & octave), and note value (length))
#define MAX_TRACK   (4)                 // Maximum number of tracks
// 256 times the Wave Form subscript to advance in one cycle @ basic 12-note scale (from C9 to B9) (@20MHz, with an interrupt every 256clocks)
static const uint16_t OCTAVE9[] = { 7023, 7441, 7883, 8352, 8848, 9375, 9932, 10523,11148,11811,12513,13258 };
// waveform data
static const uint8_t  SQUARE256[] = {
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 };
static const uint8_t  SAWTOOTH256[] = {
    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
   64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,  80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
   96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
  160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
  192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
  224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 };
static const uint8_t  SINE256[] = {
    0,  0,  0,  0,  1,  1,  1,  2,  2,  3,  4,  5,  5,  6,  7,  9,  10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35,
   37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76,  79, 82, 85, 88, 90, 93, 97,100,103,106,109,112,115,118,121,124,
  128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173, 176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215,
  218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244, 245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,
  255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246, 245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220,
  218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179, 176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131,
  128,124,121,118,115,112,109,106,103,100, 97, 93, 90, 88, 85, 82,  79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, 44, 42, 40,
   37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11,  10,  9,  7,  6,  5,  5,  4,  3,  2,  2,  1,  1,  1,  0,  0,  0 };
static const uint8_t PIANO256[] = {
    0,  0,  0,  1,  2,  2,  3,  4,  5,  5,  6,  7,  8,  9,  9, 10,  11, 11, 12, 13, 13, 14, 15, 17, 18, 20, 22, 25, 28, 32, 36, 40,
   45, 51, 57, 63, 70, 77, 85, 93,101,110,119,128,136,145,154,162, 170,178,185,192,198,204,210,215,219,223,227,230,233,235,237,238,
  240,241,242,242,243,244,244,245,246,246,247,248,249,250,250,251, 252,253,253,254,255,255,255,255,255,254,254,253,252,251,249,248,
  246,244,243,241,239,237,236,234,233,231,230,229,228,227,226,226, 225,225,224,224,224,223,223,222,221,221,220,218,217,215,214,212,
  209,207,205,202,200,197,194,192,189,187,185,183,181,179,178,177, 176,175,175,174,174,174,174,174,173,173,173,173,172,171,170,168,
  166,164,162,159,156,152,149,145,141,136,132,128,123,119,114,110, 106,103, 99, 96, 93, 91, 89, 87, 85, 84, 83, 82, 82, 82, 82, 81,
   81, 81, 81, 81, 80, 80, 79, 78, 77, 76, 74, 72, 70, 68, 66, 63,  61, 58, 55, 53, 50, 48, 46, 43, 41, 40, 38, 37, 35, 34, 34, 33,
   32, 32, 31, 31, 31, 30, 30, 29, 29, 28, 27, 26, 25, 24, 22, 21,  19, 18, 16, 14, 12, 11,  9,  7,  6,  4,  3,  2,  1,  1,  0,  0 };
// music data
static const uint16_t Jesus[] = {       // J.S.Bach "Jesu, Joy of Man's Desiring"
  125 , 0 ,
  b4e , g4e , a4e , b4e , d5e , c5e , c5e , e5e , d5e , d5e , g5e , F5e , g5e , d5e , b4e , g4e , a4e , b4e ,
  e4e , d5e , c5e , b4e , a4e , g4e , d4e , g4e , F4e , g4e , b4e , d5e , g5hd,                           0 ,
  d4q       , F4e , g4q       , F4e , g4q       , a4e , b4q       , a4e , b4q       , g4e , e4q       , g4e ,       
  a4q       , F4e , g4q       , e4e , a3q       , c4e , b3w ,                                             0 ,
  g3qd            , e3qd            , c3qd            , b2qd            , e3qd            , d3qd            ,
  c3qd            , C3qd            , d3qd            , g2w ,                                             0 , 0 };

void setup(){                           // Register Settings
  TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | TCB_ENABLE_bm;   // 20MHz / 1 / 256 -> 78,125Hz
  TCB0.CTRLB = TCB_CNTMODE_PWM8_gc   | TCB_CCMPEN_bm;   // 8-Bit PWM mode, Output Enable (WO,PA6,megaTinyCore:P0)
  TCB0.CCMPL = 0xff;                                    // top value = 255
  TCB0.CCMPH = 0;                                       // output value
  VREF.CTRLA |= VREF_DAC0REFSEL_4V34_gc;                // Voltage reference at 4.34V
  VREF.CTRLB |= VREF_DAC0REFEN_bm;                      // DAC0/AC0 reference enable: enabled
  delayMicroseconds(25);                                // Wait VREF start-up time
  PORTA.PIN6CTRL &= ~PORT_ISC_gm;                       // Disable digital input buffer
  PORTA.PIN6CTRL |=  PORT_ISC_INPUT_DISABLE_gc;          
  PORTA.PIN6CTRL &= ~PORT_PULLUPEN_bm;                  // Disable pull-up resistor
  DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm;            // Enable DAC, Output Buffer
}

void loop(){
  play212wf( Jesus , SQUARE256   );     // Playback
  play212wf( Jesus , SAWTOOTH256 );     // Playback
  play212wf( Jesus , SINE256     );     // Playback
  play212wf( Jesus , PIANO256    );     // Playback
}

void play212wf( const uint16_t *d, const uint8_t *wf ){     // ATtiny212(20MHz) waveform version 
  uint8_t  Tracks;                      // Number of tracks
  const uint16_t *NoteP[MAX_TRACK];     // Pointer for each track of the score
  uint16_t NoteCycle, n;                // Number of interrupt cycles required for the length of the reference note (96th note) and its counter (n)
  uint16_t note;                        // Note (pitch + note value) information read from PROGMEM
  uint8_t  len[MAX_TRACK];              // Length of note (how many 96th notes) (subtraction counter)
  uint16_t cyc[MAX_TRACK], c[MAX_TRACK];// 256 times the Wave Table subscript to advance in one cycle (cyc) and its counter (c)
  uint16_t env[MAX_TRACK];              // Sound amplitude (envelope)
  uint8_t  lap = 30;                    // Sound transitional cycles(laptime) (for Attenuation calculator)  

  // *** Preparing Scores ***
  NoteCycle = F_CPU / 256 *4*60 / *d++ / MIN_NOTE;      // Number of cycles required for reference note
  for( Tracks = 0; Tracks < MAX_TRACK; ) {              // Get the number of tracks and the start position of each track from the song data
    if( *d++ != 0 ) continue;           // Skip until the break comes
    if( *d   == 0 ) break;              // If two zeros follow, end of data
    len[ Tracks ] = 1;                  // Initialize the note length subtraction counter to the remaining 1
    NoteP[ Tracks++ ] = d;              // Get location in memory, Count up the number of tracks
  }
  n = Tracks;                           // Initialize the score processing so that it can be performed immediately after the start of the do loop

  // *** Playback ***
  do {
    // * Processing Scores *
    if( --n < Tracks ) {                // Processing of score for each reference note length
      if( !--len[n] ) {
        note   = *NoteP[n]++;
        len[n] = (uint8_t) note;        // The lower 8 bits are the length of the note (how many times the length of a 96th note)
        if( note & 0xff00 ) {           // If not a rest... (Leave a lingering sound even with rests)
          cyc[n] = OCTAVE9[ (note>>8) & 0x0f ] >> (9 - (note>>12));   // 256 times the Wave Tabele subscript to advance in one cycle
            c[n] = 0;                   // Initializes a counter for the number of cycles to create one waveform cycle
          env[n] = 0xffff;              // Initially, the maximum amplitude
        }
      }
      if( !n ) n = NoteCycle;
    }
    // * Waveform Processing / Output *
    switch( Tracks ) {                  // Change output by number of tracks
      case 1:   DAC0.DATA =   wf[ (c[0]+=cyc[0])>>8 ] * (env[0]>> 8)  >>8;  // 8x8=16bit -> 8bit
                break;
      case 2:   DAC0.DATA = ( wf[ (c[0]+=cyc[0])>>8 ] * (env[0]>> 9)        // 8x7=15bit
                            + wf[ (c[1]+=cyc[1])>>8 ] * (env[1]>> 9) )>>8;  // 8x7=15bit 15/15(16bit)-> 8bit
                break;
      case 3:   DAC0.DATA = ( wf[ (c[0]+=cyc[0])>>8 ] * (env[0]>> 9)        // 8x7=15bit
                            + wf[ (c[1]+=cyc[1])>>8 ] * (env[1]>>10)        // 8x6=14bit
                            + wf[ (c[2]+=cyc[2])>>8 ] * (env[2]>>10) )>>8;  // 8x6=14bit 15/14/14(16bit)-> 8bit
                break;
      case 4:   DAC0.DATA = ( wf[ (c[0]+=cyc[0])>>8 ] * (env[0]>>10)        // 8x6=14bit
                            + wf[ (c[1]+=cyc[1])>>8 ] * (env[1]>>10)        // 8x6=14bit
                            + wf[ (c[2]+=cyc[2])>>8 ] * (env[2]>>10)        // 8x6=14bit
                            + wf[ (c[3]+=cyc[3])>>8 ] * (env[3]>>10) )>>8;  // 8x6=14bit 14/14/14/14(16bit)-> 8bit
    }
    switch( --lap ) {                   // Amplitude attenuation (Distribute processing per loop)
      case 4:   env[3] -= (env[3]>>9);    break;
      case 3:   env[2] -= (env[2]>>9);    break;
      case 2:   env[1] -= (env[1]>>9);    break;
      case 1:   env[0] -= (env[0]>>9);    break;
      case 0:   lap = 30;               // every 384usec(12.8usec*30) @20MHz (Adjustable)
    }
    while( !TCB0.INTFLAGS );            // Waiting for TCB0 overflow (every 12,8usec(78,125Hz))
    TCB0.INTFLAGS = TCB_CAPT_bm;        // cleared by writing a '1'
  } while( note );                      // Exit if note data is 0
  DAC0.DATA = 0;                        // Set output to 0
}

nice!(0)  コメント(0) 

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。