UNO R4で音楽演奏 [Arduino]
音楽演奏のスケッチをいろいろなバージョンで作ってきたけど、UNO R4でもやってみた。
・DAC(12bit)を使用
・正弦波は計算で作成
・音程も計算で作成
・レジスタ触らない
・ところどころブラッシュアップ
10kΩの可変抵抗の前に100kΩの抵抗を挟んで約10分の1に分圧したらボリュームとしてちょうどいい感じ。(理論上は40kΩかな)
楽譜の作成と定義のファイルは以前と同様。
https://hello-world.blog.ss-blog.jp/2022-07-04
・DAC(12bit)を使用
・正弦波は計算で作成
・音程も計算で作成
・レジスタ触らない
・ところどころブラッシュアップ
10kΩの可変抵抗の前に100kΩの抵抗を挟んで約10分の1に分圧したらボリュームとしてちょうどいい感じ。(理論上は40kΩかな)
楽譜の作成と定義のファイルは以前と同様。
https://hello-world.blog.ss-blog.jp/2022-07-04
// Uno R4 DAC Score Replay Sketch
#include "notes2.h" // note definition data (pitch(octave,scale) + length)
#define F_SAMP 50000 // sampling frequency (Hz) (divisor of 1,000,000 (usec))
#define MAX_TRACK 4 // Maximum tracks
static uint16_t SIN[256]; // array of sine wave
static uint16_t OCT9[12]; // array subscript difference in the 9th octave
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(){
uint16_t i;
analogWriteResolution(12);
for(i=0; i<256; i++) SIN[i] = 16383.9 * (1 - cos(6.283185 * i / 256)) / 2; // 14bit sine wave
for(i=0; i< 12; i++) OCT9[i] = (440 << 16) * pow(2, (i + 51) / 12.0) / F_SAMP; // A4=440
}
void loop(){
playR4( Jesus );
}
void playR4( const uint16_t *score ){
uint8_t Tracks = 0; // track count
uint16_t note; // note (pitch(octave,scale) + length)
uint16_t NoteCycle, n; // reference note (96th note) cycle and its counter (n)
uint16_t p[MAX_TRACK]; // pointer for each track
uint8_t len[MAX_TRACK]; // note length (how many 96th notes)
uint16_t s[MAX_TRACK] = {0}; // waveform subscript (s) (x256)
uint16_t ds[MAX_TRACK] = {0}; // and its difference (ds) (x256)
uint16_t env[MAX_TRACK]; // sound envelope
uint16_t atn = 0, Atn; // attenuation counter and initial value
// *** Preparing Scores ***
Atn = 150 * F_SAMP / 1000 / 356; // attenuation half-life : 150 msec
NoteCycle = F_SAMP *4*60 / score[0] / MIN_NOTE; // reference note(96th note) cycles
for( uint16_t i = 1; Tracks < MAX_TRACK; ) { // Get track count and starting location
if( score[i++] != 0 ) continue; // Skip until 0 comes
if( score[i] == 0 ) break; // If two 0s follow, end of data
len[ Tracks ] = 1; // note length subtraction counter to 1
p[ Tracks++ ] = i; // Get location in memory, Count up the tracks
}
// *** Playback ***
n = Tracks; // To play immediately after the loop starts
uint32_t usInt = 1000000 / F_SAMP; // sampling time interval(usec)
uint32_t usPre = micros(); // sampling time previous value(usec)
do {
if( --n < Tracks ) { // Processing of score for each reference note length
if( !--len[n] ) {
note = score[ p[n]++ ];
len[n] = note & 0x00ff; // The lower 8 bits are note length (Multiples of 96th notes)
if( note & 0xff00 ) { // If not a rest... (Leave a lingering sound even with rests)
ds[n] = OCT9[ (note>>8) & 0x0f ] >> (9 - (note>>12)); // increment subscript (x256)
s[n] = 0; // start of waveform cycle
env[n] = 0xffff; // the maximum amplitude initially
}
}
if( !n ) n = NoteCycle;
}
switch( Tracks ) { // Change output by number of tracks
case 1: analogWrite( DAC, ( SIN[ (s[0]+=ds[0])>>8 ] * env[0] ) >> 18 ); // 14x16=30bit >> 18 = 12bit
break;
case 2: analogWrite( DAC, ( SIN[ (s[0]+=ds[0])>>8 ] * env[0]
+ SIN[ (s[1]+=ds[1])>>8 ] * env[1] ) >> 19 ); // 30/30(31bit)
break;
case 3: analogWrite( DAC, ( SIN[ (s[0]+=ds[0])>>8 ] * env[0]
+ SIN[ (s[1]+=ds[1])>>8 ] * env[1]
+ SIN[ (s[2]+=ds[2])>>8 ] * env[2] ) >> 20 ); // 30/30/30(31.5bit)
break;
case 4: analogWrite( DAC, ( SIN[ (s[0]+=ds[0])>>8 ] * env[0]
+ SIN[ (s[1]+=ds[1])>>8 ] * env[1]
+ SIN[ (s[2]+=ds[2])>>8 ] * env[2]
+ SIN[ (s[3]+=ds[3])>>8 ] * env[3] ) >> 20 ); // 30/30/30/30(32bit)
}
if( !atn-- ) atn = Atn; // subtract attenuation counter
if( atn < Tracks ) env[atn] -= (env[atn]>>9); // amplitude attenuation
while( micros() - usPre < usInt ); // wait for next cycle
usPre += usInt;
} while( note ); // Exit if note data is 0
analogWrite( DAC, 0 ); // Set output to 0
}
2024-01-01 23:07
nice!(0)
コメント(0)
コメント 0