SSブログ

202duino で 減衰鋸歯状波の音楽再生 [Arduino]

実は、波形をつくって再生するスケッチを作ってみたものの、波形によってノイズが多く、ATtiny212/412のDAC使用だと目立たなくなりました。
でも、とりあえずATtiny202での再生が第一。
ノイズが目立たないのは、矩形波(作成済)と鋸歯状波形だったので、鋸歯状波形専用のスケッチをつくりました。
なんとなく8ビットゲーム音楽っぽい仕上がりです。

202sqsaw.jpg



// megaTinyCore ATtiny202/212/402/412 Score Replay Sketch (positive ramp sawtooth)
#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 virtual 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 };
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
}

void loop(){
  play202saw( Jesus );                  // Playback
}

void play202saw( const uint16_t *d ){   // ATtiny202(20MHz) sawtooth(positive ramp) 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 virtual 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 Table 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:   TCB0.CCMPH =   ((c[0]+=cyc[0])>>8) * (env[0]>> 8)  >>8; // 8x8=16bit -> 8bit
                break;
      case 2:   TCB0.CCMPH = ( ((c[0]+=cyc[0])>>8) * (env[0]>> 9)       // 8x7=15bit
                             + ((c[1]+=cyc[1])>>8) * (env[1]>> 9) )>>8; // 8x7=15bit 15/15(16bit)-> 8bit
                break;
      case 3:   TCB0.CCMPH = ( ((c[0]+=cyc[0])>>8) * (env[0]>> 9)       // 8x7=15bit
                             + ((c[1]+=cyc[1])>>8) * (env[1]>>10)       // 8x6=14bit
                             + ((c[2]+=cyc[2])>>8) * (env[2]>>10) )>>8; // 8x6=14bit 15/14/14(16bit)-> 8bit
                break;
      case 4:   TCB0.CCMPH = ( ((c[0]+=cyc[0])>>8) * (env[0]>>10)       // 8x6=14bit
                             + ((c[1]+=cyc[1])>>8) * (env[1]>>10)       // 8x6=14bit
                             + ((c[2]+=cyc[2])>>8) * (env[2]>>10)       // 8x6=14bit
                             + ((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
  TCB0.CCMPH = 0;                       // Set output to 0
}

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

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

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