2013-10-15 14:49:53 +00:00
|
|
|
#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
|
|
|
|
{
|
2020-04-14 09:10:52 +00:00
|
|
|
// skip 11 bytes worth of Adlib crap
|
2013-10-15 14:49:53 +00:00
|
|
|
uint8_t keyoff;
|
|
|
|
#ifdef ENABLE_WHEEL
|
|
|
|
uint8_t portamento;
|
|
|
|
int8_t glide;
|
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
// skip 1 byte
|
2013-10-15 14:49:53 +00:00
|
|
|
#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
|
2020-04-14 09:10:52 +00:00
|
|
|
// skip 4 bytes worth of digital instrument crap
|
|
|
|
// skip 3 more bytes worth of Adlib crap that isn't even used
|
2013-10-15 14:49:53 +00:00
|
|
|
uint8_t midi_instrument;
|
|
|
|
uint8_t midi_velocity;
|
|
|
|
uint8_t midi_key;
|
|
|
|
int8_t midi_transpose;
|
2020-04-14 09:10:52 +00:00
|
|
|
// skip 2 bytes worth of MIDI dummy fields or whatever
|
2013-10-15 14:49:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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,
|
2020-04-14 09:10:52 +00:00
|
|
|
keycount, packwait;
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_VIB
|
|
|
|
uint8_t vibwait, vibspeed, vibrate, vibcount;
|
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_TREM
|
|
|
|
uint8_t trmstay, trmwait, trmspeed, trmrate, trmcount,
|
2020-04-14 09:10:52 +00:00
|
|
|
trcwait, trcspeed, trcrate, trccount;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_ARP
|
|
|
|
uint8_t arp_count, arp_size, arp_speed, arp_pos;
|
|
|
|
int8_t arp_tab[12];
|
|
|
|
#endif
|
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
struct {
|
2013-10-15 14:49:53 +00:00
|
|
|
uint8_t chandelay, sound;
|
|
|
|
uint16_t high;
|
2020-04-14 09:10:52 +00:00
|
|
|
} chancheat;
|
2013-10-15 14:49:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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 ];
|
2020-04-14 09:10:52 +00:00
|
|
|
current_instrument[ chan ] = sound;
|
2013-10-15 14:49:53 +00:00
|
|
|
if ( sound >= patches.size() ) return;
|
2020-04-14 09:10:52 +00:00
|
|
|
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
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_ARP
|
2020-04-14 09:10:52 +00:00
|
|
|
if(patch.arpeggio)
|
|
|
|
{
|
|
|
|
short arpcalc = patch.arpeggio_table[0] << 4;
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
high += arpcalc;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
// and MIDI transpose
|
|
|
|
high = (int)high + ( patch.midi_transpose << 4 );
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
note = high
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
- c->lasttune
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
;
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
// glide handling
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
if(c->glideto != 0)
|
|
|
|
{
|
|
|
|
c->gototune = note - ( last_note[ chan ] << 4 ) + c->lasttune;
|
|
|
|
c->portspeed = c->glideto;
|
|
|
|
c->glideto = c->finetune = 0;
|
|
|
|
return;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
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 )
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
{
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
if( !patch.portamento || last_note[ chan ] == 0xFF )
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
{
|
|
|
|
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;
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
c->gototune = c->lasttune;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
else
|
|
|
|
{
|
2013-10-15 14:49:53 +00:00
|
|
|
c->gototune = note - ( last_note[ chan ] << 4 ) + c->lasttune;
|
2020-04-14 09:10:52 +00:00
|
|
|
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 ) );
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENABLE_VIB
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENABLE_TREM
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENABLE_ARP
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_VIB
|
2020-04-14 09:10:52 +00:00
|
|
|
c->vibcount = 0;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
c->glideto = 0;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
c->keycount = patch.keyoff;
|
|
|
|
c->nextvol = c->finetune = 0;
|
2013-10-15 14:49:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool midi_processor::process_lds( std::vector<uint8_t> const& p_file, midi_container & p_out )
|
|
|
|
{
|
2020-04-14 09:10:52 +00:00
|
|
|
struct position_data
|
|
|
|
{
|
2013-10-15 14:49:53 +00:00
|
|
|
uint16_t pattern_number;
|
|
|
|
uint8_t transpose;
|
2020-04-14 09:10:52 +00:00
|
|
|
};
|
2013-10-15 14:49:53 +00:00
|
|
|
|
|
|
|
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();
|
2020-04-14 09:10:52 +00:00
|
|
|
std::vector<uint8_t>::const_iterator end = p_file.end();
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
if ( end == it ) return false;
|
2013-10-15 14:49:53 +00:00
|
|
|
mode = *it++;
|
|
|
|
if ( mode > 2 ) return false; /*throw exception_io_data( "Invalid LDS mode" );*/
|
|
|
|
/*speed = it[ 0 ] | ( it[ 1 ] << 8 );*/
|
2020-04-14 09:10:52 +00:00
|
|
|
if ( end - it < 4 ) return false;
|
2013-10-15 14:49:53 +00:00
|
|
|
tempo = it[ 2 ];
|
|
|
|
pattern_length = it[ 3 ];
|
|
|
|
it += 4;
|
2020-04-14 09:10:52 +00:00
|
|
|
if ( end - it < 9 ) return false;
|
|
|
|
for ( unsigned i = 0; i < 9; ++i )
|
2013-10-15 14:49:53 +00:00
|
|
|
channel_delay[ i ] = *it++;
|
|
|
|
/*register_bd = *it++;*/ it++;
|
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
if ( end - it < 2 ) return false;
|
2013-10-15 14:49:53 +00:00
|
|
|
patch_count = it[ 0 ] | ( it[ 1 ] << 8 );
|
2020-04-14 09:10:52 +00:00
|
|
|
if ( !patch_count ) return false;
|
2013-10-15 14:49:53 +00:00
|
|
|
it += 2;
|
|
|
|
patches.resize( patch_count );
|
2020-04-14 09:10:52 +00:00
|
|
|
if ( end - it < 46 * patch_count ) return false;
|
|
|
|
for ( unsigned i = 0; i < patch_count; ++i )
|
|
|
|
{
|
|
|
|
sound_patch & patch = patches[ i ];
|
2013-10-15 14:49:53 +00:00
|
|
|
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++;
|
2020-04-14 09:10:52 +00:00
|
|
|
for ( unsigned j = 0; j < 12; ++j )
|
2013-10-15 14:49:53 +00:00
|
|
|
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
|
2020-04-14 09:10:52 +00:00
|
|
|
// hax
|
|
|
|
if ( patch.midi_instrument >= 0x80 )
|
|
|
|
{
|
|
|
|
patch.glide = 0;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
if ( end - it < 2 ) return false;
|
2013-10-15 14:49:53 +00:00
|
|
|
position_count = it[ 0 ] | ( it[ 1 ] << 8 );
|
2020-04-14 09:10:52 +00:00
|
|
|
if ( !position_count ) return false;
|
2013-10-15 14:49:53 +00:00
|
|
|
it += 2;
|
|
|
|
positions.resize( 9 * position_count );
|
2020-04-14 09:10:52 +00:00
|
|
|
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 ];
|
2013-10-15 14:49:53 +00:00
|
|
|
position.pattern_number = it[ 0 ] | ( it[ 1 ] << 8 );
|
|
|
|
if ( position.pattern_number & 1 ) return false; /*throw exception_io_data( "Odd LDS pattern number" );*/
|
2020-04-14 09:10:52 +00:00
|
|
|
position.pattern_number >>= 1;
|
2013-10-15 14:49:53 +00:00
|
|
|
position.transpose = it[ 2 ];
|
|
|
|
it += 3;
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
if ( end - it < 2 ) return false;
|
2013-10-15 14:49:53 +00:00
|
|
|
it += 2;
|
|
|
|
|
2013-10-25 21:00:51 +00:00
|
|
|
pattern_count = ( end - it ) / 2;
|
2013-10-15 14:49:53 +00:00
|
|
|
patterns.resize( pattern_count );
|
2020-04-14 09:10:52 +00:00
|
|
|
for ( unsigned i = 0; i < pattern_count; ++i )
|
|
|
|
{
|
2013-10-15 14:49:53 +00:00
|
|
|
patterns[ i ] = it[ 0 ] | ( it[ 1 ] << 8 );
|
|
|
|
it += 2;
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
|
|
|
|
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];
|
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
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 ) );
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
memset( last_pitch_wheel, 0, sizeof( last_pitch_wheel ) );
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
memset( ticks_without_notes, 0, sizeof( ticks_without_notes ) );
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
unsigned current_timestamp = 0;
|
2013-10-15 14:49:53 +00:00
|
|
|
|
|
|
|
uint8_t buffer[ 2 ];
|
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
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 ) );
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
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 ) );
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
|
|
|
track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) );
|
|
|
|
p_out.add_track( track );
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
|
|
|
|
std::vector<midi_track> tracks;
|
2020-04-14 09:10:52 +00:00
|
|
|
{
|
|
|
|
midi_track track;
|
|
|
|
track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) );
|
2013-10-15 14:49:53 +00:00
|
|
|
tracks.resize( 10, track );
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
tempo_now = 3;
|
2013-10-15 14:49:53 +00:00
|
|
|
/*jumping = 0;*/
|
2020-04-14 09:10:52 +00:00
|
|
|
fadeonoff = 0;
|
|
|
|
allvolume = 0;
|
|
|
|
hardfade = 0;
|
|
|
|
pattplay = 0;
|
|
|
|
posplay = 0;
|
|
|
|
jumppos = 0;
|
|
|
|
mainvolume = 0;
|
2013-10-15 14:49:53 +00:00
|
|
|
memset( &channel[0], 0, sizeof( channel_state ) * 9 );
|
|
|
|
|
|
|
|
const uint16_t maxsound = 0x3F;
|
|
|
|
const uint16_t maxpos = 0xFF;
|
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
bool playing = true;
|
|
|
|
while ( playing )
|
|
|
|
{
|
2013-10-15 14:49:53 +00:00
|
|
|
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
|
2020-04-14 09:10:52 +00:00
|
|
|
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,
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
last_pitch_wheel,
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
_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)
|
|
|
|
{
|
2013-10-15 14:49:53 +00:00
|
|
|
if ( pattplay == 0 && position_timestamps[ posplay ] == ~0u )
|
2020-04-14 09:10:52 +00:00
|
|
|
{
|
|
|
|
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;
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2015-02-22 02:09:33 +00:00
|
|
|
if ( (unsigned long)(patnum + _c->packpos) >= patterns.size() ) return false; /*throw exception_io_data( "Invalid LDS pattern number" );*/
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
2013-10-15 14:49:53 +00:00
|
|
|
/*jumping = 1;*/
|
2020-04-14 09:10:52 +00:00
|
|
|
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:
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
_c->lasttune = 0;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
break;
|
|
|
|
case 0xf7:
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_VIB
|
2020-04-14 09:10:52 +00:00
|
|
|
_c->vibwait = 0;
|
|
|
|
// PASCAL: _c->vibspeed = ((comlo >> 4) & 15) + 2;
|
|
|
|
_c->vibspeed = (comlo >> 4) + 2;
|
|
|
|
_c->vibrate = (comlo & 15) + 1;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
break;
|
|
|
|
case 0xf6:
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
_c->glideto = comlo;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
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:
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_TREM
|
2020-04-14 09:10:52 +00:00
|
|
|
_c->trmstay = comlo;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
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:
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
if(comhi < 0xa0)
|
|
|
|
_c->glideto = comhi & 0x1f;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
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,
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
last_pitch_wheel,
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
_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;
|
2013-10-15 14:49:53 +00:00
|
|
|
if ( posplay >= position_count ) return false; /*throw exception_io_data( "Invalid LDS position jump" );*/
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
|
|
|
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;
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
|
|
|
c->keycount--;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
|
|
|
|
#ifdef ENABLE_ARP
|
2020-04-14 09:10:52 +00:00
|
|
|
// 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++;
|
|
|
|
}
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
|
|
|
|
#ifdef ENABLE_ARP
|
2020-04-14 09:10:52 +00:00
|
|
|
arpreg +=
|
2013-10-15 14:49:53 +00:00
|
|
|
#else
|
|
|
|
int16_t arpreg =
|
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
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
|
|
|
|
{
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_VIB
|
2020-04-14 09:10:52 +00:00
|
|
|
// 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);
|
2013-10-15 14:49:53 +00:00
|
|
|
|
|
|
|
#ifdef ENABLE_ARP
|
2020-04-14 09:10:52 +00:00
|
|
|
tune += arpreg;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
c->vibcount += c->vibspeed;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_ARP
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_ARP
|
2020-04-14 09:10:52 +00:00
|
|
|
else
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_ARP
|
2020-04-14 09:10:52 +00:00
|
|
|
{ // no vibrato, just arpeggio
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_VIB
|
2020-04-14 09:10:52 +00:00
|
|
|
c->vibwait--;
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENABLE_TREM
|
2020-04-14 09:10:52 +00:00
|
|
|
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;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
++current_timestamp;
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
--current_timestamp;
|
2013-10-15 14:49:53 +00:00
|
|
|
|
2020-04-14 09:10:52 +00:00
|
|
|
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 ) );
|
2013-10-15 14:49:53 +00:00
|
|
|
#ifdef ENABLE_WHEEL
|
2020-04-14 09:10:52 +00:00
|
|
|
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 ) );
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
#endif
|
2020-04-14 09:10:52 +00:00
|
|
|
}
|
|
|
|
p_out.add_track( track );
|
|
|
|
}
|
|
|
|
}
|
2013-10-15 14:49:53 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|