Skip to content

Commit

Permalink
Mostly just cleanup work. Added ModuleWaveshaper, but I have my doubt…
Browse files Browse the repository at this point in the history
…s that it is working correctly. I'll be reaserhing this more later.
  • Loading branch information
clone45 committed Jul 29, 2014
1 parent 2046607 commit 7f74b50
Show file tree
Hide file tree
Showing 14 changed files with 320 additions and 34 deletions.
2 changes: 1 addition & 1 deletion EquationBank.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class EquationBank
{
public:

EquationBank(); // Constructor
EquationBank();
virtual uint32_t compute(int equation_number, uint32_t t, uint32_t p1, uint32_t p2, uint32_t p3) = 0;

FixedPointMath fixed_point_math;
Expand Down
11 changes: 6 additions & 5 deletions EquationComposer.ino
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ Equation testing tools:
Note: When using any bytebeat tool, make sure to set the output rate to 22,050
TODO:
- research/confirm synthdrumplayer BPM accuracy
- update website - revise tutorials on updating equations
- update website - convert synth input/output labeling to text
- document SynthWavetableBitFolder
- document ModuleSamplePlayer
- document SynthDrumPlayer
- update code documentation for ModuleExtClock
- create ModuleClockMultiplier
- add a lot more arpeggiations
- pitch shifter using ring buffer (?)
- research chiptune / game sound generation code
Programming notes:
- Do _not_ put a delay() immediately before polling the analog inputs as it can
Expand Down Expand Up @@ -96,12 +97,12 @@ Programming notes:
#include "SynthWavetableBitFolder.h"
#include "SynthWavetableDelay.h"

#include "SynthTutorial16.h"

// DueTimer is a Due library for handling interrupts
#include "DueTimer.h"


// Global variables

// Create an inputs object, which contains a bunch of input modules and serves
// as a convienient wrapper class.
Inputs *inputs = new Inputs();
Expand All @@ -124,13 +125,13 @@ Synth *active_synths[] {
new SynthEquationPlayer(inputs, equation_bank_khepri),
new SynthEquationPlayer(inputs, equation_bank_ptah),
new SynthEquationPlayer(inputs, equation_bank_sobek),

new SynthDrumSelektor(inputs),
new SynthWavetableBitFolder(inputs),
new SynthPatterns(inputs),
new SynthChords(inputs),
new Synth3Osc(inputs),
new SynthDrumPlayer(inputs)
// new SynthTutorial16(inputs)
};


Expand Down
89 changes: 89 additions & 0 deletions GlobalWaveshaperTables.cpp

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions GlobalWaveshaperTables.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef WaveshaperTables_h
#define WaveshaperTables_h

extern const uint8_t WAVE_SHAPER_TABLES[][4096];

#endif
35 changes: 20 additions & 15 deletions ModuleExtClock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,41 @@
#include "ModuleExtClock.h"
#include "defines.h"

ModuleExtClock::ModuleExtClock(uint32_t bpm, int clock_division)
ModuleExtClock::ModuleExtClock(uint8_t bpm, uint16_t clock_division)
{
// 'counter' is used for timing the internal clock
this->counter = 0;

// 'ext_clocked' records the status (on or off) of the external clock input
this->ext_clocked = 0;
this->ext_clocked = false;

// 'ext_clock_count' help determine which clock mode to use: internal or external
this->ext_clock_counter = 176400;
// Default to internal. This counter is incremented whenever there is NO external
// clock detected. Once this counter reaches a certain level, it's assumed that
// there is no external clock, and the internal clock is used.
this->ext_clock_counter = 88400;

// 'bpm' the beats per minute of the internal clock
this->bpm = constrain(bpm, 0, 254);
this->bpm = min(bpm, 254);

for(uint16_t bpm_i=0; bpm_i < 255; bpm_i++)
for(uint8_t bpm_i=0; bpm_i < 255; bpm_i++)
{
bpm_ppqn[bpm_i] = ((float)(60.0 * SAMPLE_RATE_FLOAT * clock_division)/((float)bpm_i * 96.0));
bpm_half_ppqn[bpm_i] = bpm_ppqn[bpm_i] / 2;
bpm_half_ppqn[bpm_i] = bpm_ppqn[bpm_i] >> 2;
}
}

ModuleExtClock::ModuleExtClock(uint32_t bpm)
ModuleExtClock::ModuleExtClock(uint8_t bpm)
{
this->counter = 0;
this->ext_clocked = 0;
this->ext_clock_counter = 176400;
this->bpm = constrain(bpm, 0, 254);
this->ext_clocked = false;
this->ext_clock_counter = 88400;
this->bpm = min(bpm, 254);

for(uint16_t bpm_i=0; bpm_i < 255; bpm_i++)
for(uint8_t bpm_i=0; bpm_i < 255; bpm_i++)
{
bpm_ppqn[bpm_i] = ((float)(60.0 * SAMPLE_RATE_FLOAT)/((float)bpm_i * 96.0));
bpm_half_ppqn[bpm_i] = bpm_ppqn[bpm_i] / 2;
bpm_half_ppqn[bpm_i] = bpm_ppqn[bpm_i] >> 1; // divide by 2
}
}

Expand All @@ -47,7 +50,9 @@ uint16_t ModuleExtClock::compute()
// reset the ext_clock_counter

uint32_t clock_input_value = this->readInput(clock_input);

if((clock_input_value < MID_CV) && ext_clocked) ext_clocked = false;

if((clock_input_value >= MID_CV) && !ext_clocked)
{
ext_clocked = true;
Expand All @@ -56,12 +61,12 @@ uint16_t ModuleExtClock::compute()


// If 4 seconds have passed, then switch back to the internal
// clock generator. 176400 is 4 x 44100, which is our interrupt rate
if(ext_clock_counter >= 176400)
// clock generator. 88400 is 4 x 22,100, which is our interrupt rate
if(ext_clock_counter >= 88400)
{

// Avoid overflow of ext_clock_counter
ext_clock_counter = 176400;
ext_clock_counter = 88400;

// If we're at the end of the clock duty,
// then reset the counter back to 0 and return 0
Expand Down
10 changes: 5 additions & 5 deletions ModuleExtClock.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@
class ModuleExtClock : public Module
{
public:
ModuleExtClock(uint32_t bpm);
ModuleExtClock(uint32_t bpm, int clock_division);
ModuleExtClock(uint8_t bpm);
ModuleExtClock(uint8_t bpm, uint16_t clock_division);
uint16_t compute();

// Inputs
Expand All @@ -64,11 +64,11 @@ class ModuleExtClock : public Module
private:
uint32_t rate;
uint32_t counter;
uint32_t bpm;
uint8_t bpm;
uint16_t bpm_ppqn[255];
uint16_t bpm_half_ppqn[255];
uint32_t ext_clocked;
uint32_t ext_clock_counter;
boolean ext_clocked;
uint32_t ext_clock_counter = 88400;
};

#endif
71 changes: 71 additions & 0 deletions ModuleSamplePlayer.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,74 @@
/*
* +------------------------+
* | ModuleSamplePLayer |
* |------------------------|
* > sample_selection_input |
* > trigger_input |
* > sample_rate_input |
* | output >
* +------------------------+
*
*/
// =============================================================================
//
// ModuleSamplePLayer is an audio sample playback module. All of the samples
// available are currently drum sounds. There is no external memory for the
// equation composer, so it can hold very few samples.
//
// Samples are defined in Samples.cpp.
//
// Example usage:
//
// ModuleDrumSequencer *drum_sequencer = new ModuleDrumSequencer();
// ModuleSamplePlayer *kick = new ModuleSamplePlayer();
// ModuleSamplePlayer *snare = new ModuleSamplePlayer();
// ModuleSamplePlayer *hihat = new ModuleSamplePlayer();
// ModuleKitSelect *kit_select = new ModuleKitSelect();
// ModuleMixer3 *mixer = new ModuleMixer3();
// ModuleWaveFolder *wave_folder = new ModuleWaveFolder();
// ModuleExtClock *ext_clock = new ModuleExtClock(120, EIGHTH_NOTE_CLOCK_DIVISION);
//
// // Use the external clock when available, otherwise
// // default to the internal 120BPM clock
// ext_clock->clock_input = inputs->gate;
//
// drum_sequencer->clock_input = ext_clock;
//
// // Use the 3 parameters to select the patterns
// // used for the drums.
// drum_sequencer->kick_pattern_input = inputs->param1;
// drum_sequencer->snare_pattern_input = inputs->param2;
// drum_sequencer->hihat_pattern_input = inputs->param3;
//
// // Use the mode input to select the drum kit
// kit_select->kit_selection_input = inputs->mod;
//
// // Set the kick, snare, and hihat inputs
// kick->trigger_input = drum_sequencer->kick_output;
// kick->sample_rate_input = inputs->sr;
// kick->sample_selection_input = kit_select->kick_output;
//
// snare->trigger_input = drum_sequencer->snare_output;
// snare->sample_rate_input = inputs->sr;
// snare->sample_selection_input = kit_select->snare_output;
//
// hihat->trigger_input = drum_sequencer->hihat_output;;
// hihat->sample_rate_input = inputs->sr;
// hihat->sample_selection_input = kit_select->hihat_output;
//
// // Mix everything together
// mixer->input_1 = kick;
// mixer->input_2 = snare;
// mixer->input_3 = hihat;
//
// // Apply some wave folding, just to make things exciting
// wave_folder->audio_input = mixer;
// wave_folder->lower_clipping_level_input = new ModuleConstant(1492);
// wave_folder->upper_clipping_level_input = new ModuleConstant(2604);
//
// this->last_module = wave_folder;
//

#ifndef ModuleSamplePlayer_h
#define ModuleSamplePlayer_h

Expand Down
34 changes: 34 additions & 0 deletions ModuleWaveshaper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

#include "defines.h"
#include "ModuleWaveshaper.h"
#include "GlobalWaveshaperTables.h"

ModuleWaveshaper::ModuleWaveshaper()
{
// Initialize all inputs
this->audio_input = NULL;
this->mix_input = NULL;
this->waveshaper_input = NULL;
}

uint16_t ModuleWaveshaper::compute()
{
// Read inputs
uint16_t audio = this->readInput(audio_input);
uint16_t waveshaper = this->readInput(waveshaper_input,0,4);
uint16_t wet_mix = this->readInput(mix_input);

uint16_t dry_mix = 4095 - wet_mix;

uint16_t shaped_output = WAVE_SHAPER_TABLES[waveshaper][audio];

if(wet_mix == 0)
{
return(audio);
}
else
{
return(((shaped_output * wet_mix) >> 12) + ((audio * dry_mix) >> 12));
}
}

35 changes: 35 additions & 0 deletions ModuleWaveshaper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* +----------------------+
* | ModuleWaveshaper |
* |----------------------|
* > audio_input |
* | |
* | output >
* +----------------------+
!!!!!!! This module doesn't work at all yet !!!!!!!!!!!!!!!
*/


#ifndef ModuleWaveshaper_h
#define ModuleWaveshaper_h

#include "Module.h"

class ModuleWaveshaper : public Module
{

public:

// Methods
ModuleWaveshaper();
uint16_t compute();

// Inputs
Module *audio_input;
Module *mix_input;
Module *waveshaper_input;
};

#endif
3 changes: 2 additions & 1 deletion Modules.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@
#include "ModuleSwitch.h"
#include "ModuleVCA.h"
#include "ModuleWaveFolder.h"
#include "ModuleWavetableOsc.h"
#include "ModuleWavetableOsc.h"
#include "ModuleWaveshaper.h"
16 changes: 16 additions & 0 deletions SynthTutorial16.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "SynthTutorial16.h"

SynthTutorial16::SynthTutorial16(Inputs* inputs)
{
ModuleWavetableOsc *wavetable_osc = new ModuleWavetableOsc();
ModuleWaveshaper *wave_shaper = new ModuleWaveshaper();

wavetable_osc->wavetable_input = inputs->mod;
wavetable_osc->frequency_input = inputs->sr;

wave_shaper->audio_input = wavetable_osc;
wave_shaper->mix_input = inputs->param1;
wave_shaper->waveshaper_input = inputs->param2;

this->last_module = wave_shaper;
}
28 changes: 28 additions & 0 deletions SynthTutorial16.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// =============================================================================
//
// Name: SynthTutorial16
// Written by: Bret Truchan, 2014
//
// Description: Demonstration of ModuleWaveShaper
//
// SR - Sample rate input
// MOD - Wavetable selection
// [1] - Wet/Dry mix for waveshaper
// [2] - not used
// [3] - not used
// GATE - not used
//
// =============================================================================

#ifndef SynthTutorial16_h
#define SynthTutorial16_h

#include "Synth.h"

class SynthTutorial16 : public Synth
{
public:
SynthTutorial16(Inputs *inputs);
};

#endif
9 changes: 5 additions & 4 deletions SynthWavetableBitFolder.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
// Type: Audio
// Written by: Bret Truchan, 2014
//
// Description: A wavetable oscillator put through a short audio delay.
// Description: A wavetable oscillator routed through a lowpass filter,
// followed by a wave folder.
//
// SR - Sample rate of the wavetable oscillator
// MOD - Wavetable selection
// [1] - Bit reduction
// [2] - Wave folding level
// [3] - Lowpass filter cutoff
// [1] - Wave folding level
// [2] - Lowpass filter cutoff
// [3] - Lowpass filter resonance
// GATE - not used
//
// =============================================================================
Expand Down
Loading

0 comments on commit 7f74b50

Please sign in to comment.