diff --git a/README.md b/README.md
index 358b181..57b4f61 100644
--- a/README.md
+++ b/README.md
@@ -152,7 +152,7 @@ sudo losetup -d "${DEV}"
rm -r boot
# Write to SD card
-sudo dd if="${IMG}" of=/dev/mmcblk0 bs=512k status=progress
+sudo dd if="${IMG}" of=/dev/mmcblk0 bs=512k status=progress && sync
```
## Acknowledgements
diff --git a/Synth_Dexed b/Synth_Dexed
index 70293ae..e414a87 160000
--- a/Synth_Dexed
+++ b/Synth_Dexed
@@ -1 +1 @@
-Subproject commit 70293ae5998643c706244b090504dde8b4097851
+Subproject commit e414a8718300815aefc3fe0acd8df5c12ad0b58a
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 0000000..ef6a51f
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,21 @@
+
+#ifndef _common_h
+#define _common_h
+
+inline long maplong(long x, long in_min, long in_max, long out_min, long out_max) {
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+inline float32_t mapfloat(float32_t val, float32_t in_min, float32_t in_max, float32_t out_min, float32_t out_max)
+{
+ return (val - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+#define constrain(amt, low, high) ({ \
+ __typeof__(amt) _amt = (amt); \
+ __typeof__(low) _low = (low); \
+ __typeof__(high) _high = (high); \
+ (_amt < _low) ? _low : ((_amt > _high) ? _high : _amt); \
+})
+
+#endif
diff --git a/src/dexedadapter.h b/src/dexedadapter.h
index a7c77cc..71862bb 100644
--- a/src/dexedadapter.h
+++ b/src/dexedadapter.h
@@ -17,6 +17,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
+
#ifndef _dexedadapter_h
#define _dexedadapter_h
@@ -34,10 +35,6 @@ public:
: Dexed (maxnotes, rate)
{
Dexed::setCompressor(true);
- if(Dexed::getCompressor()==true)
- printf("Dexed-Compressor: enabled\n");
- else
- printf("Dexed-Compressor: disabled\n");
}
void loadVoiceParameters (uint8_t* data)
@@ -61,10 +58,10 @@ public:
m_SpinLock.Release ();
}
- void getSamples (uint16_t n_samples, int16_t* buffer)
+ void getSamples (float32_t* buffer, uint16_t n_samples)
{
m_SpinLock.Acquire ();
- Dexed::getSamples (n_samples, buffer);
+ Dexed::getSamples (buffer, n_samples);
m_SpinLock.Release ();
}
diff --git a/src/effect_platervbstereo.cpp b/src/effect_platervbstereo.cpp
index 4d987e9..5f4ec46 100644
--- a/src/effect_platervbstereo.cpp
+++ b/src/effect_platervbstereo.cpp
@@ -153,12 +153,12 @@ AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate)
lfo2_phase_acc = 0;
lfo2_adder = (UINT32_MAX + 1)/(samplerate * LFO2_FREQ_HZ);
- send_level = 0.0;
+ reverb_level = 0.0;
}
// #define sat16(n, rshift) signed_saturate_rshift((n), 16, (rshift))
-void AudioEffectPlateReverb::doReverb(uint16_t len, int16_t audioblock[][2])
+void AudioEffectPlateReverb::doReverb(float32_t* audioblockL, float32_t* audioblockR, uint16_t len)
{
int i;
float32_t input, acc, temp1, temp2;
@@ -236,7 +236,7 @@ void AudioEffectPlateReverb::doReverb(uint16_t len, int16_t audioblock[][2])
y += (int64_t)y1 * idx;
lfo2_out_cos = (int32_t) (y >> (32-8)); // 16bit output
- input = (float32_t(audioblock[i][0])/32767.0f) * input_attn;
+ input = audioblockL[i] * input_attn;
// chained input allpasses, channel L
acc = in_allp1_bufL[in_allp1_idxL] + input * in_allp_k;
@@ -259,7 +259,7 @@ void AudioEffectPlateReverb::doReverb(uint16_t len, int16_t audioblock[][2])
in_allp_out_L = acc;
if (++in_allp4_idxL >= sizeof(in_allp4_bufL)/sizeof(float32_t)) in_allp4_idxL = 0;
- input = (float32_t(audioblock[i][1])/32767.0f) * input_attn;
+ input = audioblockR[i] * input_attn;
// chained input allpasses, channel R
acc = in_allp1_bufR[in_allp1_idxR] + input * in_allp_k;
@@ -406,13 +406,7 @@ void AudioEffectPlateReverb::doReverb(uint16_t len, int16_t audioblock[][2])
temp1 = acc - master_lowpass_l;
master_lowpass_l += temp1 * master_lowpass_f;
- int32_t out = audioblock[i][0] + int16_t(master_lowpass_l * 32767.0f * send_level);
- if(out > INT16_MAX)
- audioblock[i][0] = INT16_MAX;
- else if(out < INT16_MIN)
- audioblock[i][0] = INT16_MIN;
- else
- audioblock[i][0] = out;
+ audioblockL[i]+=master_lowpass_l * reverb_level;
// Channel R
#ifdef TAP1_MODULATED
@@ -456,12 +450,6 @@ void AudioEffectPlateReverb::doReverb(uint16_t len, int16_t audioblock[][2])
temp1 = acc - master_lowpass_r;
master_lowpass_r += temp1 * master_lowpass_f;
- out = audioblock[i][1] + int16_t(master_lowpass_l * 32767.0f * send_level);
- if(out > INT16_MAX)
- audioblock[i][1] = INT16_MAX;
- else if(out < INT16_MIN)
- audioblock[i][1] = INT16_MIN;
- else
- audioblock[i][1] = out;
+ audioblockR[i]+=master_lowpass_r * reverb_level;
}
}
diff --git a/src/effect_platervbstereo.h b/src/effect_platervbstereo.h
index 3abc62d..8db1bca 100644
--- a/src/effect_platervbstereo.h
+++ b/src/effect_platervbstereo.h
@@ -45,37 +45,9 @@
#ifndef _EFFECT_PLATERVBSTEREO_H
#define _EFFECT_PLATERVBSTEREO_H
-#include "arm_math.h"
#include
-
-#define constrain(amt, low, high) ({ \
- __typeof__(amt) _amt = (amt); \
- __typeof__(low) _low = (low); \
- __typeof__(high) _high = (high); \
- (_amt < _low) ? _low : ((_amt > _high) ? _high : _amt); \
-})
-
-/*
-template
-inline static T min(const T& a, const T& b) {
- return a < b ? a : b;
-}
-
-template
-inline static T max(const T& a, const T& b) {
- return a > b ? a : b;
-}
-
-inline long maplong(long x, long in_min, long in_max, long out_min, long out_max) {
- return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
-}
-*/
-
-inline float32_t mapfloat(float32_t val, float32_t in_min, float32_t in_max, float32_t out_min, float32_t out_max)
-{
- return (val - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
-}
-
+#include
+#include "common.h"
/***
* Loop delay modulation: comment/uncomment to switch sin/cos
@@ -89,7 +61,7 @@ class AudioEffectPlateReverb
{
public:
AudioEffectPlateReverb(float32_t samplerate);
- void doReverb(uint16_t len, int16_t audioblock[][2]);
+ void doReverb(float32_t* audioblockL, float32_t* audioblockR, uint16_t len);
void size(float n)
{
@@ -136,9 +108,9 @@ public:
//__enable_irq();
}
- void send(float n)
+ void level(float n)
{
- send_level = constrain(n, 0.0f, 1.0f);
+ reverb_level = constrain(n, 0.0f, 1.0f);
}
float32_t get_size(void) {return rv_time_k;}
@@ -147,7 +119,7 @@ public:
void tgl_bypass(void) {bypass ^=1;}
private:
bool bypass = false;
- float32_t send_level;
+ float32_t reverb_level;
float32_t input_attn;
float32_t in_allp_k; // input allpass coeff
diff --git a/src/minidexed.cpp b/src/minidexed.cpp
index b462b69..eef5fa4 100644
--- a/src/minidexed.cpp
+++ b/src/minidexed.cpp
@@ -58,6 +58,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
m_nProgram[i] = 0;
m_nVolume[i] = 100;
m_nPan[i] = 64;
+ pan_float[i]=0.0f;
m_nMasterTune[i] = 0;
m_nMIDIChannel[i] = CMIDIDevice::Disabled;
@@ -113,6 +114,10 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
}
#endif
+ // BEGIN setup tg_mixer
+ tg_mixer = new AudioStereoMixer<8>();
+ // END setup tg_mixer
+
// BEGIN setup reverb
reverb = new AudioEffectPlateReverb(pConfig->GetSampleRate());
SetParameter (ParameterReverbSize, 70);
@@ -120,7 +125,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
SetParameter (ParameterReverbLowDamp, 50);
SetParameter (ParameterReverbLowPass, 30);
SetParameter (ParameterReverbDiffusion, 65);
- SetParameter (ParameterReverbSend, 80);
+ SetParameter (ParameterReverbLevel, 80);
// END setup reverb
};
@@ -285,7 +290,7 @@ void CMiniDexed::Run (unsigned nCore)
for (unsigned i = 0; i < CConfig::TGsCore23; i++, nTG++)
{
assert (m_pTG[nTG]);
- m_pTG[nTG]->getSamples (m_nFramesToProcess, m_OutputLevel[nTG]);
+ m_pTG[nTG]->getSamples (m_OutputLevel[nTG], m_nFramesToProcess);
}
}
}
@@ -348,13 +353,11 @@ void CMiniDexed::SetVolume (unsigned nVolume, unsigned nTG)
void CMiniDexed::SetPan (unsigned nPan, unsigned nTG)
{
- if (nPan > 127)
- {
- return;
- }
+ constrain(nPan,-1.0f,1.0f);
assert (nTG < CConfig::ToneGenerators);
m_nPan[nTG] = nPan;
+ pan_float[nTG]=mapfloat(nPan,0,127,-1.0,1.0);
m_UI.ParameterChanged ();
}
@@ -502,7 +505,7 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue)
case ParameterReverbLowDamp: reverb->lodamp (fValue); break;
case ParameterReverbLowPass: reverb->lowpass (fValue); break;
case ParameterReverbDiffusion: reverb->diffusion (fValue); break;
- case ParameterReverbSend: reverb->send (fValue); break;
+ case ParameterReverbLevel: reverb->level (fValue); break;
default:
assert (0);
@@ -622,8 +625,8 @@ void CMiniDexed::ProcessSound (void)
m_GetChunkTimer.Start ();
}
- int16_t SampleBuffer[nFrames];
- m_pTG[0]->getSamples (nFrames, SampleBuffer);
+ //int16_t SampleBuffer[nFrames]; // TODO float->int
+ m_pTG[0]->getSamples (SampleBuffer, nFrames);
if ( m_pSoundDevice->Write (SampleBuffer, sizeof SampleBuffer)
!= (int) sizeof SampleBuffer)
@@ -666,7 +669,7 @@ void CMiniDexed::ProcessSound (void)
for (unsigned i = 0; i < CConfig::TGsCore1; i++)
{
assert (m_pTG[i]);
- m_pTG[i]->getSamples (nFrames, m_OutputLevel[i]);
+ m_pTG[i]->getSamples (m_OutputLevel[i], nFrames);
}
// wait for cores 2 and 3 to complete their work
@@ -678,51 +681,53 @@ void CMiniDexed::ProcessSound (void)
}
}
+ //
+ // Audio signal path after tone generators starts here
+ //
+
// now mix the output of all TGs
- int16_t SampleBuffer[nFrames][2];
+ float32_t SampleBuffer[2][nFrames];
+ uint8_t indexL=0, indexR=1;
+
+ assert (SampleBuffer[0]!=NULL);
+ arm_fill_f32(0.0, SampleBuffer[0], nFrames);
+ assert (SampleBuffer[1]!=NULL);
+ arm_fill_f32(0.0, SampleBuffer[1], nFrames);
+
+ if (m_bChannelsSwapped)
+ {
+ indexL=1;
+ indexR=0;
+ }
assert (CConfig::ToneGenerators == 8);
- for (unsigned i = 0; i < nFrames; i++)
+
+ for (uint16_t i = 0; i < nFrames; i++)
{
- int32_t nLeft = m_OutputLevel[0][i] * (127-m_nPan[0])
- + m_OutputLevel[1][i] * (127-m_nPan[1])
- + m_OutputLevel[2][i] * (127-m_nPan[2])
- + m_OutputLevel[3][i] * (127-m_nPan[3])
- + m_OutputLevel[4][i] * (127-m_nPan[4])
- + m_OutputLevel[5][i] * (127-m_nPan[5])
- + m_OutputLevel[6][i] * (127-m_nPan[6])
- + m_OutputLevel[7][i] * (127-m_nPan[7]);
- nLeft >>= m_nActiveTGsLog2 + 7;
-
- int32_t nRight = m_OutputLevel[0][i] * m_nPan[0]
- + m_OutputLevel[1][i] * m_nPan[1]
- + m_OutputLevel[2][i] * m_nPan[2]
- + m_OutputLevel[3][i] * m_nPan[3]
- + m_OutputLevel[4][i] * m_nPan[4]
- + m_OutputLevel[5][i] * m_nPan[5]
- + m_OutputLevel[6][i] * m_nPan[6]
- + m_OutputLevel[7][i] * m_nPan[7];
- nRight >>= m_nActiveTGsLog2 + 7;
-
- if (!m_bChannelsSwapped)
- {
- SampleBuffer[i][0] = (int16_t) nLeft;
- SampleBuffer[i][1] = (int16_t) nRight;
- }
- else
+ for(uint8_t n=0; ndoReverb(nFrames,SampleBuffer);
+ reverb->doReverb(SampleBuffer[0],SampleBuffer[1],nFrames);
m_ReverbSpinLock.Release ();
// END adding reverb
- if (m_pSoundDevice->Write (SampleBuffer, sizeof SampleBuffer) != (int) sizeof SampleBuffer)
+ // Convert float to int16 array
+ float32_t tmp_float[nFrames*2];
+ int16_t tmp_int[nFrames*2];
+ for(uint16_t i=0; iWrite (tmp_int, sizeof tmp_int) != (int) sizeof tmp_int)
{
LOGERR ("Sound data dropped");
}
diff --git a/src/minidexed.h b/src/minidexed.h
index 2f991f0..987b27a 100644
--- a/src/minidexed.h
+++ b/src/minidexed.h
@@ -39,7 +39,9 @@
#include
#include
#include
+#include "common.h"
#include "effect_platervbstereo.h"
+#include "mixer.h"
class CMiniDexed
#ifdef ARM_ALLOW_MULTI_CORE
@@ -82,7 +84,7 @@ public:
ParameterReverbLowDamp,
ParameterReverbLowPass,
ParameterReverbDiffusion,
- ParameterReverbSend,
+ ParameterReverbLevel,
ParameterUnknown
};
@@ -137,6 +139,7 @@ private:
unsigned m_nProgram[CConfig::ToneGenerators];
unsigned m_nVolume[CConfig::ToneGenerators];
unsigned m_nPan[CConfig::ToneGenerators];
+ unsigned pan_float[CConfig::ToneGenerators];
int m_nMasterTune[CConfig::ToneGenerators];
unsigned m_nMIDIChannel[CConfig::ToneGenerators];
@@ -161,13 +164,15 @@ private:
unsigned m_nActiveTGsLog2;
volatile TCoreStatus m_CoreStatus[CORES];
volatile unsigned m_nFramesToProcess;
- int16_t m_OutputLevel[CConfig::ToneGenerators][CConfig::MaxChunkSize];
+ float32_t m_OutputLevel[CConfig::ToneGenerators][CConfig::MaxChunkSize];
#endif
CPerformanceTimer m_GetChunkTimer;
bool m_bProfileEnabled;
AudioEffectPlateReverb* reverb;
+ AudioStereoMixer<8>* tg_mixer;
+
CSpinLock m_ReverbSpinLock;
};
diff --git a/src/mixer.cpp b/src/mixer.cpp
new file mode 100644
index 0000000..16f4b51
--- /dev/null
+++ b/src/mixer.cpp
@@ -0,0 +1,87 @@
+// Taken from https://github.com/manicken/Audio/tree/templateMixer
+// Adapted for MiniDexed by Holger Wirtz
+
+/* Audio Library for Teensy 3.X
+ * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
+ *
+ * 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
+#include
+#include
+#include "arm_math.h"
+#include "mixer.h"
+
+template void AudioMixer::gain(uint8_t channel, float32_t gain)
+{
+ if (channel >= NN) return;
+
+ if (gain > MAX_GAIN)
+ gain = MAX_GAIN;
+ else if (gain < MIN_GAIN)
+ gain = MIN_GAIN;
+ multiplier[channel] = gain;
+}
+
+template void AudioMixer::gain(float32_t gain)
+{
+ for (uint8_t i = 0; i < NN; i++)
+ {
+ if (gain > MAX_GAIN)
+ gain = MAX_GAIN;
+ else if (gain < MIN_GAIN)
+ gain = MIN_GAIN;
+ multiplier[i] = gain;
+ }
+}
+
+template void AudioMixer::doAddMix(uint8_t channel, float32_t* in, float32_t* out, uint16_t len)
+{
+ float32_t* tmp=malloc(sizeof(float32_t)*len);
+
+ assert(tmp!=NULL);
+
+ arm_scale_f32(in,multiplier[channel],tmp,len);
+ arm_add_f32(out, tmp, out, len);
+
+ free(tmp);
+}
+
+template void AudioStereoMixer::doAddMix(uint8_t channel, float32_t* in[], float32_t* out[], uint16_t len)
+{
+ float32_t* tmp=malloc(sizeof(float32_t)*len);
+
+ assert(tmp!=NULL);
+
+ // panorama
+ for(uint16_t i=0;i
+
+/* Audio Library for Teensy 3.X
+ * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
+ *
+ * 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.
+ */
+
+#ifndef template_mixer_h_
+#define template_mixer_h_
+
+#include "arm_math.h"
+#include
+
+#define UNITYGAIN 1.0f
+#define MAX_GAIN 1.0f
+#define MIN_GAIN 0.0f
+
+template class AudioMixer
+{
+public:
+ AudioMixer(void)
+ {
+ for (uint8_t i=0; i class AudioStereoMixer : public AudioMixer
+{
+public:
+ AudioStereoMixer(void)
+ {
+ AudioMixer();
+ for (uint8_t i=0; i