Skip to content
Browse files

Fixes

  • Loading branch information...
1 parent 8c008be commit 7f2a09b8d693dd845287790bcd3c17286ef22f8a @stg committed Jun 15, 2012
View
179 arduino-experiments/modplayer/addressed_memory.c
@@ -1,5 +1,5 @@
#include "avr/pgmspace.h"
-
+#include "addressed_memory.h"
/*
This work is published under the Creative Commons BY-NC license available at:
http://creativecommons.org/licenses/by-nc/3.0/
@@ -22,8 +22,8 @@
#include <Math.h>
#endif
-// Intended playback rate
-#define SAMPLE_RATE 48000
+#define ROM_READB( ptr ) pgm_read_byte( ptr )
+#define ROM_READW( ptr ) pgm_read_word( ptr )
// Amiga period range (used for clamping)
#define PERIOD_MIN 54 // 54 is a modern limit, use 113 for full compatibility
@@ -78,7 +78,7 @@ typedef struct {
int8_t mode;
uint8_t volume;
uint8_t tuning;
- size_t length;
+ intptr_t length;
} sample_t;
// Oscillator memory
@@ -111,10 +111,9 @@ typedef struct {
int8_t *pc; // Point C (pb reload @end)
uint8_t active; // Channel is playing
bool loop; // Loop when reached point B
- float rate; // Rate/frequency
+ float rate; // Rate/frequency
uint8_t volume; // Volume
- int8_t *addr; // Current address (fractional)
- float offset;
+ float addr; // Current address (fractional)
} dma_t;
static ptm_t *p_mod;
@@ -165,7 +164,7 @@ static int8_t do_osc( osc_t *p_osc ) {
switch( p_osc->mode & 0x03 ) {
case 0: // Sine
- sample = sine[ ( p_osc->offset ) & 0x3F ];
+ sample = ROM_READB( &sine[ ( p_osc->offset ) & 0x3F ] );
if( sample > 127 ) sample -= 256;
break;
case 1: // Square
@@ -188,25 +187,25 @@ static uint16_t arpeggio( uint8_t ch, uint8_t halftones ) {
uint8_t n, tuning = sample[ fxm[ ch ].sample ].tuning;
// Find base note
for( n = 0; n != 47; n++ ) {
- if( fxm[ ch ].period >= period_tbl[ tuning ][ n ] ) break;
+ if( fxm[ ch ].period >= ROM_READW( &period_tbl[ tuning ][ n ] ) ) break;
}
// Clamp and return arpeggio period
- return period_tbl[ tuning ][ MIN( n + halftones, 47 ) ];
+ return ROM_READW( &period_tbl[ tuning ][ MIN( n + halftones, 47 ) ] );
}
// Calculates and returns glissando period
static uint16_t glissando( uint8_t ch ) {
uint8_t n, tuning = sample[ fxm[ ch ].sample ].tuning;
// Round off to nearest note period
for( n = 0; n != 47; n++ ) {
- if( fxm[ ch ].period < period_tbl[ tuning ][ n ] &&
- fxm[ ch ].period >= period_tbl[ tuning ][ n + 1 ] ) {
- if( period_tbl[ tuning ][ n ] - fxm[ ch ].period > fxm[ ch ].period - period_tbl[ tuning ][ n + 1 ] ) n++;
+ if( fxm[ ch ].period < ROM_READW( &period_tbl[ tuning ][ n ] ) &&
+ fxm[ ch ].period >= ROM_READW( &period_tbl[ tuning ][ n + 1 ] ) ) {
+ if( ROM_READW( &period_tbl[ tuning ][ n ] ) - fxm[ ch ].period > fxm[ ch ].period - ROM_READW( &period_tbl[ tuning ][ n + 1 ] ) ) n++;
break;
}
}
// Clamp and return arpeggio period
- return period_tbl[ tuning ][ n ];
+ return ROM_READW( &period_tbl[ tuning ][ n ] );
}
// Sets up and starts a DMA channel
@@ -216,12 +215,11 @@ static void note_start( dma_t *p_dma, uint8_t ix_sample, uint16_t period, uint8_
p_dma->pb = sample[ ix_sample ].pb;
p_dma->pc = sample[ ix_sample ].pc;
// Set reload register (defines rate)
- p_dma->rate = SYS_FREQ / period_tbl[ sample[ ix_sample ].tuning ][ period ];
+ p_dma->rate = SYS_FREQ / ROM_READW( &period_tbl[ sample[ ix_sample ].tuning ][ period ] );
// Set mode (begin playback)
p_dma->loop = sample[ ix_sample ].loop;
p_dma->active = true;
- p_dma->addr = p_dma->pa;
- p_dma->offset = 0;
+ p_dma->addr = ( float )( intptr_t )p_dma->pa;
// Set loop-point
p_dma->pa = sample[ ix_sample ].pd;
}
@@ -251,7 +249,7 @@ static void play_module() {
if( tick == 0 ) {
if( ++ix_row == 64 ) {
ix_row = 0;
- if( ++ix_order == p_mod->order_count ) ix_order = 0;
+ if( ++ix_order == ROM_READB( &p_mod->order_count ) ) ix_order = 0;
}
// Forced order/row
if( ix_nextorder != 0xFF ) {
@@ -268,7 +266,7 @@ static void play_module() {
// Set up pointers
p_ptn = ( ( uint8_t* )p_mod )
+ sizeof( ptm_t )
- + ( p_mod->order[ ix_order ] << 10 )
+ + ( ROM_READB( &p_mod->order[ ix_order ] ) << 10 )
+ ( ix_row << 4 );
p_fxm = fxm;
@@ -277,27 +275,26 @@ static void play_module() {
for( ch = 0; ch != 4; ch++ ) {
// Deconstruct cell (what the hell were they smoking?)
- temp_b = *p_ptn++; // sample.msb and period.msb
+ temp_b = ROM_READB( p_ptn++ ); // sample.msb and period.msb
temp_w = ( temp_b & 0x0F ) << 8;
ix_sample = temp_b & 0xF0;
- temp_w |= *p_ptn++; // period.lsb
- temp_b = *p_ptn++; // sample.lsb and effect
+ temp_w |= ROM_READB( p_ptn++ ); // period.lsb
+ temp_b = ROM_READB( p_ptn++ ); // sample.lsb and effect
ix_sample |= HI4( temp_b );
fx = LO4( temp_b ) << 4;
- fxp = *p_ptn++; // parameters
+ fxp = ROM_READB( p_ptn++ ); // parameters
if( fx == 0xE0 ) {
fx |= HI4( fxp ); // extended parameters
fxp &= 0x0F;
}
ix_period = 0x7F; // period index
if( temp_w ) {
for( temp_b = 0; temp_b != 36; temp_b++ ) {
- if( period_tbl[ 0 ][ temp_b ] == temp_w ) {
+ if( ROM_READW( &period_tbl[ 0 ][ temp_b ] ) == temp_w ) {
ix_period = temp_b;
break;
}
}
- // if( temp_b == 36 ) wtf();
}
// General effect parameter memory
@@ -331,13 +328,13 @@ static void play_module() {
// Cell has note
if( fx == 0x30 || fx == 0x50 ) {
// Tone-portamento effect setup
- p_fxm->port_target = period_tbl[ sample[ ix_sample ].tuning ][ ix_period ];
+ p_fxm->port_target = ROM_READW( &period_tbl[ sample[ ix_sample ].tuning ][ ix_period ] );
} else {
// Start note
temp_b = p_fxm->sample;
note_start( p_dma, temp_b, ix_period, ( fx == 0x90 ? fxp : 0 ) );
// Set required effect memory parameters
- p_fxm->period = period_tbl[ sample[ temp_b ].tuning ][ ix_period ];
+ p_fxm->period = ROM_READW( &period_tbl[ sample[ temp_b ].tuning ][ ix_period ] );
}
}
@@ -347,7 +344,7 @@ static void play_module() {
if( fxp ) p_fxm->port_speed = fxp;
break;
case 0xB0: // Jump to pattern
- ix_nextorder = ( fxp >= p_mod->order_count ? 0x00 : fxp );
+ ix_nextorder = ( fxp >= ROM_READB( &p_mod->order_count ) ? 0x00 : fxp );
ix_nextrow = 0;
pattern_jump = true;
break;
@@ -357,14 +354,13 @@ static void play_module() {
break;
case 0xD0: // Jump to row
fxp = HI4( fxp ) * 10 + LO4( fxp );
- if( !pattern_jump ) ix_nextorder = ( ( ix_order + 1 ) >= p_mod->order_count ? 0x00 : ix_order + 1 );
+ if( !pattern_jump ) ix_nextorder = ( ( ix_order + 1 ) >= ROM_READB( &p_mod->order_count ) ? 0x00 : ix_order + 1 );
pattern_jump = true;
ix_nextrow = ( fxp > 63 ? 0 : fxp );
break;
case 0xF0: // Set speed
if( fxp > 0x20 ) {
cia = SAMPLE_RATE / ( ( 24 * fxp ) / 60 );
- printf( "%i\n",cia );
} else {
speed = fxp;
}
@@ -487,37 +483,35 @@ void mod_reset() {
delay = 0;
ctr = 0;
cia = SAMPLE_RATE / ( ( 24 * 125 ) / 60 );
- printf( "%i\n", cia );
}
// Loads a module
void mod_load( const void *p_data ) {
uint8_t n;
int8_t *p_audio;
sample_t *p_sample = sample;
- size_t loop_offset, loop_len;
+ intptr_t loop_offset, loop_len;
uint8_t patterns = 0;
-
p_mod = ( ptm_t* )p_data;
// Find pattern count
for( n = 0; n < 128; n++ ) {
- if( p_mod->order[ n ] >= patterns ) patterns = p_mod->order[ n ] + 1;
+ if( ROM_READB( &p_mod->order[ n ] ) >= patterns ) patterns = ROM_READB( &p_mod->order[ n ] ) + 1;
}
// Read samples
memset( sample, 0, sizeof( sample ) );
p_audio = ( ( int8_t* )p_mod ) + sizeof( ptm_t ) + ( patterns << 10 );
for( n = 0; n != 31; n++ ) {
p_sample->pa = p_audio;
- p_sample->length = ( p_mod->sample[ n ].length_msb << 9 )
- | ( p_mod->sample[ n ].length_lsb << 1 );
- p_sample->volume = p_mod->sample[ n ].volume;
- p_sample->tuning = p_mod->sample[ n ].tuning;
- loop_offset = ( p_mod->sample[ n ].loop_offset_msb << 9 )
- | ( p_mod->sample[ n ].loop_offset_lsb << 1 );
- loop_len = ( p_mod->sample[ n ].loop_len_msb << 9 )
- | ( p_mod->sample[ n ].loop_len_lsb << 1 );
+ p_sample->length = ( ROM_READB( &p_mod->sample[ n ].length_msb ) << 9 )
+ | ( ROM_READB( &p_mod->sample[ n ].length_lsb ) << 1 );
+ p_sample->volume = ROM_READB( &p_mod->sample[ n ].volume );
+ p_sample->tuning = ROM_READB( &p_mod->sample[ n ].tuning );
+ loop_offset = ( ROM_READB( &p_mod->sample[ n ].loop_offset_msb ) << 9 )
+ | ( ROM_READB( &p_mod->sample[ n ].loop_offset_lsb ) << 1 );
+ loop_len = ( ROM_READB( &p_mod->sample[ n ].loop_len_msb ) << 9 )
+ | ( ROM_READB( &p_mod->sample[ n ].loop_len_lsb ) << 1 );
p_sample->pb = p_audio + p_sample->length;
p_sample->pd = ( loop_len < 3 ? 0 : loop_offset ) + p_sample->pa;
p_sample->pc = ( loop_len < 3 ? p_sample->pb : p_sample->pd + loop_len );
@@ -528,90 +522,11 @@ void mod_load( const void *p_data ) {
mod_reset();
}
-#ifdef HQ
-// Returns realtime sample data
-int16_t mod_sample() {
- uint8_t ch;
- dma_t *p_dma;
- float lsample, rsample;
- float delta, dsample;
- float lmix = 0, rmix = 0;
- float mmix;
- static float merr = 0;
- int16_t out;
-
- if( ctr-- == 0 ) {
- ctr = cia;
- play_module();
- }
-
- p_dma = dma;
- for( ch = 0; ch != 4; ch++ ) {
- if( p_dma->active ) {
- p_dma->offset += p_dma->rate;
- if( p_dma->addr + ( size_t )p_dma->offset >= p_dma->pb ) {
- if( p_dma->loop ) {
- p_dma->offset += p_dma->pa - p_dma->pb;
- p_dma->pb = p_dma->pc;
- } else {
- p_dma->offset = p_dma->pb - 1 - p_dma->pa;
- p_dma->active = false;
- }
- }
- // Get interpolation samples
- lsample = ( float )*( p_dma->addr + 0 + ( size_t )p_dma->offset );
- if( p_dma->addr + ( size_t )p_dma->offset >= ( p_dma->pb - 1 ) ) {
- rsample = ( float )*( p_dma->addr );
- } else {
- if( p_dma->loop ) {
- rsample = ( float )*( p_dma->addr + 1 + ( size_t )p_dma->offset );
- } else {
- rsample = lsample;
- }
- }
-
- // Interpolate
- delta = p_dma->offset - floor( p_dma->offset );
- dsample = lsample * ( 1.0f - delta ) + ( rsample * delta );
-
- // Apply volume
- dsample *= ( float )p_dma->volume;
-
- // Channel mix
- if( ch == 0 || ch == 3 ) {
- lmix += dsample;
- } else {
- rmix += dsample;
- }
-
- }
-
- p_dma++;
- }
-
- // Mix
- mmix = lmix + rmix;
- out = ( int16_t )round( mmix );
-
- // Apply dithering
- if( ( ( ( float )rand() ) / RAND_MAX ) < abs( merr ) ) {
- if( merr > 0 ) {
- out -= 1;
- } else {
- out += 1;
- }
- }
- merr += ( float )out - mmix;
-
- return out;
-}
-
-#else
int8_t mod_sample() {
uint8_t ch;
dma_t *p_dma;
- int16_t left = 0, right = 0;
+ int16_t mono = 0;
if( ctr-- == 0 ) {
ctr = cia;
@@ -621,27 +536,21 @@ int8_t mod_sample() {
p_dma = dma;
for( ch = 0; ch != 4; ch++ ) {
if( p_dma->active ) {
- p_dma->offset += p_dma->rate;
- if( p_dma->addr + ( size_t )p_dma->offset >= p_dma->pb ) {
+ p_dma->addr += p_dma->rate;
+ if( p_dma->addr >= ( float )( intptr_t )p_dma->pb ) {
if( p_dma->loop ) {
- p_dma->offset += p_dma->pa - p_dma->pb;
+ p_dma->addr -= p_dma->pb - p_dma->pa;
p_dma->pb = p_dma->pc;
} else {
- p_dma->offset = p_dma->pb - 1 - p_dma->pa;
+ p_dma->addr = p_dma->pb - 1 - p_dma->pa;
p_dma->active = false;
}
}
- if( ch == 0 || ch == 3 ) {
- left += *( p_dma->addr + ( size_t )p_dma->offset ) * p_dma->volume;
- } else {
- right += *( p_dma->addr + ( size_t )p_dma->offset ) * p_dma->volume;
- }
-
+ mono += ( ( int8_t )ROM_READB( ( intptr_t )p_dma->addr ) ) * p_dma->volume;
}
-
p_dma++;
}
- return ( left + right ) / 256;
+ return mono / 256;
}
-#endif
+
View
12 arduino-experiments/modplayer/addressed_memory.h
@@ -1,11 +1,13 @@
+#ifdef __cplusplus
extern "C" {
+#endif
#include "stdint.h"
-//#define HQ // High quality sampler (16-bit, interpolation, dithering)
+// Intended playback rate
+#define SAMPLE_RATE 8000
+
void mod_load( const void *p_data );
void mod_reset( void );
-#ifdef HQ
-int16_t mod_sample( void );
-#else
int8_t mod_sample( void );
-#endif
+#ifdef __cplusplus
}
+#endif
View
BIN arduino-experiments/modplayer/agnostic.mod
Binary file not shown.
View
34 arduino-experiments/modplayer/modplayer.ino
@@ -1,15 +1,43 @@
#include "Synth.h"
#include "addressed_memory.h"
-extern uint8_t mod_data[];
+#include <avr/pgmspace.h>
+extern uint8_t PROGMEM mod_data[];
+
+
+//uint8_t pwm=0;
+//uint8_t volatile poo=0;
+
+//uint8_t *mem=(uint8_t*)mod_data;
+
+#define BUFSZ 64
+
+uint8_t buf[ BUFSZ ];
+uint8_t *p_rd = buf, *p_wr = buf;
+int8_t buf_c = 0;
uint8_t sampler() {
- return ( uint8_t )( mod_sample() ^ 0x80 );
+ buf_c--;
+ if( ++p_rd >= &buf[ BUFSZ ] ) p_rd = buf;
+ return *p_rd;
}
void setup() {
mod_load( mod_data );
- Synth.attachInterrupt( sampler, 44100 );
+ Synth.attachInterrupt( sampler, SAMPLE_RATE );
+ Synth.setFilter( 0, FILTER_LP );
+ Synth.setFilter( 1, FILTER_LP );
+ Synth.setMode( 0, 0 );
+ Synth.setMode( 1, 0 );
+ Synth.setResonance( 0, 32 );
+ Synth.setResonance( 1, 32 );
+ Synth.setCutoff( 0, 20000 );
+ Synth.setCutoff( 1, 20000 );
}
void loop() {
+ if( buf_c < BUFSZ ) {
+ buf_c++;
+ *p_wr = mod_sample() ^ 0x80;
+ if( ++p_wr >= &buf[ BUFSZ ] ) p_wr = buf;
+ }
}
View
28 arduino-library/Synth/Synth.cpp
@@ -180,11 +180,7 @@ void Synth_Class::attachInterrupt( uint8_t ( *p_cb )(), uint16_t sample_rate ) {
TIMSK1 = 0;
TIMSK2 = 0;
- // Enable SPI
- SPCR = 0b01010000;
- SPSR = 0b00000001;
-
- // Set up timers (T0, T1) to generate filter clock
+ // Set up timers (T0, T2) to generate filter clock
TCCR0A = 0b01000010;
TCCR0B = 0b00000001;
TCCR2A = 0b00010010;
@@ -199,23 +195,27 @@ void Synth_Class::attachInterrupt( uint8_t ( *p_cb )(), uint16_t sample_rate ) {
OCR1AL = isr_rr & 0xFF;
TIMSK1 = 1 << OCIE1A; // Enable interrupt
+ // Enable SPI
+ SPCR = 0b01010000;
+ SPSR = 0b00000001;
+
+ // Enable serial(MIDI) communication
+ Serial.begin( 31250 );
+
+ // Disable default Arduino Serial.read behaviour
+ UCSR0B &= ~( 1 << RXCIE0 );
+
// Set filter defaults
- setMode( 0, 0 );
- setMode( 1, 0 );
setResonance( 0, 0x14 );
setResonance( 1, 0x14 );
setShift( 0, 0x20 );
setShift( 1, 0x20 );
- setCutoff( 0, 10000 );
+ setCutoff( 0, 200 );
setCutoff( 1, 10000 );
setFilter( 0, FILTER_HP );
setFilter( 1, FILTER_LP );
-
- // Enable serial(MIDI) communication
- Serial.begin( 31250 );
-
- // Disable default Arduino Serial.read behaviour
- UCSR0B &= ~( 1 << RXCIE0 );
+ setMode( 0, 2 );
+ setMode( 1, 0 );
// Enable interrupts
sei();
View
322 arduino-sketches/supersaw_sylt/supersaw_sylt.ino
@@ -3,8 +3,8 @@
#define SAMPLE_FREQ 10000
// Volume and frequency calculations
-#define VOLUME_CALC( CH ) pm[ CH ].volume = ( pm[ CH ].e.value * pm[ CH ].e.velocity ) >> 8
-#define F_CALC( CH ) Synth.setCutoff( CH, ( track[ CH ].rate ? track[ CH ].freq : track[ CH ].base + ( float )( filter[ CH ].value * filter[ CH ].velocity ) ) );
+#define VOLUME_CALC( CH ) pm[ CH ].volume = ( (pm[ CH ].e.value>>8) * pm[ CH ].e.velocity ) >> 8
+#define F_CALC( CH ) Synth.setCutoff( CH, ( track[ CH ].rate ? track[ CH ].freq : track[ CH ].base + ( float )( ( filter[ CH ].value >> 8 ) * filter[ CH ].velocity ) ) );
typedef enum {
STATE_OFF = 0,
@@ -33,7 +33,7 @@ typedef struct {
} pm_t;
typedef struct {
- uint8_t initial;
+ uint8_t retrig;
uint8_t attack;
uint8_t decay;
uint8_t sustain;
@@ -42,7 +42,6 @@ typedef struct {
typedef struct {
uint8_t rate;
- int16_t envelope;
float base;
float freq;
float dest;
@@ -52,38 +51,41 @@ typedef struct {
static float pitch = 1.0;
// Supersaw spread
-static float spread = 0.0;
+static float spread = 100.0;
// Pitch portamento
static float port_freq, port_dest, port_speed = 40.0;
// Envelope shaping parameters for filter 0, 1, volume
-static envcfg_t env[ 3 ] = { { 0xFF, 0xFF, 0x00, 0xFF, 0xFF },
- { 0xFF, 0xFF, 0x00, 0xFF, 0xFF },
- { 0x3F, 0x3F, 0x00, 0x3F, 0xFF } };
+static envcfg_t env[ 3 ] = { { 0, 0x80, 0x00, 0x80, 0x80 },
+ { 0, 0x80, 0x47, 0x05, 0x00 },
+ { 0, 0x80, 0x00, 0x3F, 0x40 } };
// Voices
static uint16_t pfreq[ 4 ][ 4 ];
-static uint16_t ppcm[ 4 ][ 4 ] = { { 0x8000, 0x8000, 0x8000, 0x8000 },
- { 0x8000, 0x8000, 0x8000, 0x8000 },
- { 0x8000, 0x8000, 0x8000, 0x8000 },
- { 0x8000, 0x8000, 0x8000, 0x8000 } };
-static pm_t pm[ 4 ] = { { 0xFF, 0x3F, { 0, 0, STATE_OFF } },
- { 0xFF, 0x3F, { 0, 0, STATE_OFF } },
- { 0xFF, 0x3F, { 0, 0, STATE_OFF } },
- { 0xFF, 0x3F, { 0, 0, STATE_OFF } } };
+static uint16_t ppcm[ 4 ][ 4 ] = { { 0x0000, 0x0000, 0x0000, 0x0000 },
+ { 0x0000, 0x0000, 0x0000, 0x0000 },
+ { 0x0000, 0x0000, 0x0000, 0x0000 },
+ { 0x0000, 0x0000, 0x0000, 0x0000 } };
+static pm_t pm[ 4 ] = { { 0xFF, 0x00, { 0, 0, STATE_OFF } },
+ { 0xFF, 0x00, { 0, 0, STATE_OFF } },
+ { 0xFF, 0x00, { 0, 0, STATE_OFF } },
+ { 0xFF, 0x00, { 0, 0, STATE_OFF } } };
// Envelope state for filter 0, 1
static env_t filter[ 2 ] = { { 0, 0, STATE_OFF },
- { 0, 0, STATE_OFF } };
-static track_t track[ 2 ] = { { 0 },
- { 0 } };
-
+ { 19, 0, STATE_OFF } };
+static track_t track[ 2 ] = { { 0, 156, 156, 156 },
+ { 0, 10000, 10000, 10000 } };
+
// Interrupt counter
static uint16_t int_count = 0;
// Mode
-static uint8_t poly = 0;
+static uint8_t poly = 1;
+
+// Pulse
+static uint8_t pulse = 0;
// Add note to "playlist"
void p_add( uint8_t m, uint8_t v ) {
@@ -92,8 +94,8 @@ void p_add( uint8_t m, uint8_t v ) {
filter[ 1 ].state = STATE_ATTACK;
track[ 0 ].dest = noteTable[ m ];
track[ 1 ].dest = noteTable[ m ];
- filter[ 0 ].value = env[ ENV_F0 ].initial;
- filter[ 1 ].value = env[ ENV_F1 ].initial;
+ filter[ 0 ].value = 0;
+ filter[ 1 ].value = 0;
F_CALC( 0 );
F_CALC( 1 );
// search for already existing instance
@@ -116,21 +118,21 @@ void p_add( uint8_t m, uint8_t v ) {
// insert new note data
pm[ q ].note = m;
pm[ q ].e.velocity = v;
- pm[ q ].e.value = env[ ENV_VOL ].initial;
+ pm[ q ].e.value = 0;
pm[ q ].e.state = STATE_ATTACK;
VOLUME_CALC( q );
pitch_calc( q );
// reset waveform for this channel
- ppcm[ q ][ 0 ] = 0x8000;
- ppcm[ q ][ 1 ] = 0x8000;
- ppcm[ q ][ 2 ] = 0x8000;
- ppcm[ q ][ 3 ] = 0x8000;
+ ppcm[ q ][ 0 ] = 0x0000;
+ ppcm[ q ][ 1 ] = 0x0000;
+ ppcm[ q ][ 2 ] = 0x0000;
+ ppcm[ q ][ 3 ] = 0x0000;
} else {
// insert new note data
if( pm[ 0 ].e.state == STATE_OFF ) {
pm[ 0 ].note = m;
pm[ 0 ].e.velocity = v;
- pm[ 0 ].e.value = env[ ENV_VOL ].initial;
+ pm[ 0 ].e.value = 0;
pm[ 0 ].e.state = STATE_ATTACK;
VOLUME_CALC( 0 );
port_dest = port_freq = noteTable[ m ];
@@ -192,16 +194,15 @@ void p_rem( uint8_t m ) {
pfreq[ 0 ][ 3 ] = 0;
pm[ 0 ].note = 255;
pm[ 0 ].e.state = STATE_OFF;
- ppcm[ 0 ][ 0 ] = 0x8000;
- ppcm[ 0 ][ 1 ] = 0x8000;
- ppcm[ 0 ][ 2 ] = 0x8000;
- ppcm[ 0 ][ 3 ] = 0x8000;
+ ppcm[ 0 ][ 0 ] = 0x0000;
+ ppcm[ 0 ][ 1 ] = 0x0000;
+ ppcm[ 0 ][ 2 ] = 0x0000;
+ ppcm[ 0 ][ 3 ] = 0x0000;
}
}
}
-byte ooo;
-
+/*
uint8_t sample( void ) {
register int16_t vout; // voice out
register int16_t aout; // accumulated out
@@ -257,6 +258,102 @@ uint8_t sample( void ) {
// scale and convert to unsigned
return ( ( uint8_t )( aout >> 1 ) ) ^ 0x80;
}
+*/
+
+uint8_t sample( void ) {
+ register int16_t vout; // voice out
+ register int16_t aout; // accumulated out
+ if( pulse==0 ) {
+ // update voice 0
+ vout = -512;
+ ppcm[ 0 ][ 0 ] += pfreq[ 0 ][ 0 ];
+ vout += static_cast<uint8_t>( ppcm[ 0 ][ 0 ] >> 8 );
+ ppcm[ 0 ][ 1 ] += pfreq[ 0 ][ 1 ];
+ vout += static_cast<uint8_t>( ppcm[ 0 ][ 1 ] >> 8 );
+ ppcm[ 0 ][ 2 ] += pfreq[ 0 ][ 2 ];
+ vout += static_cast<uint8_t>( ppcm[ 0 ][ 2 ] >> 8 );
+ ppcm[ 0 ][ 3 ] += pfreq[ 0 ][ 3 ];
+ vout += static_cast<uint8_t>( ppcm[ 0 ][ 3 ] >> 8 );
+ aout = ( vout * pm[ 0 ].volume ) >> 8;
+ // update voice 1
+ vout = -512;
+ ppcm[ 1 ][ 0 ] += pfreq[ 1 ][ 0 ];
+ vout += static_cast<uint8_t>( ppcm[ 1 ][ 0 ] >> 8 );
+ ppcm[ 1 ][ 1 ] += pfreq[ 1 ][ 1 ];
+ vout += static_cast<uint8_t>( ppcm[ 1 ][ 1 ] >> 8 );
+ ppcm[ 1 ][ 2 ] += pfreq[ 1 ][ 2 ];
+ vout += static_cast<uint8_t>( ppcm[ 1 ][ 2 ] >> 8 );
+ ppcm[ 1 ][ 3 ] += pfreq[ 1 ][ 3 ];
+ vout += static_cast<uint8_t>( ppcm[ 1 ][ 3 ] >> 8 );
+ aout += ( vout * pm[ 1 ].volume ) >> 8;
+ // update voice 2
+ vout = -512;
+ ppcm[ 2 ][ 0 ] += pfreq[ 2 ][ 0 ];
+ vout += static_cast<uint8_t>( ppcm[ 2 ][ 0 ] >> 8 );
+ ppcm[ 2 ][ 1 ] += pfreq[ 2 ][ 1 ];
+ vout += static_cast<uint8_t>( ppcm[ 2 ][ 1 ] >> 8 );
+ ppcm[ 2 ][ 2 ] += pfreq[ 2 ][ 2 ];
+ vout += static_cast<uint8_t>( ppcm[ 2 ][ 2 ] >> 8 );
+ ppcm[ 2 ][ 3 ] += pfreq[ 2 ][ 3 ];
+ vout += static_cast<uint8_t>( ppcm[ 2 ][ 3 ] >> 8 );
+ aout += ( vout * pm[ 2 ].volume ) >> 8;
+ // update voice 3
+ vout = -512;
+ ppcm[ 3 ][ 0 ] += pfreq[ 3 ][ 0 ];
+ vout += static_cast<uint8_t>( ppcm[ 3 ][ 0 ] >> 8 );
+ ppcm[ 3 ][ 1 ] += pfreq[ 3 ][ 1 ];
+ vout += static_cast<uint8_t>( ppcm[ 3 ][ 1 ] >> 8 );
+ ppcm[ 3 ][ 2 ] += pfreq[ 3 ][ 2 ];
+ vout += static_cast<uint8_t>( ppcm[ 3 ][ 2 ] >> 8 );
+ ppcm[ 3 ][ 3 ] += pfreq[ 3 ][ 3 ];
+ vout += static_cast<uint8_t>( ppcm[ 3 ][ 3 ] >> 8 );
+ aout += ( vout * pm[ 3 ].volume ) >> 8;
+ } else {
+ // update voice 0
+ vout = -384;
+ ppcm[ 0 ][ 0 ] += pfreq[ 0 ][ 0 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 0 ][ 0 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ ppcm[ 0 ][ 1 ] += pfreq[ 0 ][ 1 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 0 ][ 1 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ ppcm[ 0 ][ 2 ] += pfreq[ 0 ][ 2 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 0 ][ 2 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ aout = ( vout * pm[ 0 ].volume ) >> 8;
+ // update voice 1
+ vout = -384;
+ ppcm[ 1 ][ 0 ] += pfreq[ 1 ][ 0 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 1 ][ 0 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ ppcm[ 1 ][ 1 ] += pfreq[ 1 ][ 1 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 1 ][ 1 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ ppcm[ 1 ][ 2 ] += pfreq[ 1 ][ 2 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 1 ][ 2 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ aout += ( vout * pm[ 1 ].volume ) >> 8;
+ // update voice 2
+ vout = -384;
+ ppcm[ 2 ][ 0 ] += pfreq[ 2 ][ 0 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 2 ][ 0 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ ppcm[ 2 ][ 1 ] += pfreq[ 2 ][ 1 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 2 ][ 1 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ ppcm[ 2 ][ 2 ] += pfreq[ 2 ][ 2 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 2 ][ 2 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ aout += ( vout * pm[ 2 ].volume ) >> 8;
+ // update voice 3
+ vout = -384;
+ ppcm[ 3 ][ 0 ] += pfreq[ 3 ][ 0 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 3 ][ 0 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ ppcm[ 3 ][ 1 ] += pfreq[ 3 ][ 1 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 3 ][ 1 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ ppcm[ 3 ][ 2 ] += pfreq[ 3 ][ 2 ];
+ vout += ( static_cast<uint8_t>( ppcm[ 3 ][ 2 ] >> 8 ) > pulse ? 0x40 : 0xC0 );
+ aout += ( vout * pm[ 3 ].volume ) >> 8;
+ }
+ // limit
+ if( aout > 255 ) aout = 255;
+ else if( aout < -256 ) aout = -256;
+ // count (used by envelope shaping)
+ int_count++;
+ // scale and convert to unsigned
+ return ( ( uint8_t )( aout >> 1 ) ) ^ 0x80;
+}
// Sets/updates frequency for one polyphony channel
void pitch_calc( uint8_t ch ) {
@@ -325,7 +422,6 @@ void loop( void ) {
break;
case 10: // F0 center frequency
- //OCR2A = ( 255 - midi->data2 ) << 1;
track[ 0 ].base = 20000.0 / ( float )( ( 128 - midi->data2 ) );
F_CALC( 0 );
break;
@@ -335,15 +431,36 @@ void loop( void ) {
case 12: // F0 center frequency shift
Synth.setShift( 0, ( 255 - midi->data2 ) >> 1 );
break;
- case 13: // F0 mode
- Synth.setMode( 0, midi->data2 >> 5 );
- break;
- case 14: // F0 type
- Synth.setFilter( 0, ( midi->data2 < 43 ? FILTER_LP : ( midi->data2 < 86 ? FILTER_BP : FILTER_HP ) ) );
+ case 13: // F0 style
+ switch( midi->data2 / 22 ) {
+ case 0: // low-pass
+ Synth.setFilter( 0, FILTER_LP );
+ Synth.setMode( 0, 0 );
+ break;
+ case 1: // fat low-pass
+ Synth.setFilter( 0, FILTER_LP );
+ Synth.setMode( 0, 3 );
+ break;
+ case 2: // band-pass
+ Synth.setFilter( 0, FILTER_BP );
+ Synth.setMode( 0, 0 );
+ break;
+ case 3: // fat band-pass
+ Synth.setFilter( 0, FILTER_BP );
+ Synth.setMode( 0, 3 );
+ break;
+ case 4: // high-pass
+ Synth.setFilter( 0, FILTER_HP );
+ Synth.setMode( 0, 2 );
+ break;
+ case 5: // phaser
+ Synth.setFilter( 0, FILTER_HP );
+ Synth.setMode( 0, 0 );
+ break;
+ }
break;
-
+
case 15: // F1 center frequency
- //OCR0A = ( 255 - midi->data2 ) << 1;
track[ 1 ].base = 20000.0 / ( float )( ( 128 - midi->data2 ) );
F_CALC( 1 );
break;
@@ -353,78 +470,103 @@ void loop( void ) {
case 17: // F1 center frequency shift
Synth.setShift( 1, ( 255 - midi->data2 ) >> 1 );
break;
- case 18: // F1 mode
- Synth.setMode( 1, midi->data2 >> 5 );
- break;
- case 19: // F1 type
- Synth.setFilter( 1, ( midi->data2 < 43 ? FILTER_LP : ( midi->data2 < 86 ? FILTER_BP : FILTER_HP ) ) );
+ case 18: // F1 style
+ switch( midi->data2 / 22 ) {
+ case 0: // low-pass
+ Synth.setFilter( 1, FILTER_LP );
+ Synth.setMode( 1, 0 );
+ break;
+ case 1: // fat low-pass
+ Synth.setFilter( 1, FILTER_LP );
+ Synth.setMode( 1, 3 );
+ break;
+ case 2: // band-pass
+ Synth.setFilter( 1, FILTER_BP );
+ Synth.setMode( 1, 0 );
+ break;
+ case 3: // fat band-pass
+ Synth.setFilter( 1, FILTER_BP );
+ Synth.setMode( 1, 3 );
+ break;
+ case 4: // high-pass
+ Synth.setFilter( 1, FILTER_HP );
+ Synth.setMode( 1, 2 );
+ break;
+ case 5: // phaser
+ Synth.setFilter( 1, FILTER_HP );
+ Synth.setMode( 1, 0 );
+ break;
+ }
break;
-
+
case 20: // Pitch portamento speed
- port_speed = midi->data2;
+ port_speed = 127-midi->data2;
break;
- case 21: // Volume envelope initial level
- env[ ENV_VOL ].initial = midi->data2 >> 1;
+ case 21: // Volume envelope retriggering
+ env[ ENV_VOL].retrig = midi->data2 >> 6;
break;
case 22: // Volume envelope attack rate
- env[ ENV_VOL ].attack = midi->data2;
+ env[ ENV_VOL ].attack = 128 - midi->data2;
break;
case 23: // Volume envelope decay rate
- env[ ENV_VOL ].decay = midi->data2;
+ env[ ENV_VOL ].decay = 128 - midi->data2;
break;
case 24: // Volume envelope sustain level
env[ ENV_VOL ].sustain = midi->data2 >> 1;
break;
- case 25: // Volume envelope decay rate
- env[ ENV_VOL ].release = midi->data2;
+ case 25: // Volume envelope release rate
+ env[ ENV_VOL ].release = 128 - midi->data2;
break;
+ case 28: // Pulse mode
+ pulse = midi->data2;
+ break;
case 29: // Mode (mono/poly)
poly = midi->data2 >> 6;
break;
case 30: // F0 tracking (0 off/envelope, 1-127 slow-immediate)
track[ 0 ].rate = midi->data2;
break;
- case 31: // F0 envelope initial level
- env[ ENV_F0 ].initial = midi->data2 >> 1;
+ case 31: // F0 envelope retriggering
+ env[ ENV_F0 ].retrig = midi->data2 >> 6;
break;
case 32: // F0 envelope attack rate
- env[ ENV_F0 ].attack = midi->data2;
+ env[ ENV_F0 ].attack = 128 - midi->data2;
break;
case 33: // F0 envelope decay rate
- env[ ENV_F0 ].decay = midi->data2;
+ env[ ENV_F0 ].decay = 128 - midi->data2;
break;
case 34: // F0 envelope sustain level
env[ ENV_F0 ].sustain = midi->data2 >> 1;
break;
case 35: // F0 envelope release rate
- env[ ENV_F0 ].release = midi->data2;
+ env[ ENV_F0 ].release = 128 - midi->data2;
break;
case 36: // F0 envelope velocity
- filter[ 0 ].velocity = ( ( int8_t )midi->data2 << 1 ) - 128;
+ filter[ 0 ].velocity = midi->data2 << 1;
break;
case 40: // F1 tracking (0 off/envelope, 1-127 slow-immediate)
track[ 1 ].rate = midi->data2;
break;
- case 41: // F1 envelope initial level
- env[ ENV_F1 ].initial = midi->data2 >> 1;
+ case 41: // F1 envelope retriggering
+ env[ ENV_F1 ].retrig = midi->data2 >> 6;
break;
case 42: // F1 envelope attack rate
- env[ ENV_F1 ].attack = midi->data2;
+ env[ ENV_F1 ].attack = 128 - midi->data2;
break;
case 43: // F1 envelope decay rate
- env[ ENV_F1 ].decay = midi->data2;
+ env[ ENV_F1 ].decay = 128 - midi->data2;
break;
case 44: // F1 envelope sustain level
env[ ENV_F1 ].sustain = midi->data2 >> 1;
break;
case 45: // F1 envelope release rate
- env[ ENV_F1 ].release = midi->data2;
+ env[ ENV_F1 ].release = 128 - midi->data2;
break;
case 46: // F1 envelope velocity
- filter[ 1 ].velocity = ( ( int8_t )midi->data2 << 1 ) - 128;
+ filter[ 1 ].velocity = midi->data2 << 1;
break;
}
@@ -433,10 +575,10 @@ void loop( void ) {
Synth.freeMidi();
}
- // run once for every 1/50 second
- while( int_count > ( SAMPLE_FREQ / 50 ) ) {
+ // run once for every 1/64 second
+ while( int_count > ( SAMPLE_FREQ / 32 ) ) {
cli();
- int_count -= ( SAMPLE_FREQ / 50 );
+ int_count -= ( SAMPLE_FREQ / 32 );
sei();
if( poly == 0 && pm[ 0 ].e.state != STATE_OFF ) {
@@ -454,24 +596,24 @@ void loop( void ) {
for( n = 0; n != 4; n++ ) {
switch( pm[ n ].e.state ) {
case STATE_ATTACK:
- pm[ n ].e.value += env[ ENV_VOL ].attack;
- if( pm[ n ].e.value >= 0x003F ) {
- pm[ n ].e.value = 0x003F;
+ pm[ n ].e.value += env[ ENV_VOL ].attack << 6;
+ if( pm[ n ].e.value >= 0x3F00 || env[ ENV_VOL ].attack == 0x80 ) {
+ pm[ n ].e.value = 0x3F00;
pm[ n ].e.state = STATE_DECAY;
}
VOLUME_CALC( n );
break;
case STATE_DECAY:
- pm[ n ].e.value -= env[ ENV_VOL ].decay;
- if( pm[ n ].e.value <= env[ ENV_VOL ].sustain ) {
- pm[ n ].e.value = env[ ENV_VOL ].sustain;
- pm[ n ].e.state = STATE_SUSTAIN;
+ pm[ n ].e.value -= env[ ENV_VOL ].decay << 6;
+ if( pm[ n ].e.value <= ( env[ ENV_VOL ].sustain << 8 ) || env[ ENV_VOL ].decay == 0x80 ) {
+ pm[ n ].e.value = (env[ ENV_VOL ].sustain<<8);
+ pm[ n ].e.state = env[ ENV_VOL ].retrig ? STATE_ATTACK : STATE_SUSTAIN;
}
VOLUME_CALC( n );
break;
case STATE_RELEASE:
- pm[ n ].e.value -= env[ ENV_VOL ].release;
- if( pm[ n ].e.value <= 0x0000 ) {
+ pm[ n ].e.value -= env[ ENV_VOL ].release << 6;
+ if( pm[ n ].e.value <= 0x0000 || env[ ENV_VOL ].release == 0x80 ) {
pm[ n ].e.value = 0x0000;
p_rem( pm[ n ].note );
}
@@ -487,26 +629,26 @@ void loop( void ) {
} else {
switch( filter[ n ].state ) {
case STATE_ATTACK:
- filter[ n ].value += env[ n ].attack;
- if( filter[ n ].value >= 0x003F ) {
- filter[ n ].value = 0x003F;
+ filter[ n ].value += env[ n ].attack << 6;
+ if( filter[ n ].value >= 0x3F00 || env[ n ].attack == 0x80 ) {
+ filter[ n ].value = 0x3F00;
filter[ n ].state = STATE_DECAY;
}
F_CALC( n );
break;
case STATE_DECAY:
- filter[ n ].value -= env[ n ].decay;
- if( filter[ n ].value <= env[ n ].sustain ) {
- filter[ n ].value = env[ n ].sustain;
- filter[ n ].state = STATE_SUSTAIN;
+ filter[ n ].value -= env[ n ].decay << 6;
+ if( filter[ n ].value <= ( env[ n ].sustain << 8 ) || env[ n ].decay == 0x80 ) {
+ filter[ n ].value = env[ n ].sustain << 8;
+ filter[ n ].state = env[ n ].retrig ? STATE_ATTACK : STATE_SUSTAIN;
}
F_CALC( n );
break;
case STATE_RELEASE:
- filter[ n ].value -= env[ n ].release;
- if( filter[ n ].value <= 0x0000 ) {
+ filter[ n ].value -= env[ n ].release << 6;
+ if( filter[ n ].value <= 0x0000 || env[ ENV_VOL ].release == 0x80 ) {
filter[ n ].value = 0x0000;
- p_rem( pm[ n ].note );
+ filter[ n ].state = STATE_OFF;
}
F_CALC( n );
break;

0 comments on commit 7f2a09b

Please sign in to comment.
Something went wrong with that request. Please try again.