Added a drum synthesis object to Audio librarydds
| @@ -0,0 +1,104 @@ | |||
| #include <Audio.h> | |||
| #include <Wire.h> | |||
| #include <SPI.h> | |||
| #include <SD.h> | |||
| #include <SerialFlash.h> | |||
| #include <synth_simple_drum.h> | |||
| #include <Audio.h> | |||
| #include <Wire.h> | |||
| #include <SPI.h> | |||
| #include <SD.h> | |||
| #include <SerialFlash.h> | |||
| // GUItool: begin automatically generated code | |||
| AudioSynthSimpleDrum drum2; //xy=399,244 | |||
| AudioSynthSimpleDrum drum3; //xy=424,310 | |||
| AudioSynthSimpleDrum drum1; //xy=431,197 | |||
| AudioSynthSimpleDrum drum4; //xy=464,374 | |||
| AudioMixer4 mixer1; //xy=737,265 | |||
| AudioOutputI2S i2s1; //xy=979,214 | |||
| AudioConnection patchCord1(drum2, 0, mixer1, 1); | |||
| AudioConnection patchCord2(drum3, 0, mixer1, 2); | |||
| AudioConnection patchCord3(drum1, 0, mixer1, 0); | |||
| AudioConnection patchCord4(drum4, 0, mixer1, 3); | |||
| AudioConnection patchCord5(mixer1, 0, i2s1, 0); | |||
| AudioConnection patchCord6(mixer1, 0, i2s1, 1); | |||
| AudioControlSGTL5000 sgtl5000_1; //xy=930,518 | |||
| // GUItool: end automatically generated code | |||
| static uint32_t next; | |||
| void setup() { | |||
| // put your setup code here, to run once: | |||
| Serial.begin(115200); | |||
| // audio library init | |||
| AudioMemory(15); | |||
| next = millis() + 1000; | |||
| AudioNoInterrupts(); | |||
| drum1.frequency(60); | |||
| drum1.length(1500); | |||
| drum1.secondMix(0.0); | |||
| drum1.pitchMod(0.55); | |||
| drum2.frequency(60); | |||
| drum2.length(300); | |||
| drum2.secondMix(0.0); | |||
| drum2.pitchMod(1.0); | |||
| drum3.frequency(550); | |||
| drum3.length(400); | |||
| drum3.secondMix(1.0); | |||
| drum3.pitchMod(0.5); | |||
| drum4.frequency(1200); | |||
| drum4.length(150); | |||
| drum4.secondMix(0.0); | |||
| drum4.pitchMod(0.0); | |||
| sgtl5000_1.enable(); | |||
| sgtl5000_1.volume(0.5); | |||
| AudioInterrupts(); | |||
| } | |||
| void loop() { | |||
| // put your main code here, to run repeatedly: | |||
| static uint32_t num = 0; | |||
| if(millis() == next) | |||
| { | |||
| next = millis() + 1000; | |||
| switch(num % 4) | |||
| { | |||
| case 0: | |||
| drum1.noteOn(); | |||
| break; | |||
| case 1: | |||
| drum2.noteOn(); | |||
| break; | |||
| case 2: | |||
| drum3.noteOn(); | |||
| break; | |||
| case 3: | |||
| drum4.noteOn(); | |||
| break; | |||
| } | |||
| num++; | |||
| Serial.print("Diagnostics: "); | |||
| Serial.print(AudioProcessorUsageMax()); | |||
| Serial.print(" "); | |||
| Serial.println(AudioMemoryUsageMax()); | |||
| AudioProcessorUsageMaxReset(); | |||
| } | |||
| } | |||
| @@ -361,6 +361,7 @@ span.mainfunction {color: #993300; font-weight: bolder} | |||
| {"type":"AudioPlaySerialflashRaw","data":{"defaults":{"name":{"value":"new"}},"shortName":"playFlashRaw","inputs":0,"outputs":1,"category":"play-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
| {"type":"AudioPlayQueue","data":{"defaults":{"name":{"value":"new"}},"shortName":"queue","inputs":0,"outputs":1,"category":"play-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
| {"type":"AudioRecordQueue","data":{"defaults":{"name":{"value":"new"}},"shortName":"queue","inputs":1,"outputs":0,"category":"record-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
| {"type":"AudioSynthSimpleDrum","data":{"defaults":{"name":{"value":"new"}},"shortName":"drum","inputs":0,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
| {"type":"AudioSynthWaveformSine","data":{"defaults":{"name":{"value":"new"}},"shortName":"sine","inputs":0,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
| {"type":"AudioSynthWaveformSineHires","data":{"defaults":{"name":{"value":"new"}},"shortName":"sine_hires","inputs":0,"outputs":2,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
| {"type":"AudioSynthWaveformSineModulated","data":{"defaults":{"name":{"value":"new"}},"shortName":"sine_fm","inputs":1,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
| @@ -1338,6 +1339,51 @@ The actual packets are taken | |||
| </div> | |||
| </script> | |||
| <script type="text/x-red" data-help-name="AudioSynthSimpleDrum"> | |||
| <h3>Summary</h3> | |||
| <div class=tooltipinfo> | |||
| <p>Generate a synthesised drum sound. Also useful for laser pistol and bursting | |||
| bubble sound effects.</p> | |||
| </div> | |||
| <h3>Audio Connections</h3> | |||
| <table class=doc align=center cellpadding=3> | |||
| <tr class=top><th>Port</th><th>Purpose</th></tr> | |||
| <tr class=odd><td align=center>Out 0</td><td>Drum Tone Output</td></tr> | |||
| </table> | |||
| <h3>Functions</h3> | |||
| <p class=func><span class=keyword>noteOn</span>();</p> | |||
| <p class=desc>Trigger the drum. | |||
| </p> | |||
| <p class=func><span class=keyword>frequency</span>(frequency);</p> | |||
| <p class=desc>Set the base frequency of the drum. | |||
| </p> | |||
| <p class=func><span class=keyword>length</span>(milliseconds);</p> | |||
| <p class=desc>Set the duration of the envelope, in milliseconds. | |||
| </p> | |||
| <p class=func><span class=keyword>secondMix</span>(level);</p> | |||
| <p class=desc>Emulates a two-headed tom, by adding a second sine wave that is | |||
| harmonized a perfect fifth above | |||
| the base frequency. Using this involves a slight CPU penalty. | |||
| </p> | |||
| <p class=func><span class=keyword>pitchMod</span>(depth);</p> | |||
| <p class=desc>Set the depth of envelope of the pitch, by a maximum of two octaves. | |||
| Default is 0.5, with no modulation. Values above 0.5 cause the pitch to sweep | |||
| downwards, values lower than 0.5 cause the pitch to sweep upwards. | |||
| </p> | |||
| <h3>Examples</h3> | |||
| <p class=exam>File > Examples > Synthesis > SimpleDrumm | |||
| </p> | |||
| <h3>Notes</h3> | |||
| <p></p> | |||
| </script> | |||
| <script type="text/x-red" data-template-name="AudioSynthSimpleDrum"> | |||
| <div class="form-row"> | |||
| <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> | |||
| <input type="text" id="node-input-name" placeholder="Name"> | |||
| </div> | |||
| </script> | |||
| <script type="text/x-red" data-help-name="AudioSynthWaveformSineHires"> | |||
| <h3>Summary</h3> | |||
| <div class=tooltipinfo> | |||
| @@ -0,0 +1,208 @@ | |||
| /* Audio Library for Teensy 3.X | |||
| * Copyright (c) 2016, Byron Jacquot, SparkFun Electronics | |||
| * | |||
| * Development of this audio library was funded by PJRC.COM, LLC by sales of | |||
| * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop | |||
| * open source software by purchasing Teensy or other PJRC products. | |||
| * | |||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| * of this software and associated documentation files (the "Software"), to deal | |||
| * in the Software without restriction, including without limitation the rights | |||
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| * copies of the Software, and to permit persons to whom the Software is | |||
| * furnished to do so, subject to the following conditions: | |||
| * | |||
| * The above copyright notice, development funding notice, and this permission | |||
| * notice shall be included in all copies or substantial portions of the Software. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
| * THE SOFTWARE. | |||
| */ | |||
| #include "synth_simple_drum.h" | |||
| extern "C" { | |||
| extern const int16_t AudioWaveformSine[257]; | |||
| } | |||
| void AudioSynthSimpleDrum::noteOn(void) | |||
| { | |||
| __disable_irq(); | |||
| wav_phasor = 0; | |||
| wav_phasor2 = 0; | |||
| env_lin_current = 0x7fff0000; | |||
| __enable_irq(); | |||
| } | |||
| void AudioSynthSimpleDrum::secondMix(float level) | |||
| { | |||
| // As level goes from 0.0 to 1.0, | |||
| // second goes from 0 to 1/2 scale | |||
| // first goes from full scale to half scale. | |||
| if(level < 0) | |||
| { | |||
| level = 0; | |||
| } | |||
| else if(level > 1.0) | |||
| { | |||
| level = 1.0; | |||
| } | |||
| __disable_irq(); | |||
| wav_amplitude2 = level * 0x3fff; | |||
| wav_amplitude1 = 0x7fff - wav_amplitude2; | |||
| __enable_irq(); | |||
| } | |||
| void AudioSynthSimpleDrum::pitchMod(float depth) | |||
| { | |||
| int32_t intdepth, calc; | |||
| // Validate parameter | |||
| if(depth < 0) | |||
| { | |||
| depth = 0; | |||
| } | |||
| else if(depth > 1.0) | |||
| { | |||
| depth = 1.0; | |||
| } | |||
| // Depth is float, 0.0..1.0 | |||
| // turn 0.0 to 1.0 into | |||
| // 0x0 to 0x3fff; | |||
| intdepth = depth * 0x7fff; | |||
| // Lets turn it into 2.14, in range between -0.75 and 2.9999, woth 0 at 0.5 | |||
| // It becomes the scalar for the modulation component of the phasor increment. | |||
| if(intdepth < 0x4000) | |||
| { | |||
| // 0 to 0.5 becomes | |||
| // -0x3000 (0xffffCfff) to 0 () | |||
| calc = ((0x4000 - intdepth) * 0x3000 )>> 14; | |||
| calc = -calc; | |||
| } | |||
| else | |||
| { | |||
| // 0.5 to 1.0 becomes | |||
| // 0x00 to 0xbfa0 | |||
| calc = ((intdepth - 0x4000) * 0xc000)>> 14; | |||
| } | |||
| // Call result 2.14 format (max of ~3.99...approx 4) | |||
| // See note in update(). | |||
| wav_pitch_mod = calc; | |||
| } | |||
| void AudioSynthSimpleDrum::update(void) | |||
| { | |||
| audio_block_t *block_wav; | |||
| int16_t *p_wave, *end; | |||
| int32_t sin_l, sin_r, interp, mod, mod2, delta; | |||
| int32_t interp2; | |||
| int32_t index, scale; | |||
| bool do_second; | |||
| int32_t env_sqr_current; // the square of the linear value - inexpensive quasi exponential decay. | |||
| block_wav = allocate(); | |||
| if (!block_wav) return; | |||
| p_wave = (block_wav->data); | |||
| end = p_wave + AUDIO_BLOCK_SAMPLES; | |||
| // 50 is arbitrary threshold... | |||
| // low values of second are inaudible, and we can save CPU cycles | |||
| // by not calculating second when it's really quiet. | |||
| do_second = (wav_amplitude2 > 50); | |||
| while(p_wave < end) | |||
| { | |||
| // Do envelope first | |||
| if(env_lin_current < 0x0000ffff) | |||
| { | |||
| // If envelope has expired, then stuff zeros into output buffer. | |||
| *p_wave = 0; | |||
| p_wave++; | |||
| } | |||
| else | |||
| { | |||
| env_lin_current -= env_decrement; | |||
| env_sqr_current = multiply_16tx16t(env_lin_current, env_lin_current) ; | |||
| // do wave second; | |||
| wav_phasor += wav_increment; | |||
| // modulation changes how we use the increment | |||
| // the increment will be scaled by the modulation amount. | |||
| // | |||
| // Pitch mod is in range [-0.75 .. 3.99999] in 2.14 format | |||
| // Current envelope value gets scaled by mod depth. | |||
| // Then phasor increment gets scaled by that. | |||
| mod = signed_multiply_32x16b((env_sqr_current), (wav_pitch_mod>>1)) >> 13; | |||
| mod2 = signed_multiply_32x16b(wav_increment<<3, mod>>1); | |||
| wav_phasor += (mod2); | |||
| wav_phasor &= 0x7fffffff; | |||
| if(do_second) | |||
| { | |||
| // A perfect fifth uses increment of 1.5 times regular increment | |||
| wav_phasor2 += wav_increment; | |||
| wav_phasor2 += (wav_increment >> 1); | |||
| wav_phasor2 += mod2; | |||
| wav_phasor2 += (mod2 >> 1); | |||
| wav_phasor2 &= 0x7fffffff; | |||
| } | |||
| // Phase to Sine lookup * interp: | |||
| index = wav_phasor >> 23; // take top valid 8 bits | |||
| sin_l = AudioWaveformSine[index]; | |||
| sin_r = AudioWaveformSine[index+1]; | |||
| // The fraction of the phasor in time we are between L and R | |||
| // is the same as the fraction of the ampliture of that interval we should add | |||
| // to L. | |||
| delta = sin_r-sin_l; | |||
| scale = (wav_phasor >> 7) & 0xfFFF; | |||
| delta = (delta * scale)>> 16; | |||
| interp = sin_l + delta; | |||
| if(do_second) | |||
| { | |||
| index = wav_phasor2 >> 23; // take top valid 8 bits | |||
| sin_l = AudioWaveformSine[index]; | |||
| sin_r = AudioWaveformSine[index+1]; | |||
| delta = sin_r-sin_l; | |||
| scale = (wav_phasor2 >> 7) & 0xFFFF; | |||
| delta = (delta * scale)>> 16; | |||
| interp2 = sin_l + delta; | |||
| // Then scale and add the two waves | |||
| interp2 = (interp2 * wav_amplitude2 ) >> 15; | |||
| interp = (interp * wav_amplitude1) >> 15; | |||
| interp = interp + interp2; | |||
| } | |||
| *p_wave = signed_multiply_32x16b(env_sqr_current, interp ) >> 15 ; | |||
| p_wave++; | |||
| } | |||
| } | |||
| transmit(block_wav, 0); | |||
| release(block_wav); | |||
| } | |||
| @@ -0,0 +1,95 @@ | |||
| /* Audio Library for Teensy 3.X | |||
| * Copyright (c) 2016, Byron Jacquot, SparkFun Electronics | |||
| * | |||
| * Development of this audio library was funded by PJRC.COM, LLC by sales of | |||
| * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop | |||
| * open source software by purchasing Teensy or other PJRC products. | |||
| * | |||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| * of this software and associated documentation files (the "Software"), to deal | |||
| * in the Software without restriction, including without limitation the rights | |||
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| * copies of the Software, and to permit persons to whom the Software is | |||
| * furnished to do so, subject to the following conditions: | |||
| * | |||
| * The above copyright notice, development funding notice, and this permission | |||
| * notice shall be included in all copies or substantial portions of the Software. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
| * THE SOFTWARE. | |||
| */ | |||
| #pragma once | |||
| #ifndef _SYNTH_SIMPLE_DRUM_H_ | |||
| #define _SYNTH_SIMPLE_DRUM_H_ | |||
| #include "AudioStream.h" | |||
| #include "utility/dspinst.h" | |||
| class AudioSynthSimpleDrum : public AudioStream | |||
| { | |||
| public: | |||
| AudioSynthSimpleDrum() : AudioStream(1, inputQueueArray) | |||
| { | |||
| length(600); | |||
| frequency(60); | |||
| pitchMod(0x200); | |||
| wav_amplitude1 = 0x7fff; | |||
| wav_amplitude2 = 0; | |||
| } | |||
| void noteOn(); | |||
| void frequency(float freq) | |||
| { | |||
| if(freq < 0.0) | |||
| freq = 0; | |||
| else if(freq > (AUDIO_SAMPLE_RATE_EXACT/2)) | |||
| freq = AUDIO_SAMPLE_RATE_EXACT/2; | |||
| wav_increment = (freq * (0x7fffffffLL/AUDIO_SAMPLE_RATE_EXACT)) + 0.5; | |||
| } | |||
| void length(int32_t milliseconds) | |||
| { | |||
| if(milliseconds < 0) | |||
| return; | |||
| if(milliseconds > 5000) | |||
| milliseconds = 5000; | |||
| int32_t len_samples = milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0); | |||
| env_decrement = (0x7fff0000/len_samples); | |||
| }; | |||
| void secondMix(float level); | |||
| void pitchMod(float depth); | |||
| using AudioStream::release; | |||
| virtual void update(void); | |||
| private: | |||
| audio_block_t *inputQueueArray[1]; | |||
| // Envelope params | |||
| int32_t env_lin_current; // present value of linear slope. | |||
| int32_t env_decrement; // how each sample deviates from previous. | |||
| // Waveform params | |||
| uint32_t wav_phasor; | |||
| uint32_t wav_phasor2; | |||
| int16_t wav_amplitude1; | |||
| int16_t wav_amplitude2; | |||
| uint32_t wav_increment; | |||
| int32_t wav_pitch_mod; | |||
| }; | |||
| #endif | |||