cog/Frameworks/midi_processing/midi_processing/midi_processor_lds.cpp

1050 lines
36 KiB
C++

#include "midi_processor.h"
#include <string.h>
const uint8_t midi_processor::lds_default_tempo[5] = { 0xFF, 0x51, 0x07, 0xA1, 0x20 };
#define ENABLE_WHEEL
//#define ENABLE_VIB
//#define ENABLE_ARP
//#define ENABLE_TREM
#ifdef ENABLE_WHEEL
#define WHEEL_RANGE_HIGH 12
#define WHEEL_RANGE_LOW 0
#define WHEEL_SCALE(x) ((x) * 512 / WHEEL_RANGE_HIGH)
#define WHEEL_SCALE_LOW(x) (WHEEL_SCALE(x) & 127)
#define WHEEL_SCALE_HIGH(x) (((WHEEL_SCALE(x) >> 7) + 64) & 127)
#endif
#ifdef ENABLE_VIB
// Vibrato (sine) table
static const unsigned char vibtab[] = {
0, 13, 25, 37, 50, 62, 74, 86, 98, 109, 120, 131, 142, 152, 162,
171, 180, 189, 197, 205, 212, 219, 225, 231, 236, 240, 244, 247,
250, 252, 254, 255, 255, 255, 254, 252, 250, 247, 244, 240, 236,
231, 225, 219, 212, 205, 197, 189, 180, 171, 162, 152, 142, 131,
120, 109, 98, 86, 74, 62, 50, 37, 25, 13
};
#endif
#ifdef ENABLE_TREM
// Tremolo (sine * sine) table
static const unsigned char tremtab[] = {
0, 0, 1, 1, 2, 4, 5, 7, 10, 12, 15, 18, 21, 25, 29, 33, 37, 42, 47,
52, 57, 62, 67, 73, 79, 85, 90, 97, 103, 109, 115, 121, 128, 134,
140, 146, 152, 158, 165, 170, 176, 182, 188, 193, 198, 203, 208,
213, 218, 222, 226, 230, 234, 237, 240, 243, 245, 248, 250, 251,
253, 254, 254, 255, 255, 255, 254, 254, 253, 251, 250, 248, 245,
243, 240, 237, 234, 230, 226, 222, 218, 213, 208, 203, 198, 193,
188, 182, 176, 170, 165, 158, 152, 146, 140, 134, 127, 121, 115,
109, 103, 97, 90, 85, 79, 73, 67, 62, 57, 52, 47, 42, 37, 33, 29,
25, 21, 18, 15, 12, 10, 7, 5, 4, 2, 1, 1, 0
};
#endif
bool midi_processor::is_lds( std::vector<uint8_t> const& p_file, const char * p_extension )
{
if ( strcasecmp( p_extension, "LDS" ) ) return false;
if ( p_file.size() < 1 ) return false;
if ( p_file[ 0 ] > 2 ) return false;
return true;
}
struct sound_patch
{
// skip 11 bytes worth of Adlib crap
uint8_t keyoff;
#ifdef ENABLE_WHEEL
uint8_t portamento;
int8_t glide;
#endif
// skip 1 byte
#ifdef ENABLE_VIB
uint8_t vibrato;
uint8_t vibrato_delay;
#endif
#ifdef ENABLE_TREM
uint8_t modulator_tremolo;
uint8_t carrier_tremolo;
uint8_t tremolo_delay;
#endif
#ifdef ENABLE_ARP
uint8_t arpeggio;
int8_t arpeggio_table[12];
#endif
// skip 4 bytes worth of digital instrument crap
// skip 3 more bytes worth of Adlib crap that isn't even used
uint8_t midi_instrument;
uint8_t midi_velocity;
uint8_t midi_key;
int8_t midi_transpose;
// skip 2 bytes worth of MIDI dummy fields or whatever
};
struct channel_state {
#ifdef ENABLE_WHEEL
int16_t gototune, lasttune;
#endif
uint16_t packpos;
int8_t finetune;
#ifdef ENABLE_WHEEL
uint8_t glideto, portspeed;
#endif
uint8_t nextvol, volmod, volcar,
keycount, packwait;
#ifdef ENABLE_VIB
uint8_t vibwait, vibspeed, vibrate, vibcount;
#endif
#ifdef ENABLE_TREM
uint8_t trmstay, trmwait, trmspeed, trmrate, trmcount,
trcwait, trcspeed, trcrate, trccount;
#endif
#ifdef ENABLE_ARP
uint8_t arp_count, arp_size, arp_speed, arp_pos;
int8_t arp_tab[12];
#endif
struct {
uint8_t chandelay, sound;
uint16_t high;
} chancheat;
};
void playsound( uint8_t current_instrument[], std::vector<sound_patch> const& patches, uint8_t last_note[], uint8_t last_channel[], uint8_t last_instrument[], uint8_t last_volume[], uint8_t last_sent_volume[],
#ifdef ENABLE_WHEEL
int16_t last_pitch_wheel[],
#endif
channel_state * c, uint8_t allvolume, unsigned current_timestamp, unsigned sound, unsigned chan, unsigned high, midi_track & track )
{
uint8_t buffer[ 2 ];
current_instrument[ chan ] = sound;
if ( sound >= patches.size() ) return;
const sound_patch & patch = patches[ current_instrument[ chan ] ];
unsigned channel = ( patch.midi_instrument >= 0x80 ) ? 9 : ( chan == 9 ) ? 10 : chan;
unsigned saved_last_note = last_note[ chan ];
unsigned note;
if ( channel != 9 )
{
// set fine tune
high += c->finetune;
// arpeggio handling
#ifdef ENABLE_ARP
if(patch.arpeggio)
{
short arpcalc = patch.arpeggio_table[0] << 4;
high += arpcalc;
}
#endif
// and MIDI transpose
high = (int)high + ( patch.midi_transpose << 4 );
note = high
#ifdef ENABLE_WHEEL
- c->lasttune
#endif
;
// glide handling
#ifdef ENABLE_WHEEL
if(c->glideto != 0)
{
c->gototune = note - ( last_note[ chan ] << 4 ) + c->lasttune;
c->portspeed = c->glideto;
c->glideto = c->finetune = 0;
return;
}
#endif
if ( patch.midi_instrument != last_instrument[ chan ] )
{
buffer[ 0 ] = patch.midi_instrument;
track.add_event( midi_event( current_timestamp, midi_event::program_change, channel, buffer, 1 ) );
last_instrument[ chan ] = patch.midi_instrument;
}
}
else
{
note = ( patch.midi_instrument & 0x7F ) << 4;
}
unsigned volume = 127;
if ( c->nextvol )
{
volume = ( c->nextvol & 0x3F ) * 127 / 63;
last_volume[ chan ] = volume;
}
if ( allvolume )
{
volume = volume * allvolume / 255;
}
if ( volume != last_sent_volume[ channel ] )
{
buffer[ 0 ] = 7;
buffer[ 1 ] = volume;
track.add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ chan ], buffer, 2 ) );
last_sent_volume[ channel ] = volume;
}
if ( saved_last_note != 0xFF )
{
buffer[ 0 ] = saved_last_note;
buffer[ 1 ] = 127;
track.add_event( midi_event( current_timestamp, midi_event::note_off, last_channel[ chan ], buffer, 2 ) );
last_note[ chan ] = 0xFF;
#ifdef ENABLE_WHEEL
if ( channel != 9 )
{
note += c->lasttune;
c->lasttune = 0;
if ( last_pitch_wheel[ channel ] != 0 )
{
buffer[ 0 ] = 0;
buffer[ 1 ] = 64;
track.add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) );
last_pitch_wheel[ channel ] = 0;
}
}
#endif
}
#ifdef ENABLE_WHEEL
if ( c->lasttune != last_pitch_wheel[ channel ] )
{
buffer[ 0 ] = WHEEL_SCALE_LOW( c->lasttune );
buffer[ 1 ] = WHEEL_SCALE_HIGH( c->lasttune );
track.add_event( midi_event( current_timestamp, midi_event::pitch_wheel, channel, buffer, 2 ) );
last_pitch_wheel[ channel ] = c->lasttune;
}
if( !patch.glide || last_note[ chan ] == 0xFF )
#endif
{
#ifdef ENABLE_WHEEL
if( !patch.portamento || last_note[ chan ] == 0xFF )
#endif
{
buffer[ 0 ] = note >> 4;
buffer[ 1 ] = patch.midi_velocity;
track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) );
last_note[ chan ] = note >> 4;
last_channel[ chan ] = channel;
#ifdef ENABLE_WHEEL
c->gototune = c->lasttune;
#endif
}
#ifdef ENABLE_WHEEL
else
{
c->gototune = note - ( last_note[ chan ] << 4 ) + c->lasttune;
c->portspeed = patch.portamento;
buffer[ 0 ] = last_note[ chan ] = saved_last_note;
buffer[ 1 ] = patch.midi_velocity;
track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) );
}
#endif
}
#ifdef ENABLE_WHEEL
else
{
buffer[ 0 ] = note >> 4;
buffer[ 1 ] = patch.midi_velocity;
track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) );
last_note[ chan ] = note >> 4;
last_channel[ chan ] = channel;
c->gototune = patch.glide;
c->portspeed = patch.portamento;
}
#endif
#ifdef ENABLE_VIB
if(!patch.vibrato)
{
c->vibwait = c->vibspeed = c->vibrate = 0;
}
else
{
c->vibwait = patch.vibrato_delay;
// PASCAL: c->vibspeed = ((i->vibrato >> 4) & 15) + 1;
c->vibspeed = (patch.vibrato >> 4) + 2;
c->vibrate = (patch.vibrato & 15) + 1;
}
#endif
#ifdef ENABLE_TREM
if(!(c->trmstay & 0xf0))
{
c->trmwait = (patch.tremolo_delay & 0xf0) >> 3;
// PASCAL: c->trmspeed = (i->mod_trem >> 4) & 15;
c->trmspeed = patch.modulator_tremolo >> 4;
c->trmrate = patch.modulator_tremolo & 15;
c->trmcount = 0;
}
if(!(c->trmstay & 0x0f))
{
c->trcwait = (patch.tremolo_delay & 15) << 1;
// PASCAL: c->trcspeed = (i->car_trem >> 4) & 15;
c->trcspeed = patch.carrier_tremolo >> 4;
c->trcrate = patch.carrier_tremolo & 15;
c->trccount = 0;
}
#endif
#ifdef ENABLE_ARP
c->arp_size = patch.arpeggio & 15;
c->arp_speed = patch.arpeggio >> 4;
memcpy(c->arp_tab, patch.arpeggio_table, 12);
c->arp_pos = c->arp_count = 0;
#endif
#ifdef ENABLE_VIB
c->vibcount = 0;
#endif
#ifdef ENABLE_WHEEL
c->glideto = 0;
#endif
c->keycount = patch.keyoff;
c->nextvol = c->finetune = 0;
}
bool midi_processor::process_lds( std::vector<uint8_t> const& p_file, midi_container & p_out )
{
struct position_data
{
uint16_t pattern_number;
uint8_t transpose;
};
uint8_t mode;
/*uint16_t speed;*/
uint8_t tempo;
uint8_t pattern_length;
uint8_t channel_delay[ 9 ];
/*uint8_t register_bd;*/
uint16_t patch_count;
std::vector<sound_patch> patches;
uint16_t position_count;
std::vector<position_data> positions;
std::size_t pattern_count;
std::vector<uint16_t> patterns;
std::vector<uint8_t>::const_iterator it = p_file.begin();
std::vector<uint8_t>::const_iterator end = p_file.end();
if ( end == it ) return false;
mode = *it++;
if ( mode > 2 ) return false; /*throw exception_io_data( "Invalid LDS mode" );*/
/*speed = it[ 0 ] | ( it[ 1 ] << 8 );*/
if ( end - it < 4 ) return false;
tempo = it[ 2 ];
pattern_length = it[ 3 ];
it += 4;
if ( end - it < 9 ) return false;
for ( unsigned i = 0; i < 9; ++i )
channel_delay[ i ] = *it++;
/*register_bd = *it++;*/ it++;
if ( end - it < 2 ) return false;
patch_count = it[ 0 ] | ( it[ 1 ] << 8 );
if ( !patch_count ) return false;
it += 2;
patches.resize( patch_count );
if ( end - it < 46 * patch_count ) return false;
for ( unsigned i = 0; i < patch_count; ++i )
{
sound_patch & patch = patches[ i ];
it += 11;
patch.keyoff = *it++;
#ifdef ENABLE_WHEEL
patch.portamento = *it++;
patch.glide = *it++;
it++;
#else
it += 3;
#endif
#ifdef ENABLE_VIB
patch.vibrato = *it++;
patch.vibrato_delay = *it++;
#else
it += 2;
#endif
#ifdef ENABLE_TREM
patch.modulator_tremolo = *it++;
patch.carrier_tremolo = *it++;
patch.tremolo_delay = *it++;
#else
it += 3;
#endif
#ifdef ENABLE_ARP
patch.arpeggio = *it++;
for ( unsigned j = 0; j < 12; ++j )
patch.arpeggio_table[ j ] = *it++;
it += 7;
#else
it += 20;
#endif
patch.midi_instrument = *it++;
patch.midi_velocity = *it++;
patch.midi_key = *it++;
patch.midi_transpose = *it++;
it += 2;
#ifdef ENABLE_WHEEL
// hax
if ( patch.midi_instrument >= 0x80 )
{
patch.glide = 0;
}
#endif
}
if ( end - it < 2 ) return false;
position_count = it[ 0 ] | ( it[ 1 ] << 8 );
if ( !position_count ) return false;
it += 2;
positions.resize( 9 * position_count );
if ( end - it < 3 * position_count ) return false;
for ( unsigned i = 0; i < position_count; ++i )
{
for ( unsigned j = 0; j < 9; ++j )
{
position_data & position = positions[ i * 9 + j ];
position.pattern_number = it[ 0 ] | ( it[ 1 ] << 8 );
if ( position.pattern_number & 1 ) return false; /*throw exception_io_data( "Odd LDS pattern number" );*/
position.pattern_number >>= 1;
position.transpose = it[ 2 ];
it += 3;
}
}
if ( end - it < 2 ) return false;
it += 2;
pattern_count = ( end - it ) / 2;
patterns.resize( pattern_count );
for ( unsigned i = 0; i < pattern_count; ++i )
{
patterns[ i ] = it[ 0 ] | ( it[ 1 ] << 8 );
it += 2;
}
uint8_t /*jumping,*/ fadeonoff, allvolume, hardfade, tempo_now, pattplay;
uint16_t posplay, jumppos;
uint32_t mainvolume;
std::vector<channel_state> channel;
channel.resize( 9 );
std::vector<unsigned> position_timestamps;
position_timestamps.resize( position_count, ~0u );
uint8_t current_instrument[9] = { 0 };
uint8_t last_channel[9];
uint8_t last_instrument[9];
uint8_t last_note[9];
uint8_t last_volume[9];
uint8_t last_sent_volume[11];
#ifdef ENABLE_WHEEL
int16_t last_pitch_wheel[11];
#endif
uint8_t ticks_without_notes[11];
memset( last_channel, 0, sizeof( last_channel ) );
memset( last_instrument, 0xFF, sizeof( last_instrument ) );
memset( last_note, 0xFF, sizeof( last_note ) );
memset( last_volume, 127, sizeof( last_volume ) );
memset( last_sent_volume, 127, sizeof( last_sent_volume ) );
#ifdef ENABLE_WHEEL
memset( last_pitch_wheel, 0, sizeof( last_pitch_wheel ) );
#endif
memset( ticks_without_notes, 0, sizeof( ticks_without_notes ) );
unsigned current_timestamp = 0;
uint8_t buffer[ 2 ];
p_out.initialize( 1, 35 );
{
midi_track track;
track.add_event( midi_event( 0, midi_event::extended, 0, lds_default_tempo, _countof( lds_default_tempo ) ) );
for ( unsigned i = 0; i < 11; ++i )
{
buffer[ 0 ] = 120;
buffer[ 1 ] = 0;
track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) );
buffer[ 0 ] = 121;
track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) );
#ifdef ENABLE_WHEEL
buffer[ 0 ] = 0x65;
track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) );
buffer[ 0 ] = 0x64;
track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) );
buffer[ 0 ] = 0x06;
buffer[ 1 ] = WHEEL_RANGE_HIGH;
track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) );
buffer[ 0 ] = 0x26;
buffer[ 1 ] = WHEEL_RANGE_LOW;
track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) );
buffer[ 0 ] = 0;
buffer[ 1 ] = 64;
track.add_event( midi_event( 0, midi_event::pitch_wheel, i, buffer, 2 ) );
#endif
}
track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) );
p_out.add_track( track );
}
std::vector<midi_track> tracks;
{
midi_track track;
track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) );
tracks.resize( 10, track );
}
tempo_now = 3;
/*jumping = 0;*/
fadeonoff = 0;
allvolume = 0;
hardfade = 0;
pattplay = 0;
posplay = 0;
jumppos = 0;
mainvolume = 0;
memset( &channel[0], 0, sizeof( channel_state ) * 9 );
const uint16_t maxsound = 0x3F;
const uint16_t maxpos = 0xFF;
bool playing = true;
while ( playing )
{
uint16_t chan;
#ifdef ENABLE_VIB
uint16_t wibc;
#endif
#if defined(ENABLE_VIB) || defined(ENABLE_ARP)
int16_t tune;
#endif
#ifdef ENABLE_ARP
int16_t arpreg;
#endif
#ifdef ENABLE_TREM
uint16_t tremc;
#endif
bool vbreak;
unsigned i;
channel_state * c;
if(fadeonoff)
{
if(fadeonoff <= 128)
{
if(allvolume > fadeonoff || allvolume == 0)
{
allvolume -= fadeonoff;
}
else
{
allvolume = 1;
fadeonoff = 0;
if(hardfade != 0)
{
playing = false;
hardfade = 0;
for(i = 0; i < 9; i++)
channel[i].keycount = 1;
}
}
}
else if((unsigned)((allvolume + (0x100 - fadeonoff)) & 0xff) <= mainvolume)
{
allvolume += 0x100 - fadeonoff;
}
else
{
allvolume = mainvolume;
fadeonoff = 0;
}
}
// handle channel delay
for(chan = 0; chan < 9; ++chan)
{
channel_state * _c = &channel[chan];
if(_c->chancheat.chandelay)
{
if(!(--_c->chancheat.chandelay))
{
playsound( current_instrument, patches, last_note, last_channel, last_instrument, last_volume, last_sent_volume,
#ifdef ENABLE_WHEEL
last_pitch_wheel,
#endif
_c, allvolume, current_timestamp, _c->chancheat.sound, chan, _c->chancheat.high, tracks[ chan ] );
ticks_without_notes[ last_channel[ chan ] ] = 0;
}
}
}
// handle notes
if(!tempo_now)
{
if ( pattplay == 0 && position_timestamps[ posplay ] == ~0u )
{
position_timestamps[ posplay ] = current_timestamp;
}
vbreak = false;
for(unsigned _chan = 0; _chan < 9; _chan++)
{
channel_state * _c = &channel[_chan];
if(!_c->packwait)
{
unsigned short patnum = positions[posplay * 9 + _chan].pattern_number;
unsigned char transpose = positions[posplay * 9 + _chan].transpose;
if ( (unsigned long)(patnum + _c->packpos) >= patterns.size() ) return false; /*throw exception_io_data( "Invalid LDS pattern number" );*/
unsigned comword = patterns[patnum + _c->packpos];
unsigned comhi = comword >> 8;
unsigned comlo = comword & 0xff;
if(comword)
{
if(comhi == 0x80)
{
_c->packwait = comlo;
}
else if(comhi >= 0x80)
{
switch(comhi) {
case 0xff:
{
unsigned volume = ( comlo & 0x3F ) * 127 / 63;
last_volume[ _chan ] = volume;
if ( volume != last_sent_volume[ last_channel[ _chan ] ] )
{
buffer[ 0 ] = 7;
buffer[ 1 ] = volume;
tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ _chan ], buffer, 2 ) );
last_sent_volume[ last_channel [ _chan ] ] = volume;
}
}
break;
case 0xfe:
tempo = comword & 0x3f;
break;
case 0xfd:
_c->nextvol = comlo;
break;
case 0xfc:
playing = false;
// in real player there's also full keyoff here, but we don't need it
break;
case 0xfb:
_c->keycount = 1;
break;
case 0xfa:
vbreak = true;
jumppos = (posplay + 1) & maxpos;
break;
case 0xf9:
vbreak = true;
jumppos = comlo & maxpos;
/*jumping = 1;*/
if(jumppos <= posplay)
{
p_out.add_track_event( 0, midi_event( position_timestamps[ jumppos ], midi_event::extended, 0, loop_start, _countof( loop_start ) ) );
p_out.add_track_event( 0, midi_event( current_timestamp + tempo - 1, midi_event::extended, 0, loop_end, _countof( loop_end ) ) );
playing = false;
}
break;
case 0xf8:
#ifdef ENABLE_WHEEL
_c->lasttune = 0;
#endif
break;
case 0xf7:
#ifdef ENABLE_VIB
_c->vibwait = 0;
// PASCAL: _c->vibspeed = ((comlo >> 4) & 15) + 2;
_c->vibspeed = (comlo >> 4) + 2;
_c->vibrate = (comlo & 15) + 1;
#endif
break;
case 0xf6:
#ifdef ENABLE_WHEEL
_c->glideto = comlo;
#endif
break;
case 0xf5:
_c->finetune = comlo;
break;
case 0xf4:
if(!hardfade) {
allvolume = mainvolume = comlo;
fadeonoff = 0;
}
break;
case 0xf3:
if(!hardfade) fadeonoff = comlo;
break;
case 0xf2:
#ifdef ENABLE_TREM
_c->trmstay = comlo;
#endif
break;
case 0xf1:
buffer[ 0 ] = 10;
buffer[ 1 ] = ( comlo & 0x3F ) * 127 / 63;
tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ _chan ], buffer, 2 ) );
break;
case 0xf0:
buffer[ 0 ] = comlo & 0x7F;
tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::program_change, last_channel[ _chan ], buffer, 1 ) );
break;
default:
#ifdef ENABLE_WHEEL
if(comhi < 0xa0)
_c->glideto = comhi & 0x1f;
#endif
break;
}
}
else
{
unsigned char sound;
unsigned short high;
signed char transp = transpose << 1;
transp >>= 1;
if(transpose & 128) {
sound = (comlo + transp) & maxsound;
high = comhi << 4;
} else {
sound = comlo & maxsound;
high = (comhi + transp) << 4;
}
/*
PASCAL:
sound = comlo & maxsound;
high = (comhi + (((transpose + 0x24) & 0xff) - 0x24)) << 4;
*/
if( !channel_delay[ _chan ] )
{
playsound( current_instrument, patches, last_note, last_channel, last_instrument, last_volume, last_sent_volume,
#ifdef ENABLE_WHEEL
last_pitch_wheel,
#endif
_c, allvolume, current_timestamp, sound, _chan, high, tracks[ _chan ] );
ticks_without_notes[ last_channel[ _chan ] ] = 0;
}
else
{
_c->chancheat.chandelay = channel_delay[_chan];
_c->chancheat.sound = sound;
_c->chancheat.high = high;
}
}
}
_c->packpos++;
}
else
{
_c->packwait--;
}
}
tempo_now = tempo;
/*
The continue table is updated here, but this is only used in the
original player, which can be paused in the middle of a song and then
unpaused. Since AdPlug does all this for us automatically, we don't
have a continue table here. The continue table update code is noted
here for reference only.
if(!pattplay) {
conttab[speed & maxcont].position = posplay & 0xff;
conttab[speed & maxcont].tempo = tempo;
}
*/
pattplay++;
if(vbreak)
{
pattplay = 0;
for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0;
posplay = jumppos;
if ( posplay >= position_count ) return false; /*throw exception_io_data( "Invalid LDS position jump" );*/
}
else if(pattplay >= pattern_length)
{
pattplay = 0;
for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0;
posplay = (posplay + 1) & maxpos;
if ( posplay >= position_count ) playing = false; //throw exception_io_data( "LDS reached the end without a loop or end command" );
}
}
else
{
tempo_now--;
}
// make effects
for(chan = 0; chan < 9; ++chan)
{
c = &channel[chan];
if(c->keycount > 0)
{
if( c->keycount == 1 && last_note[ chan ] != 0xFF )
{
buffer[ 0 ] = last_note[ chan ];
buffer[ 1 ] = 127;
tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::note_off, last_channel[ chan ], buffer, 2 ) );
last_note[ chan ] = 0xFF;
#ifdef ENABLE_WHEEL
if ( 0 != last_pitch_wheel[ last_channel[ chan ] ] )
{
buffer[ 0 ] = 0;
buffer[ 1 ] = 64;
tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) );
last_pitch_wheel[ last_channel[ chan ] ] = 0;
c->lasttune = 0;
c->gototune = 0;
}
#endif
}
c->keycount--;
}
#ifdef ENABLE_ARP
// arpeggio
if(c->arp_size == 0)
{
arpreg = 0;
}
else
{
arpreg = c->arp_tab[c->arp_pos] << 4;
if(arpreg == -0x800)
{
if(c->arp_pos > 0) c->arp_tab[0] = c->arp_tab[c->arp_pos - 1];
c->arp_size = 1; c->arp_pos = 0;
arpreg = c->arp_tab[0] << 4;
}
if(c->arp_count == c->arp_speed) {
c->arp_pos++;
if(c->arp_pos >= c->arp_size) c->arp_pos = 0;
c->arp_count = 0;
}
else
{
c->arp_count++;
}
}
#endif
#ifdef ENABLE_WHEEL
// glide & portamento
if(c->lasttune != c->gototune)
{
if(c->lasttune > c->gototune)
{
if(c->lasttune - c->gototune < c->portspeed)
{
c->lasttune = c->gototune;
}
else
{
c->lasttune -= c->portspeed;
}
}
else
{
if(c->gototune - c->lasttune < c->portspeed)
{
c->lasttune = c->gototune;
}
else
{
c->lasttune += c->portspeed;
}
}
#ifdef ENABLE_ARP
arpreg +=
#else
int16_t arpreg =
#endif
c->lasttune;
if ( arpreg != last_pitch_wheel[ last_channel[ chan ] ] )
{
buffer[ 0 ] = WHEEL_SCALE_LOW( arpreg );
buffer[ 1 ] = WHEEL_SCALE_HIGH( arpreg );
tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) );
last_pitch_wheel[ last_channel[ chan ] ] = arpreg;
}
} else
{
#ifdef ENABLE_VIB
// vibrato
if(!c->vibwait)
{
if(c->vibrate)
{
wibc = vibtab[c->vibcount & 0x3f] * c->vibrate;
if((c->vibcount & 0x40) == 0)
tune = c->lasttune + (wibc >> 8);
else
tune = c->lasttune - (wibc >> 8);
#ifdef ENABLE_ARP
tune += arpreg;
#endif
if ( tune != last_pitch_wheel[ last_channel[ chan ] ] )
{
buffer[ 0 ] = WHEEL_SCALE_LOW( tune );
buffer[ 1 ] = WHEEL_SCALE_HIGH( tune );
tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) );
last_pitch_wheel[ last_channel[ chan ] ] = tune;
}
c->vibcount += c->vibspeed;
}
#ifdef ENABLE_ARP
else if(c->arp_size != 0)
{ // no vibrato, just arpeggio
tune = c->lasttune + arpreg;
if ( tune != last_pitch_wheel[ last_channel[ chan ] ] )
{
buffer[ 0 ] = WHEEL_SCALE_LOW( tune );
buffer[ 1 ] = WHEEL_SCALE_HIGH( tune );
tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) );
last_pitch_wheel[ last_channel[ chan ] ] = tune;
}
}
#endif
}
#ifdef ENABLE_ARP
else
#endif
#endif
#ifdef ENABLE_ARP
{ // no vibrato, just arpeggio
#ifdef ENABLE_VIB
c->vibwait--;
#endif
if(c->arp_size != 0)
{
tune = c->lasttune + arpreg;
if ( tune != last_pitch_wheel[ last_channel[ chan ] ] )
{
buffer[ 0 ] = WHEEL_SCALE_LOW( tune );
buffer[ 1 ] = WHEEL_SCALE_HIGH( tune );
tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) );
last_pitch_wheel[ last_channel[ chan ] ] = tune;
}
}
}
#endif
}
#endif
#ifdef ENABLE_TREM
unsigned volume = last_volume[ chan ];
// tremolo (modulator)
if(!c->trmwait)
{
if(c->trmrate)
{
tremc = tremtab[c->trmcount & 0x7f] * c->trmrate;
if((tremc >> 7) <= volume)
volume = volume - (tremc >> 7);
else
volume = 0;
c->trmcount += c->trmspeed;
}
}
else
{
c->trmwait--;
}
// tremolo (carrier)
if(!c->trcwait)
{
if(c->trcrate)
{
tremc = tremtab[c->trccount & 0x7f] * c->trcrate;
if((tremc >> 7) <= volume)
volume = volume - (tremc >> 8);
else
volume = 0;
}
}
else
{
c->trcwait--;
}
if ( allvolume )
{
volume = volume * allvolume / 255;
}
if ( volume != last_sent_volume[ last_channel[ chan ] ] )
{
buffer[ 0 ] = 7;
buffer[ 1 ] = volume;
tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ chan ], buffer, 2 ) );
last_sent_volume[ last_channel[ chan ] ] = volume;
}
#endif
}
++current_timestamp;
}
--current_timestamp;
for ( unsigned i = 0; i < 9; ++i )
{
midi_track & track = tracks[ i ];
unsigned long count = track.get_count();
if ( count > 1 )
{
if ( last_note[ i ] != 0xFF )
{
buffer[ 0 ] = last_note[ i ];
buffer[ 1 ] = 127;
track.add_event( midi_event( current_timestamp + channel[ i ].keycount, midi_event::note_off, last_channel[ i ], buffer, 2 ) );
#ifdef ENABLE_WHEEL
if ( last_pitch_wheel[ last_channel[ i ] ] != 0 )
{
buffer[ 0 ] = 0;
buffer[ 1 ] = 0x40;
track.add_event( midi_event( current_timestamp + channel[ i ].keycount, midi_event::pitch_wheel, last_channel[ i ], buffer, 2 ) );
}
#endif
}
p_out.add_track( track );
}
}
return true;
}