202duino で 減衰矩形波の音楽再生 [Arduino]
減衰矩形波での音楽再生スケッチをATtiny202用に調整してみた。
正弦波の実験ではノイズが出たのに矩形波ではノイズが目立たなくなった。
(直接スピーカーに接続です。アンプとかは壊れる可能性があるのでダメ。)
よくわからない。
以下、スケッチ。
20MHz用に調整してあります。
"note2.h" は以下参照
Digisparkで音楽演奏【楽譜編】
https://hello-world.blog.ss-blog.jp/2022-07-04
正弦波の実験ではノイズが出たのに矩形波ではノイズが目立たなくなった。
(直接スピーカーに接続です。アンプとかは壊れる可能性があるのでダメ。)
よくわからない。
以下、スケッチ。
20MHz用に調整してあります。
// megaTinyCore ATtiny202/212/402/412 Score Replay Sketch
#include "notes2.h" // Definition data of notes ( pitch (scale & octave), and note value (length))
#define MAX_TRACK (4) // Maximum number of tracks
// Number of cycles that are the wavelength of the basic 12-note scale (from C0 to B0) (@20MHz, with an interrupt every 256clocks)
static const uint16_t CYC_SCALE[] = { 4778, 4510, 4257, 4018, 3792, 3579, 3378, 3189, 3010, 2841, 2681, 2531 };
// 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
}
void loop(){
play202( Jesus ); // Playback
delay(1000);
}
void play202(const uint16_t *d){ // ATtiny202(20MHz) 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];// Number of interrupt cycles (cyc) required for one sound wavelength cycle and its counter (c)
uint16_t env[MAX_TRACK]; // Sound amplitude (envelope)
uint16_t wav[MAX_TRACK]; // Output value
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)
cyc[n] = (note>>8) ? CYC_SCALE[ (note>>8) & 0xf ] >> (note>>12) : 0; // Upper 4 bits are octave, next 4 bits are pitch class (0-11), 0 for rests
c[n] = 0; // Initialize the counter for the number of cycles to create one square wave cycle
env[n] = 0xffff; // Initially, the maximum amplitude
}
if( !n ) n = NoteCycle;
}
// * Waveform Processing / Output *
switch( Tracks ) { // Create output data, Square wave with duty ratio of 1:1
case 4: wav[3] = ( ( c[3] = (++c[3]==cyc[3]) ? 0 : c[3] ) < (cyc[3]>>1) ) ? env[3] : 0; [[fallthrough]];
case 3: wav[2] = ( ( c[2] = (++c[2]==cyc[2]) ? 0 : c[2] ) < (cyc[2]>>1) ) ? env[2] : 0; [[fallthrough]];
case 2: wav[1] = ( ( c[1] = (++c[1]==cyc[1]) ? 0 : c[1] ) < (cyc[1]>>1) ) ? env[1] : 0; [[fallthrough]];
case 1: wav[0] = ( ( c[0] = (++c[0]==cyc[0]) ? 0 : c[0] ) < (cyc[0]>>1) ) ? env[0] : 0;
}
switch( Tracks ) { // WO(ATtiny202:PA1) Change output by number of tracks
case 1: TCB0.CCMPH = wav[0] >>8; break;
case 2: TCB0.CCMPH = ((wav[0]>>1) + (wav[1]>>1)) >>8; break;
case 3: TCB0.CCMPH = ((wav[0]>>1) + (wav[1]>>2) + (wav[2]>>2)) >>8; break;
case 4: TCB0.CCMPH = ((wav[0]>>2) + (wav[1]>>2) + (wav[2]>>2) + (wav[3]>>2)) >>8;
}
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
}
"note2.h" は以下参照
Digisparkで音楽演奏【楽譜編】
https://hello-world.blog.ss-blog.jp/2022-07-04
2023-06-19 21:28
nice!(0)
コメント(0)
コメント 0