#include "midi_processor.h" #include 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 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 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 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 patches; uint16_t position_count; std::vector positions; std::size_t pattern_count; std::vector patterns; std::vector::const_iterator it = p_file.begin(); std::vector::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; channel.resize( 9 ); std::vector 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 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; }