forest-all-around/sampler/lib/Audio_SdFat/examples/Synthesis/PlaySynthMusic/PlaySynthMusic.ino
Dooho Yi 91f92c0e6c audio & sd lib upgrade (SdFatSdioEX)
migration from 'smp_v1p0' dev.
for 'sampler' -> skip irrelavant note msg. and keep playing
2019-12-11 23:37:44 +09:00

257 lines
7 KiB
C++

// Implement a 16 note polyphonic midi player :-)
//
// Music data is read from memory. The "Miditones" program is used to
// convert from a MIDI file to this compact format.
//
// This example code is in the public domain.
#include <Audio.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>
#include <SerialFlash.h>
#include "PlaySynthMusic.h"
unsigned char *sp = score;
#define AMPLITUDE (0.2)
// Create 16 waveforms, one for each MIDI channel
AudioSynthWaveform sine0, sine1, sine2, sine3;
AudioSynthWaveform sine4, sine5, sine6, sine7;
AudioSynthWaveform sine8, sine9, sine10, sine11;
AudioSynthWaveform sine12, sine13, sine14, sine15;
AudioSynthWaveform *waves[16] = {
&sine0, &sine1, &sine2, &sine3,
&sine4, &sine5, &sine6, &sine7,
&sine8, &sine9, &sine10, &sine11,
&sine12, &sine13, &sine14, &sine15
};
// allocate a wave type to each channel.
// The types used and their order is purely arbitrary.
short wave_type[16] = {
WAVEFORM_SINE,
WAVEFORM_SQUARE,
WAVEFORM_SAWTOOTH,
WAVEFORM_TRIANGLE,
WAVEFORM_SINE,
WAVEFORM_SQUARE,
WAVEFORM_SAWTOOTH,
WAVEFORM_TRIANGLE,
WAVEFORM_SINE,
WAVEFORM_SQUARE,
WAVEFORM_SAWTOOTH,
WAVEFORM_TRIANGLE,
WAVEFORM_SINE,
WAVEFORM_SQUARE,
WAVEFORM_SAWTOOTH,
WAVEFORM_TRIANGLE
};
// Each waveform will be shaped by an envelope
AudioEffectEnvelope env0, env1, env2, env3;
AudioEffectEnvelope env4, env5, env6, env7;
AudioEffectEnvelope env8, env9, env10, env11;
AudioEffectEnvelope env12, env13, env14, env15;
AudioEffectEnvelope *envs[16] = {
&env0, &env1, &env2, &env3,
&env4, &env5, &env6, &env7,
&env8, &env9, &env10, &env11,
&env12, &env13, &env14, &env15
};
// Route each waveform through its own envelope effect
AudioConnection patchCord01(sine0, env0);
AudioConnection patchCord02(sine1, env1);
AudioConnection patchCord03(sine2, env2);
AudioConnection patchCord04(sine3, env3);
AudioConnection patchCord05(sine4, env4);
AudioConnection patchCord06(sine5, env5);
AudioConnection patchCord07(sine6, env6);
AudioConnection patchCord08(sine7, env7);
AudioConnection patchCord09(sine8, env8);
AudioConnection patchCord10(sine9, env9);
AudioConnection patchCord11(sine10, env10);
AudioConnection patchCord12(sine11, env11);
AudioConnection patchCord13(sine12, env12);
AudioConnection patchCord14(sine13, env13);
AudioConnection patchCord15(sine14, env14);
AudioConnection patchCord16(sine15, env15);
// Four mixers are needed to handle 16 channels of music
AudioMixer4 mixer1;
AudioMixer4 mixer2;
AudioMixer4 mixer3;
AudioMixer4 mixer4;
// Mix the 16 channels down to 4 audio streams
AudioConnection patchCord17(env0, 0, mixer1, 0);
AudioConnection patchCord18(env1, 0, mixer1, 1);
AudioConnection patchCord19(env2, 0, mixer1, 2);
AudioConnection patchCord20(env3, 0, mixer1, 3);
AudioConnection patchCord21(env4, 0, mixer2, 0);
AudioConnection patchCord22(env5, 0, mixer2, 1);
AudioConnection patchCord23(env6, 0, mixer2, 2);
AudioConnection patchCord24(env7, 0, mixer2, 3);
AudioConnection patchCord25(env8, 0, mixer3, 0);
AudioConnection patchCord26(env9, 0, mixer3, 1);
AudioConnection patchCord27(env10, 0, mixer3, 2);
AudioConnection patchCord28(env11, 0, mixer3, 3);
AudioConnection patchCord29(env12, 0, mixer4, 0);
AudioConnection patchCord30(env13, 0, mixer4, 1);
AudioConnection patchCord31(env14, 0, mixer4, 2);
AudioConnection patchCord32(env15, 0, mixer4, 3);
// Now create 2 mixers for the main output
AudioMixer4 mixerLeft;
AudioMixer4 mixerRight;
AudioOutputI2S audioOut;
// Mix all channels to both the outputs
AudioConnection patchCord33(mixer1, 0, mixerLeft, 0);
AudioConnection patchCord34(mixer2, 0, mixerLeft, 1);
AudioConnection patchCord35(mixer3, 0, mixerLeft, 2);
AudioConnection patchCord36(mixer4, 0, mixerLeft, 3);
AudioConnection patchCord37(mixer1, 0, mixerRight, 0);
AudioConnection patchCord38(mixer2, 0, mixerRight, 1);
AudioConnection patchCord39(mixer3, 0, mixerRight, 2);
AudioConnection patchCord40(mixer4, 0, mixerRight, 3);
AudioConnection patchCord41(mixerLeft, 0, audioOut, 0);
AudioConnection patchCord42(mixerRight, 0, audioOut, 1);
AudioControlSGTL5000 codec;
// Initial value of the volume control
int volume = 50;
void setup()
{
Serial.begin(115200);
//while (!Serial) ; // wait for Arduino Serial Monitor
delay(200);
// http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
Serial.print("Begin ");
Serial.println(__FILE__);
// Proc = 12 (13), Mem = 2 (8)
// Audio connections require memory to work.
// The memory usage code indicates that 10 is the maximum
// so give it 12 just to be sure.
AudioMemory(18);
codec.enable();
codec.volume(0.45);
// reduce the gain on some channels, so half of the channels
// are "positioned" to the left, half to the right, but all
// are heard at least partially on both ears
mixerLeft.gain(1, 0.36);
mixerLeft.gain(3, 0.36);
mixerRight.gain(0, 0.36);
mixerRight.gain(2, 0.36);
// set envelope parameters, for pleasing sound :-)
for (int i=0; i<16; i++) {
envs[i]->attack(9.2);
envs[i]->hold(2.1);
envs[i]->decay(31.4);
envs[i]->sustain(0.6);
envs[i]->release(84.5);
// uncomment these to hear without envelope effects
//envs[i]->attack(0.0);
//envs[i]->hold(0.0);
//envs[i]->decay(0.0);
//envs[i]->release(0.0);
}
Serial.println("setup done");
// Initialize processor and memory measurements
AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset();
}
unsigned long last_time = millis();
void loop()
{
unsigned char c,opcode,chan;
unsigned long d_time;
// Change this to if(1) for measurement output every 5 seconds
if(1) {
if(millis() - last_time >= 5000) {
Serial.print("Proc = ");
Serial.print(AudioProcessorUsage());
Serial.print(" (");
Serial.print(AudioProcessorUsageMax());
Serial.print("), Mem = ");
Serial.print(AudioMemoryUsage());
Serial.print(" (");
Serial.print(AudioMemoryUsageMax());
Serial.println(")");
last_time = millis();
}
}
// Volume control
// uncomment if you have a volume pot soldered to your audio shield
/*
int n = analogRead(15);
if (n != volume) {
volume = n;
codec.volume((float)n / 1023);
}
*/
// read the next note from the table
c = *sp++;
opcode = c & 0xF0;
chan = c & 0x0F;
if(c < 0x80) {
// Delay
d_time = (c << 8) | *sp++;
delay(d_time);
return;
}
if(*sp == CMD_STOP) {
for (chan=0; chan<10; chan++) {
envs[chan]->noteOff();
waves[chan]->amplitude(0);
}
Serial.println("DONE");
while(1);
}
// It is a command
// Stop the note on 'chan'
if(opcode == CMD_STOPNOTE) {
envs[chan]->noteOff();
return;
}
// Play the note on 'chan'
if(opcode == CMD_PLAYNOTE) {
unsigned char note = *sp++;
unsigned char velocity = *sp++;
AudioNoInterrupts();
waves[chan]->begin(AMPLITUDE * velocity2amplitude[velocity-1],
tune_frequencies2_PGM[note],
wave_type[chan]);
envs[chan]->noteOn();
AudioInterrupts();
return;
}
// replay the tune
if(opcode == CMD_RESTART) {
sp = score;
return;
}
}