Removed compressor from AudioEffectDynamics library because of wasting CPU time and it seems to be buggy on T_3.6.
Tested all CPU clock modes on T_3.6. Limited T_3.6 to single engine.pull/46/head
parent
75901c90d6
commit
60ac8c6b02
@ -1,34 +0,0 @@ |
|||||||
# Prerequisites |
|
||||||
*.d |
|
||||||
|
|
||||||
# Compiled Object files |
|
||||||
*.slo |
|
||||||
*.lo |
|
||||||
*.o |
|
||||||
*.obj |
|
||||||
|
|
||||||
# Precompiled Headers |
|
||||||
*.gch |
|
||||||
*.pch |
|
||||||
|
|
||||||
# Compiled Dynamic libraries |
|
||||||
*.so |
|
||||||
*.dylib |
|
||||||
*.dll |
|
||||||
|
|
||||||
# Fortran module files |
|
||||||
*.mod |
|
||||||
*.smod |
|
||||||
|
|
||||||
# Compiled Static libraries |
|
||||||
*.lai |
|
||||||
*.la |
|
||||||
*.a |
|
||||||
*.lib |
|
||||||
|
|
||||||
# Executables |
|
||||||
*.exe |
|
||||||
*.out |
|
||||||
*.app |
|
||||||
|
|
||||||
cmake-build-debug |
|
@ -1,7 +0,0 @@ |
|||||||
# AudioEffectDynamics |
|
||||||
Dynamics Processor (Gate, Compressor & Limiter) for the Teensy Audio Library |
|
||||||
|
|
||||||
# my version of [MarkzP/AudioEffectDynamics](https://github.com/MarkzP/AudioEffectDynamics) |
|
||||||
* removes theoretical divide by zero when rms == 0 (sqrt_uint32(0) will divide by zero, thou it doesnt seem to cause any issues) |
|
||||||
* uses running rms calculation and applies gain per sample instead of rms calculation per audio block and applying a constant gain to entire audio buffer |
|
||||||
* adds some build stuff |
|
@ -1,155 +0,0 @@ |
|||||||
/* Audio Library for Teensy 3.X
|
|
||||||
* Dynamics Processor (Gate, Compressor & Limiter) |
|
||||||
* Copyright (c) 2017, Marc Paquette (marc@dacsystemes.com) |
|
||||||
* Based on analyse_rms & mixer objects by Paul Stoffregen |
|
||||||
* |
|
||||||
* 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 "effect_dynamics.h" |
|
||||||
#include "fast_log.h" |
|
||||||
#include "utility/dspinst.h" |
|
||||||
#include "utility/sqrt_integer.h" |
|
||||||
|
|
||||||
static float analyse_rms(int16_t *data) { |
|
||||||
|
|
||||||
uint32_t *p = (uint32_t *)data; |
|
||||||
const uint32_t *end = p + AUDIO_BLOCK_SAMPLES / 2; |
|
||||||
int64_t sum = 0; |
|
||||||
do { |
|
||||||
uint32_t n1 = *p++; |
|
||||||
uint32_t n2 = *p++; |
|
||||||
uint32_t n3 = *p++; |
|
||||||
uint32_t n4 = *p++; |
|
||||||
sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n1, n1); |
|
||||||
sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n2, n2); |
|
||||||
sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n3, n3); |
|
||||||
sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n4, n4); |
|
||||||
|
|
||||||
} while (p < end); |
|
||||||
if (sum == 0) return 0; |
|
||||||
int32_t meansq = sum / AUDIO_BLOCK_SAMPLES; |
|
||||||
return sqrt_uint32(meansq) / 32767.0f; |
|
||||||
} |
|
||||||
|
|
||||||
static void applyGain(int16_t *data, int32_t mult1, int32_t mult2) { |
|
||||||
|
|
||||||
uint32_t *p = (uint32_t *)data; |
|
||||||
const uint32_t *end = p + AUDIO_BLOCK_SAMPLES / 2; |
|
||||||
int32_t inc = (mult2 - mult1) / (AUDIO_BLOCK_SAMPLES / 2); |
|
||||||
|
|
||||||
do { |
|
||||||
uint32_t tmp32 = *p; // read 2 samples from *data
|
|
||||||
int32_t val1 = signed_multiply_32x16b(mult1, tmp32); |
|
||||||
mult1 += inc; |
|
||||||
int32_t val2 = signed_multiply_32x16t(mult1, tmp32); |
|
||||||
mult1 += inc; |
|
||||||
val1 = signed_saturate_rshift(val1, 16, 0); |
|
||||||
val2 = signed_saturate_rshift(val2, 16, 0); |
|
||||||
*p++ = pack_16b_16b(val2, val1); |
|
||||||
} while (p < end); |
|
||||||
} |
|
||||||
|
|
||||||
void AudioEffectDynamics::update(void) { |
|
||||||
|
|
||||||
audio_block_t *block; |
|
||||||
|
|
||||||
block = receiveWritable(0); |
|
||||||
|
|
||||||
if (!block) return; |
|
||||||
|
|
||||||
if (!gateEnabled && !compEnabled && !limiterEnabled) { |
|
||||||
|
|
||||||
//Transmit & release
|
|
||||||
transmit(block); |
|
||||||
release(block); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
for (int i=0; i<AUDIO_BLOCK_SAMPLES; i++) { |
|
||||||
|
|
||||||
unsigned int sampleIndexPlus1 = (sampleIndex + 1) % sampleBufferSize; |
|
||||||
|
|
||||||
uint32_t sampleToRemove = samplesSquared[sampleIndexPlus1]; |
|
||||||
sumOfSamplesSquared -= (sampleToRemove * sampleToRemove); |
|
||||||
|
|
||||||
int16_t sample = block->data[i]; |
|
||||||
samplesSquared[sampleIndex] = abs(sample); |
|
||||||
uint32_t sampleSquared = sample * sample; |
|
||||||
sumOfSamplesSquared += sampleSquared; |
|
||||||
|
|
||||||
sampleIndex = (sampleIndex + 1) % sampleBufferSize; |
|
||||||
|
|
||||||
float rms = sqrt(sumOfSamplesSquared / float(sampleBufferSize)) / 32768.0; |
|
||||||
|
|
||||||
//Compute block RMS level in Db
|
|
||||||
float inputdb = MIN_DB; |
|
||||||
if (rms > 0) inputdb = unitToDb(rms); |
|
||||||
|
|
||||||
//Gate
|
|
||||||
if (gateEnabled) { |
|
||||||
if (inputdb >= gateThresholdOpen) gatedb = (aGateAttack * gatedb) + (aOneMinusGateAttack * MAX_DB); |
|
||||||
else if (inputdb < gateThresholdClose) gatedb = (aGateRelease * gatedb) + (aOneMinusGateRelease * MIN_DB); |
|
||||||
} else gatedb = MAX_DB; |
|
||||||
|
|
||||||
//Compressor
|
|
||||||
if (compEnabled) { |
|
||||||
float attdb = MAX_DB; //Below knee
|
|
||||||
if (inputdb >= aLowKnee) { |
|
||||||
if (inputdb <= aHighKnee) { |
|
||||||
//Knee transition
|
|
||||||
float knee = inputdb - aLowKnee; |
|
||||||
attdb = aKneeRatio * knee * knee * aTwoKneeWidth; |
|
||||||
} else { |
|
||||||
//Above knee
|
|
||||||
attdb = compThreshold + ((inputdb - compThreshold) * compRatio) - inputdb; |
|
||||||
} |
|
||||||
} |
|
||||||
if (attdb <= compdb) compdb = (aCompAttack * compdb) + (aOneMinusCompAttack * attdb); |
|
||||||
else compdb = (aCompRelease * compdb) + (aOneMinusCompRelease * attdb); |
|
||||||
} else compdb = MAX_DB; |
|
||||||
|
|
||||||
//Brickwall Limiter
|
|
||||||
if (limiterEnabled) { |
|
||||||
float outdb = inputdb + compdb + makeupdb; |
|
||||||
if (outdb >= limitThreshold) limitdb = (aLimitAttack * limitdb) + |
|
||||||
(aOneMinusLimitAttack * (limitThreshold - outdb)); |
|
||||||
else limitdb *= aLimitRelease; |
|
||||||
} else limitdb = MAX_DB; |
|
||||||
|
|
||||||
//Compute linear gain
|
|
||||||
float totalGain = gatedb + compdb + makeupdb + limitdb; |
|
||||||
|
|
||||||
float multiplier = dbToUnit(totalGain); |
|
||||||
int16_t result = sample * multiplier; |
|
||||||
block->data[i] = result; |
|
||||||
//Apply gain to block
|
|
||||||
} |
|
||||||
|
|
||||||
//Transmit & release
|
|
||||||
transmit(block); |
|
||||||
release(block); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,196 +0,0 @@ |
|||||||
/* Audio Library for Teensy 3.X
|
|
||||||
* Dynamics Processor (Gate, Compressor & Limiter) |
|
||||||
* Copyright (c) 2018, Marc Paquette (marc@dacsystemes.com) |
|
||||||
* Based on analyse_rms, effect_envelope & mixer objects by Paul Stoffregen |
|
||||||
* |
|
||||||
* 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 effect_dynamics_h_ |
|
||||||
#define effect_dynamics_h_ |
|
||||||
|
|
||||||
#include "Arduino.h" |
|
||||||
#include "AudioStream.h" |
|
||||||
|
|
||||||
#define MIN_DB -110.0f |
|
||||||
#define MAX_DB 0.0f |
|
||||||
|
|
||||||
#define MIN_T 0.03f //Roughly 1 block
|
|
||||||
#define MAX_T 4.00f |
|
||||||
|
|
||||||
#define RATIO_OFF 1.0f |
|
||||||
#define RATIO_INFINITY 60.0f |
|
||||||
|
|
||||||
class AudioEffectDynamics : public AudioStream |
|
||||||
{ |
|
||||||
public: |
|
||||||
AudioEffectDynamics(void) : AudioStream(1, inputQueueArray) { |
|
||||||
|
|
||||||
gate(); |
|
||||||
compression(); |
|
||||||
limit(); |
|
||||||
autoMakeupGain(); |
|
||||||
|
|
||||||
gatedb = MIN_DB; |
|
||||||
compdb = MIN_DB; |
|
||||||
limitdb = MIN_DB; |
|
||||||
} |
|
||||||
|
|
||||||
//Sets the gate parameters.
|
|
||||||
//threshold is in dbFS
|
|
||||||
//attack & release are in seconds
|
|
||||||
void gate(float threshold = -50.0f, float attack = MIN_T, float release = 0.3f, float hysterisis = 6.0f) { |
|
||||||
|
|
||||||
gateEnabled = threshold > MIN_DB; |
|
||||||
|
|
||||||
gateThresholdOpen = constrain(threshold, MIN_DB, MAX_DB); |
|
||||||
gateThresholdClose = gateThresholdOpen - constrain(hysterisis, 0.0f, 6.0f); |
|
||||||
|
|
||||||
float gateAttackTime = constrain(attack, MIN_T, MAX_T); |
|
||||||
float gateReleaseTime = constrain(release, MIN_T, MAX_T); |
|
||||||
|
|
||||||
aGateAttack = timeToAlpha(gateAttackTime); |
|
||||||
aOneMinusGateAttack = 1.0f - aGateAttack; |
|
||||||
aGateRelease = timeToAlpha(gateReleaseTime); |
|
||||||
aOneMinusGateRelease = 1.0f - aGateRelease; |
|
||||||
} |
|
||||||
|
|
||||||
//Sets the compression parameters.
|
|
||||||
//threshold & kneeWidth are in db(FS)
|
|
||||||
//attack and release are in seconds
|
|
||||||
//ratio is expressed as x:1 i.e. 1 for no compression, 60 for brickwall limiting
|
|
||||||
//Set kneeWidth to 0 for hard knee
|
|
||||||
void compression(float threshold = -40.0f, float attack = MIN_T, float release = 0.5f, float ratio = 35.0f, float kneeWidth = 6.0f) { |
|
||||||
|
|
||||||
compEnabled = threshold < MAX_DB; |
|
||||||
|
|
||||||
compThreshold = constrain(threshold, MIN_DB, MAX_DB); |
|
||||||
float compAttackTime = constrain(attack, MIN_T, MAX_T); |
|
||||||
float compReleaseTime = constrain(release, MIN_T, MAX_T); |
|
||||||
compRatio = 1.0f / constrain(abs(ratio), RATIO_OFF, RATIO_INFINITY); |
|
||||||
float compKneeWidth = constrain(abs(kneeWidth), 0.0f, 32.0f); |
|
||||||
computeMakeupGain(); |
|
||||||
|
|
||||||
aCompAttack = timeToAlpha(compAttackTime); |
|
||||||
aOneMinusCompAttack = 1.0f - aCompAttack; |
|
||||||
aCompRelease = timeToAlpha(compReleaseTime); |
|
||||||
aOneMinusCompRelease = 1.0f - aCompRelease; |
|
||||||
aHalfKneeWidth = compKneeWidth / 2.0f; |
|
||||||
aTwoKneeWidth = 1.0f / (compKneeWidth * 2.0f); |
|
||||||
aKneeRatio = compRatio - 1.0f; |
|
||||||
aLowKnee = compThreshold - aHalfKneeWidth; |
|
||||||
aHighKnee = compThreshold + aHalfKneeWidth; |
|
||||||
} |
|
||||||
|
|
||||||
//Sets the hard limiter parameters
|
|
||||||
//threshold is in dbFS
|
|
||||||
//attack & release are in seconds
|
|
||||||
void limit(float threshold = -3.0f, float attack = MIN_T, float release = MIN_T) { |
|
||||||
|
|
||||||
limiterEnabled = threshold < MAX_DB; |
|
||||||
|
|
||||||
limitThreshold = constrain(threshold, MIN_DB, MAX_DB); |
|
||||||
float limitAttackTime = constrain(attack, MIN_T, MAX_T); |
|
||||||
float limitReleaseTime = constrain(release, MIN_T, MAX_T);
|
|
||||||
|
|
||||||
computeMakeupGain(); |
|
||||||
|
|
||||||
aLimitAttack = timeToAlpha(limitAttackTime); |
|
||||||
aOneMinusLimitAttack = 1.0f - aLimitAttack; |
|
||||||
aLimitRelease = timeToAlpha(limitReleaseTime); |
|
||||||
} |
|
||||||
|
|
||||||
//Enables automatic makeup gain setting
|
|
||||||
//headroom is in dbFS
|
|
||||||
void autoMakeupGain(float headroom = 6.0f) { |
|
||||||
|
|
||||||
mgAutoEnabled = true; |
|
||||||
mgHeadroom = constrain(headroom, 0.0f, 60.0f); |
|
||||||
computeMakeupGain(); |
|
||||||
} |
|
||||||
|
|
||||||
//Sets a fixed makeup gain value.
|
|
||||||
//gain is in dbFS
|
|
||||||
void makeupGain(float gain = 0.0f) { |
|
||||||
|
|
||||||
mgAutoEnabled = false; |
|
||||||
makeupdb = constrain(gain, -12.0f, 24.0f); |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
audio_block_t *inputQueueArray[1]; |
|
||||||
|
|
||||||
bool gateEnabled = false; |
|
||||||
float gateThresholdOpen; |
|
||||||
float gateThresholdClose; |
|
||||||
float gatedb; |
|
||||||
|
|
||||||
bool compEnabled = false; |
|
||||||
float compThreshold; |
|
||||||
float compRatio; |
|
||||||
float compdb; |
|
||||||
|
|
||||||
bool limiterEnabled = false; |
|
||||||
float limitThreshold; |
|
||||||
float limitdb; |
|
||||||
|
|
||||||
bool mgAutoEnabled; |
|
||||||
float mgHeadroom; |
|
||||||
float makeupdb; |
|
||||||
|
|
||||||
float aGateAttack; |
|
||||||
float aOneMinusGateAttack; |
|
||||||
float aGateRelease; |
|
||||||
float aOneMinusGateRelease; |
|
||||||
float aHalfKneeWidth; |
|
||||||
float aTwoKneeWidth; |
|
||||||
float aKneeRatio; |
|
||||||
float aLowKnee; |
|
||||||
float aHighKnee; |
|
||||||
float aCompAttack; |
|
||||||
float aOneMinusCompAttack; |
|
||||||
float aCompRelease; |
|
||||||
float aOneMinusCompRelease; |
|
||||||
float aLimitAttack; |
|
||||||
float aOneMinusLimitAttack; |
|
||||||
float aLimitRelease; |
|
||||||
const static unsigned int sampleBufferSize = 4410; |
|
||||||
u_int64_t sumOfSamplesSquared = 0; |
|
||||||
uint32_t samplesSquared[sampleBufferSize] = {0}; |
|
||||||
uint16_t sampleIndex = 0; |
|
||||||
|
|
||||||
void computeMakeupGain() { |
|
||||||
if (mgAutoEnabled) { |
|
||||||
makeupdb = -compThreshold + (compThreshold * compRatio) + limitThreshold - mgHeadroom; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
//Computes smoothing time constants for a 10% to 90% change
|
|
||||||
float timeToAlpha(float time) { |
|
||||||
return expf(-0.9542f / (((float)AUDIO_SAMPLE_RATE_EXACT / (float)AUDIO_BLOCK_SAMPLES) * time)); |
|
||||||
} |
|
||||||
|
|
||||||
virtual void update(void); |
|
||||||
}; |
|
||||||
|
|
||||||
#endif |
|
@ -1,50 +0,0 @@ |
|||||||
/* ----------------------------------------------------------------------
|
|
||||||
* https://community.arm.com/tools/f/discussions/4292/cmsis-dsp-new-functionality-proposal/22621#22621
|
|
||||||
* Fast approximation to the log2() function. It uses a two step |
|
||||||
* process. First, it decomposes the floating-point number into |
|
||||||
* a fractional component F and an exponent E. The fraction component |
|
||||||
* is used in a polynomial approximation and then the exponent added |
|
||||||
* to the result. A 3rd order polynomial is used and the result |
|
||||||
* when computing db20() is accurate to 7.984884e-003 dB. |
|
||||||
** ------------------------------------------------------------------- */ |
|
||||||
|
|
||||||
float log2f_approx_coeff[4] = {1.23149591368684f, -4.11852516267426f, 6.02197014179219f, -3.13396450166353f}; |
|
||||||
|
|
||||||
float log2f_approx(float X) |
|
||||||
{ |
|
||||||
float *C = &log2f_approx_coeff[0]; |
|
||||||
float Y; |
|
||||||
float F; |
|
||||||
int E; |
|
||||||
|
|
||||||
// This is the approximation to log2()
|
|
||||||
F = frexpf(fabsf(X), &E); |
|
||||||
|
|
||||||
// Y = C[0]*F*F*F + C[1]*F*F + C[2]*F + C[3] + E;
|
|
||||||
Y = *C++; |
|
||||||
Y *= F; |
|
||||||
Y += (*C++); |
|
||||||
Y *= F; |
|
||||||
Y += (*C++); |
|
||||||
Y *= F; |
|
||||||
Y += (*C++); |
|
||||||
Y += E; |
|
||||||
return(Y); |
|
||||||
} |
|
||||||
|
|
||||||
// https://codingforspeed.com/using-faster-exponential-approximation/
|
|
||||||
inline float expf_approx(float x) { |
|
||||||
x = 1.0f + x / 1024; |
|
||||||
x *= x; x *= x; x *= x; x *= x; |
|
||||||
x *= x; x *= x; x *= x; x *= x; |
|
||||||
x *= x; x *= x; |
|
||||||
return x; |
|
||||||
} |
|
||||||
|
|
||||||
inline float unitToDb(float unit) { |
|
||||||
return 6.02f * log2f_approx(unit); |
|
||||||
} |
|
||||||
|
|
||||||
inline float dbToUnit(float db) { |
|
||||||
return expf_approx(db * 2.302585092994046f * 0.05f); |
|
||||||
} |
|
@ -1,65 +0,0 @@ |
|||||||
#include <Audio.h> |
|
||||||
#include "synth_dexed.h" |
|
||||||
#include "banks.h" |
|
||||||
|
|
||||||
AudioSynthDexed dexed(4, SAMPLE_RATE); // 4 voices max
|
|
||||||
AudioOutputI2S i2s1; |
|
||||||
AudioControlSGTL5000 sgtl5000_1; |
|
||||||
AudioConnection patchCord1(dexed, 0, i2s1, 0); |
|
||||||
AudioConnection patchCord2(dexed, 0, i2s1, 1); |
|
||||||
|
|
||||||
void setup() |
|
||||||
{ |
|
||||||
Serial.begin(230400); |
|
||||||
|
|
||||||
AudioMemory(32); |
|
||||||
|
|
||||||
sgtl5000_1.enable(); |
|
||||||
sgtl5000_1.lineOutLevel(29); |
|
||||||
sgtl5000_1.dacVolumeRamp(); |
|
||||||
sgtl5000_1.dacVolume(1.0); |
|
||||||
sgtl5000_1.unmuteHeadphone(); |
|
||||||
sgtl5000_1.unmuteLineout(); |
|
||||||
sgtl5000_1.volume(0.8, 0.8); // Headphone volume
|
|
||||||
|
|
||||||
randomSeed(analogRead(0)); |
|
||||||
} |
|
||||||
|
|
||||||
void loop() |
|
||||||
{ |
|
||||||
uint8_t b = random(0, 10); |
|
||||||
uint8_t v = random(0, 32); |
|
||||||
uint8_t t = random(0, 36); |
|
||||||
char voice_name[11]; |
|
||||||
uint8_t decoded_voice[156]; |
|
||||||
|
|
||||||
memset(voice_name, 0, 11); |
|
||||||
memcpy(voice_name, &progmem_bank[b][v][117], 10); |
|
||||||
|
|
||||||
Serial.print("Voice: "); |
|
||||||
Serial.print(voice_name); |
|
||||||
Serial.print(" "); |
|
||||||
Serial.print("Transpose: "); |
|
||||||
Serial.println(t); |
|
||||||
|
|
||||||
dexed.decodeVoice(progmem_bank[b][v],decoded_voice);
|
|
||||||
dexed.loadVoiceParameters(decoded_voice); |
|
||||||
dexed.setTranspose(t); |
|
||||||
|
|
||||||
Serial.println("Key-Down"); |
|
||||||
dexed.keydown(48, 100); |
|
||||||
delay(100); |
|
||||||
dexed.keydown(52, 100); |
|
||||||
delay(100); |
|
||||||
dexed.keydown(55, 100); |
|
||||||
delay(100); |
|
||||||
dexed.keydown(60, 100); |
|
||||||
delay(2000); |
|
||||||
|
|
||||||
Serial.println("Key-Up"); |
|
||||||
dexed.keyup(48); |
|
||||||
dexed.keyup(52); |
|
||||||
dexed.keyup(55); |
|
||||||
dexed.keyup(60); |
|
||||||
delay(1000); |
|
||||||
} |
|
File diff suppressed because it is too large
Load Diff
@ -1,151 +0,0 @@ |
|||||||
#!/usr/bin/python3 |
|
||||||
|
|
||||||
import sys |
|
||||||
import os.path |
|
||||||
|
|
||||||
# From: https://github.com/bwhitman/learnfm/blob/master/dx7db.py |
|
||||||
def unpack_packed_patch(p): |
|
||||||
# Input is a 128 byte thing from compact.bin |
|
||||||
# Output is a 156 byte thing that the synth knows about |
|
||||||
o = [0]*156 |
|
||||||
for op in range(6): |
|
||||||
o[op*21:op*21 + 11] = p[op*17:op*17+11] |
|
||||||
leftrightcurves = p[op*17+11] |
|
||||||
o[op * 21 + 11] = leftrightcurves & 3 |
|
||||||
o[op * 21 + 12] = (leftrightcurves >> 2) & 3 |
|
||||||
detune_rs = p[op * 17 + 12] |
|
||||||
o[op * 21 + 13] = detune_rs & 7 |
|
||||||
o[op * 21 + 20] = detune_rs >> 3 |
|
||||||
kvs_ams = p[op * 17 + 13] |
|
||||||
o[op * 21 + 14] = kvs_ams & 3 |
|
||||||
o[op * 21 + 15] = kvs_ams >> 2 |
|
||||||
o[op * 21 + 16] = p[op * 17 + 14] |
|
||||||
fcoarse_mode = p[op * 17 + 15] |
|
||||||
o[op * 21 + 17] = fcoarse_mode & 1 |
|
||||||
o[op * 21 + 18] = fcoarse_mode >> 1 |
|
||||||
o[op * 21 + 19] = p[op * 17 + 16] |
|
||||||
|
|
||||||
o[126:126+9] = p[102:102+9] |
|
||||||
oks_fb = p[111] |
|
||||||
o[135] = oks_fb & 7 |
|
||||||
o[136] = oks_fb >> 3 |
|
||||||
o[137:137+4] = p[112:112+4] |
|
||||||
lpms_lfw_lks = p[116] |
|
||||||
o[141] = lpms_lfw_lks & 1 |
|
||||||
o[142] = (lpms_lfw_lks >> 1) & 7 |
|
||||||
o[143] = lpms_lfw_lks >> 4 |
|
||||||
o[144:144+11] = p[117:117+11] |
|
||||||
o[155] = 0x3f |
|
||||||
|
|
||||||
# Clamp the unpacked patches to a known max. |
|
||||||
maxes = [ |
|
||||||
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc6 |
|
||||||
3, 3, 7, 3, 7, 99, 1, 31, 99, 14, |
|
||||||
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc5 |
|
||||||
3, 3, 7, 3, 7, 99, 1, 31, 99, 14, |
|
||||||
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc4 |
|
||||||
3, 3, 7, 3, 7, 99, 1, 31, 99, 14, |
|
||||||
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc3 |
|
||||||
3, 3, 7, 3, 7, 99, 1, 31, 99, 14, |
|
||||||
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc2 |
|
||||||
3, 3, 7, 3, 7, 99, 1, 31, 99, 14, |
|
||||||
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, # osc1 |
|
||||||
3, 3, 7, 3, 7, 99, 1, 31, 99, 14, |
|
||||||
99, 99, 99, 99, 99, 99, 99, 99, # pitch eg rate & level |
|
||||||
31, 7, 1, 99, 99, 99, 99, 1, 5, 7, 48, # algorithm etc |
|
||||||
126, 126, 126, 126, 126, 126, 126, 126, 126, 126, # name |
|
||||||
127 # operator on/off |
|
||||||
] |
|
||||||
for i in range(156): |
|
||||||
if(o[i] > maxes[i]): o[i] = maxes[i] |
|
||||||
if(o[i] < 0): o[i] = 0 |
|
||||||
return o |
|
||||||
|
|
||||||
def print_header_data(voice_data): |
|
||||||
print("\t\t\t",end="") |
|
||||||
for y in range(0,len(voice_data)): |
|
||||||
if(y!=len(voice_data)-1): |
|
||||||
print("%3d, " % voice_data[y],end="") |
|
||||||
else: |
|
||||||
print("%3d\n" % voice_data[y],end="") |
|
||||||
if((y+1)%8==0 and y!=len(voice_data)-1): |
|
||||||
print("\n\t\t\t",end="") |
|
||||||
|
|
||||||
def help_message(): |
|
||||||
print(progname+" [--decode] <sysex1> [<sysex2> ... <sysexn>]") |
|
||||||
|
|
||||||
#--------------------------------------------------------------------------- |
|
||||||
|
|
||||||
progname=sys.argv.pop(0) |
|
||||||
if(len(sys.argv)==0): |
|
||||||
help_message() |
|
||||||
exit(1) |
|
||||||
if(sys.argv[0]=="-h" or sys.argv[0]=="--help"): |
|
||||||
help_message() |
|
||||||
exit(1) |
|
||||||
if(sys.argv[0]=="--decode"): |
|
||||||
decode=True |
|
||||||
sys.argv.pop(0) |
|
||||||
else: |
|
||||||
decode=False |
|
||||||
|
|
||||||
print(""" |
|
||||||
// |
|
||||||
// File generated with sysex2c.py |
|
||||||
// |
|
||||||
|
|
||||||
#pragma once |
|
||||||
""") |
|
||||||
if(decode==True): |
|
||||||
print("uint8_t progmem_bank[%d][32][156] PROGMEM =\n{" % int(len(sys.argv))) |
|
||||||
else: |
|
||||||
print("uint8_t progmem_bank[%d][32][128] PROGMEM =\n{" % int(len(sys.argv))) |
|
||||||
for sysex in sys.argv: |
|
||||||
if(not os.path.isfile(sysex)): |
|
||||||
print("* File "+sysex+" does not exists.") |
|
||||||
exit(10) |
|
||||||
if(not os.access(sysex,os.R_OK)): |
|
||||||
print("* File "+sysex+" does not readable.") |
|
||||||
exit(11) |
|
||||||
print("\t{\t// %s" % os.path.basename(sysex)) |
|
||||||
with open(sysex, "rb") as f: |
|
||||||
header = f.read(6) |
|
||||||
if(header[0]!=240): |
|
||||||
print("* %s: Start of sysex not found." % sysex) |
|
||||||
exit(200) |
|
||||||
if(header[1]!=67): |
|
||||||
print("* %s: Manufactorer-ID not Yamaha." % sysex) |
|
||||||
exit(201) |
|
||||||
if(header[3]!=9): |
|
||||||
print("* %s: Not a 32 voice sysex file." % sysex) |
|
||||||
exit(202) |
|
||||||
byte_count = header[4]*128+header[5] |
|
||||||
if(byte_count!=4096): |
|
||||||
print("* %s: Byte count mismatch." % sysex) |
|
||||||
exit(203) |
|
||||||
patch_data=f.read(4096) |
|
||||||
check = ~sum(patch_data) + 1 & 0x7F |
|
||||||
f.seek(4102) # Bulk checksum |
|
||||||
checksum=int.from_bytes(f.read(1),"little") |
|
||||||
if(check!=checksum): |
|
||||||
print("* %s: Checksum mismatch!" % sysex) |
|
||||||
exit(204) |
|
||||||
f.seek(6) |
|
||||||
|
|
||||||
for v in range(1,33): |
|
||||||
data=f.read(128) |
|
||||||
patchname=str(data[118:128].decode('ascii')).upper().replace('\\','') |
|
||||||
print("\t\t{\t// %d: %s" % (v, patchname)) |
|
||||||
if(decode==True): |
|
||||||
print_header_data(unpack_packed_patch(data)) |
|
||||||
else: |
|
||||||
print_header_data(data) |
|
||||||
if(v!=32): |
|
||||||
print("\t\t},") |
|
||||||
else: |
|
||||||
print("\t\t}") |
|
||||||
if(sys.argv[len(sys.argv)-1]==sysex): |
|
||||||
print("\t}") |
|
||||||
else: |
|
||||||
print("\t},") |
|
||||||
print("};") |
|
Loading…
Reference in new issue