2013-10-10 21:13:18 -03:00
/*
* SSEQ Player - Track structure
* By Naram Qashat ( CyberBotX ) [ cyberbotx @ cyberbotx . com ]
2014-11-04 22:56:15 -03:00
* Last modification on 2014 - 10 - 23
2013-10-10 21:13:18 -03:00
*
* Adapted from source code of FeOS Sound System
* By fincs
* https : //github.com/fincs/FSS
*/
2014-11-04 22:56:15 -03:00
# include <cstdlib>
2013-10-10 21:13:18 -03:00
# include "Track.h"
# include "Player.h"
# include "common.h"
Track : : Track ( )
{
this - > Zero ( ) ;
}
2014-11-04 22:56:15 -03:00
// Original FSS Function: Player_InitTrack
2013-10-10 21:13:18 -03:00
void Track : : Init ( uint8_t handle , Player * player , const uint8_t * dataPos , int n )
{
this - > trackId = handle ;
this - > num = n ;
this - > ply = player ;
this - > startPos = dataPos ;
this - > ClearState ( ) ;
}
void Track : : Zero ( )
{
this - > trackId = - 1 ;
this - > state . reset ( ) ;
this - > num = this - > prio = 0 ;
this - > ply = nullptr ;
this - > startPos = this - > pos = nullptr ;
2014-11-04 22:56:15 -03:00
std : : fill_n ( & this - > stack [ 0 ] , FSS_TRACKSTACKSIZE , StackValue ( ) ) ;
2013-10-10 21:13:18 -03:00
this - > stackPos = 0 ;
memset ( this - > loopCount , 0 , sizeof ( this - > loopCount ) ) ;
2014-11-04 22:56:15 -03:00
this - > overriding ( ) = false ;
this - > lastComparisonResult = true ;
2013-10-10 21:13:18 -03:00
this - > wait = 0 ;
this - > patch = 0 ;
this - > portaKey = this - > portaTime = 0 ;
this - > sweepPitch = 0 ;
this - > vol = this - > expr = 0 ;
this - > pan = 0 ;
this - > pitchBendRange = 0 ;
this - > pitchBend = this - > transpose = 0 ;
this - > a = this - > d = this - > s = this - > r = 0 ;
this - > modType = this - > modSpeed = this - > modDepth = this - > modRange = 0 ;
this - > modDelay = 0 ;
this - > updateFlags . reset ( ) ;
}
2014-11-04 22:56:15 -03:00
// Original FSS Function: Track_ClearState
2013-10-10 21:13:18 -03:00
void Track : : ClearState ( )
{
this - > state . reset ( ) ;
this - > state . set ( TS_ALLOCBIT ) ;
this - > state . set ( TS_NOTEWAIT ) ;
this - > prio = this - > ply - > prio + 64 ;
this - > pos = this - > startPos ;
this - > stackPos = 0 ;
this - > wait = 0 ;
this - > patch = 0 ;
this - > portaKey = 60 ;
this - > portaTime = 0 ;
this - > sweepPitch = 0 ;
2014-11-04 22:56:15 -03:00
this - > vol = this - > expr = 127 ;
2013-10-10 21:13:18 -03:00
this - > pan = 0 ;
this - > pitchBendRange = 2 ;
this - > pitchBend = this - > transpose = 0 ;
this - > a = this - > d = this - > s = this - > r = 0xFF ;
this - > modType = 0 ;
this - > modRange = 1 ;
this - > modSpeed = 16 ;
2014-11-04 22:56:15 -03:00
this - > modDelay = 0 ;
2013-10-10 21:13:18 -03:00
this - > modDepth = 0 ;
}
2014-11-04 22:56:15 -03:00
// Original FSS Function: Track_Free
2013-10-10 21:13:18 -03:00
void Track : : Free ( )
{
this - > state . reset ( ) ;
this - > updateFlags . reset ( ) ;
}
2014-11-04 22:56:15 -03:00
// Original FSS Function: Note_On
2013-10-10 21:13:18 -03:00
int Track : : NoteOn ( int key , int vel , int len )
{
auto sbnk = this - > ply - > sseq - > bank ;
if ( this - > patch > = sbnk - > instruments . size ( ) )
return - 1 ;
bool bIsPCM = true ;
Channel * chn = nullptr ;
int nCh = - 1 ;
auto & instrument = sbnk - > instruments [ this - > patch ] ;
const SBNKInstrumentRange * noteDef = nullptr ;
int fRecord = instrument . record ;
if ( fRecord = = 16 )
{
if ( ! ( instrument . ranges [ 0 ] . lowNote < = key & & key < = instrument . ranges [ instrument . ranges . size ( ) - 1 ] . highNote ) )
return - 1 ;
int rn = key - instrument . ranges [ 0 ] . lowNote ;
noteDef = & instrument . ranges [ rn ] ;
fRecord = noteDef - > record ;
}
else if ( fRecord = = 17 )
{
size_t reg , ranges ;
for ( reg = 0 , ranges = instrument . ranges . size ( ) ; reg < ranges ; + + reg )
if ( key < = instrument . ranges [ reg ] . highNote )
break ;
if ( reg = = ranges )
return - 1 ;
noteDef = & instrument . ranges [ reg ] ;
fRecord = noteDef - > record ;
}
if ( ! fRecord )
return - 1 ;
else if ( fRecord = = 1 )
{
if ( ! noteDef )
noteDef = & instrument . ranges [ 0 ] ;
}
else if ( fRecord < 4 )
{
// PSG
// fRecord = 2 -> PSG tone, pNoteDef->wavid -> PSG duty
// fRecord = 3 -> PSG noise
bIsPCM = false ;
if ( ! noteDef )
noteDef = & instrument . ranges [ 0 ] ;
if ( fRecord = = 3 )
{
nCh = this - > ply - > ChannelAlloc ( TYPE_NOISE , this - > prio ) ;
if ( nCh < 0 )
return - 1 ;
chn = & this - > ply - > channels [ nCh ] ;
chn - > tempReg . CR = SOUND_FORMAT_PSG | SCHANNEL_ENABLE ;
}
else
{
nCh = this - > ply - > ChannelAlloc ( TYPE_PSG , this - > prio ) ;
if ( nCh < 0 )
return - 1 ;
chn = & this - > ply - > channels [ nCh ] ;
chn - > tempReg . CR = SOUND_FORMAT_PSG | SCHANNEL_ENABLE | SOUND_DUTY ( noteDef - > swav & 0x7 ) ;
}
// TODO: figure out what pNoteDef->tnote means for PSG channels
chn - > tempReg . TIMER = - SOUND_FREQ ( 440 * 8 ) ; // key #69 (A4)
chn - > reg . samplePosition = - 1 ;
chn - > reg . psgX = 0x7FFF ;
}
if ( bIsPCM )
{
nCh = this - > ply - > ChannelAlloc ( TYPE_PCM , this - > prio ) ;
if ( nCh < 0 )
return - 1 ;
chn = & this - > ply - > channels [ nCh ] ;
auto swav = & sbnk - > waveArc [ noteDef - > swar ] - > swavs . find ( noteDef - > swav ) - > second ;
chn - > tempReg . CR = SOUND_FORMAT ( swav - > waveType & 3 ) | SOUND_LOOP ( ! ! swav - > loop ) | SCHANNEL_ENABLE ;
chn - > tempReg . SOURCE = swav ;
chn - > tempReg . TIMER = swav - > time ;
chn - > tempReg . REPEAT_POINT = swav - > loopOffset ;
chn - > tempReg . LENGTH = swav - > nonLoopLength ;
chn - > reg . samplePosition = - 3 ;
}
chn - > state = CS_START ;
chn - > trackId = this - > trackId ;
chn - > flags . reset ( ) ;
chn - > prio = this - > prio ;
chn - > key = key ;
chn - > orgKey = bIsPCM ? noteDef - > noteNumber : 69 ;
chn - > velocity = Cnv_Sust ( vel ) ;
chn - > pan = static_cast < int > ( noteDef - > pan ) - 64 ;
chn - > modDelayCnt = 0 ;
chn - > modCounter = 0 ;
chn - > noteLength = len ;
chn - > reg . sampleIncrease = 0 ;
chn - > attackLvl = Cnv_Attack ( this - > a = = 0xFF ? noteDef - > attackRate : this - > a ) ;
chn - > decayRate = Cnv_Fall ( this - > d = = 0xFF ? noteDef - > decayRate : this - > d ) ;
chn - > sustainLvl = this - > s = = 0xFF ? noteDef - > sustainLevel : this - > s ;
chn - > releaseRate = Cnv_Fall ( this - > r = = 0xFF ? noteDef - > releaseRate : this - > r ) ;
chn - > UpdateVol ( * this ) ;
chn - > UpdatePan ( * this ) ;
chn - > UpdateTune ( * this ) ;
chn - > UpdateMod ( * this ) ;
chn - > UpdatePorta ( * this ) ;
this - > portaKey = key ;
return nCh ;
}
2014-11-04 22:56:15 -03:00
// Original FSS Function: Note_On_Tie
2013-10-10 21:13:18 -03:00
int Track : : NoteOnTie ( int key , int vel )
{
// Find an existing note
int i ;
Channel * chn = nullptr ;
for ( i = 0 ; i < 16 ; + + i )
{
chn = & this - > ply - > channels [ i ] ;
if ( chn - > state > CS_NONE & & chn - > trackId = = this - > trackId & & chn - > state ! = CS_RELEASE )
break ;
}
if ( i = = 16 )
// Can't find note -> create an endless one
return this - > NoteOn ( key , vel , - 1 ) ;
chn - > flags . reset ( ) ;
chn - > prio = this - > prio ;
chn - > key = key ;
chn - > velocity = Cnv_Sust ( vel ) ;
chn - > modDelayCnt = 0 ;
chn - > modCounter = 0 ;
chn - > UpdateVol ( * this ) ;
//chn->UpdatePan(*this);
chn - > UpdateTune ( * this ) ;
chn - > UpdateMod ( * this ) ;
chn - > UpdatePorta ( * this ) ;
this - > portaKey = key ;
chn - > flags . set ( CF_UPDTMR ) ;
return i ;
}
2014-11-04 22:56:15 -03:00
// Original FSS Function: Track_ReleaseAllNotes
2013-10-10 21:13:18 -03:00
void Track : : ReleaseAllNotes ( )
{
for ( int i = 0 ; i < 16 ; + + i )
{
Channel & chn = this - > ply - > channels [ i ] ;
if ( chn . state > CS_NONE & & chn . trackId = = this - > trackId & & chn . state ! = CS_RELEASE )
chn . Release ( ) ;
}
}
enum SseqCommand
{
2014-11-04 22:56:15 -03:00
SSEQ_CMD_ALLOCTRACK = 0xFE , // Silently ignored
SSEQ_CMD_OPENTRACK = 0x93 ,
2013-10-10 21:13:18 -03:00
SSEQ_CMD_REST = 0x80 ,
SSEQ_CMD_PATCH = 0x81 ,
SSEQ_CMD_PAN = 0xC0 ,
SSEQ_CMD_VOL = 0xC1 ,
SSEQ_CMD_MASTERVOL = 0xC2 ,
SSEQ_CMD_PRIO = 0xC6 ,
SSEQ_CMD_NOTEWAIT = 0xC7 ,
SSEQ_CMD_TIE = 0xC8 ,
SSEQ_CMD_EXPR = 0xD5 ,
SSEQ_CMD_TEMPO = 0xE1 ,
SSEQ_CMD_END = 0xFF ,
SSEQ_CMD_GOTO = 0x94 ,
SSEQ_CMD_CALL = 0x95 ,
SSEQ_CMD_RET = 0xFD ,
SSEQ_CMD_LOOPSTART = 0xD4 ,
SSEQ_CMD_LOOPEND = 0xFC ,
SSEQ_CMD_TRANSPOSE = 0xC3 ,
SSEQ_CMD_PITCHBEND = 0xC4 ,
SSEQ_CMD_PITCHBENDRANGE = 0xC5 ,
SSEQ_CMD_ATTACK = 0xD0 ,
SSEQ_CMD_DECAY = 0xD1 ,
SSEQ_CMD_SUSTAIN = 0xD2 ,
SSEQ_CMD_RELEASE = 0xD3 ,
SSEQ_CMD_PORTAKEY = 0xC9 ,
SSEQ_CMD_PORTAFLAG = 0xCE ,
SSEQ_CMD_PORTATIME = 0xCF ,
SSEQ_CMD_SWEEPPITCH = 0xE3 ,
SSEQ_CMD_MODDEPTH = 0xCA ,
SSEQ_CMD_MODSPEED = 0xCB ,
SSEQ_CMD_MODTYPE = 0xCC ,
SSEQ_CMD_MODRANGE = 0xCD ,
SSEQ_CMD_MODDELAY = 0xE0 ,
SSEQ_CMD_RANDOM = 0xA0 ,
SSEQ_CMD_PRINTVAR = 0xD6 ,
SSEQ_CMD_IF = 0xA2 ,
2014-11-04 22:56:15 -03:00
SSEQ_CMD_FROMVAR = 0xA1 ,
SSEQ_CMD_SETVAR = 0xB0 ,
SSEQ_CMD_ADDVAR = 0xB1 ,
SSEQ_CMD_SUBVAR = 0xB2 ,
SSEQ_CMD_MULVAR = 0xB3 ,
SSEQ_CMD_DIVVAR = 0xB4 ,
SSEQ_CMD_SHIFTVAR = 0xB5 ,
SSEQ_CMD_RANDVAR = 0xB6 ,
SSEQ_CMD_CMP_EQ = 0xB8 ,
SSEQ_CMD_CMP_GE = 0xB9 ,
SSEQ_CMD_CMP_GT = 0xBA ,
SSEQ_CMD_CMP_LE = 0xBB ,
SSEQ_CMD_CMP_LT = 0xBC ,
SSEQ_CMD_CMP_NE = 0xBD ,
SSEQ_CMD_MUTE = 0xD7 // Unsupported
} ;
static const uint8_t VariableByteCount = 1 < < 7 ;
static const uint8_t ExtraByteOnNoteOrVarOrCmp = 1 < < 6 ;
static inline uint8_t SseqCommandByteCount ( int cmd )
{
if ( cmd < 0x80 )
return 1 | VariableByteCount ;
else
switch ( cmd )
{
case SSEQ_CMD_REST :
case SSEQ_CMD_PATCH :
return VariableByteCount ;
case SSEQ_CMD_PAN :
case SSEQ_CMD_VOL :
case SSEQ_CMD_MASTERVOL :
case SSEQ_CMD_PRIO :
case SSEQ_CMD_NOTEWAIT :
case SSEQ_CMD_TIE :
case SSEQ_CMD_EXPR :
case SSEQ_CMD_LOOPSTART :
case SSEQ_CMD_TRANSPOSE :
case SSEQ_CMD_PITCHBEND :
case SSEQ_CMD_PITCHBENDRANGE :
case SSEQ_CMD_ATTACK :
case SSEQ_CMD_DECAY :
case SSEQ_CMD_SUSTAIN :
case SSEQ_CMD_RELEASE :
case SSEQ_CMD_PORTAKEY :
case SSEQ_CMD_PORTAFLAG :
case SSEQ_CMD_PORTATIME :
case SSEQ_CMD_MODDEPTH :
case SSEQ_CMD_MODSPEED :
case SSEQ_CMD_MODTYPE :
case SSEQ_CMD_MODRANGE :
case SSEQ_CMD_PRINTVAR :
case SSEQ_CMD_MUTE :
return 1 ;
case SSEQ_CMD_ALLOCTRACK :
case SSEQ_CMD_TEMPO :
case SSEQ_CMD_SWEEPPITCH :
case SSEQ_CMD_MODDELAY :
return 2 ;
case SSEQ_CMD_GOTO :
case SSEQ_CMD_CALL :
case SSEQ_CMD_SETVAR :
case SSEQ_CMD_ADDVAR :
case SSEQ_CMD_SUBVAR :
case SSEQ_CMD_MULVAR :
case SSEQ_CMD_DIVVAR :
case SSEQ_CMD_SHIFTVAR :
case SSEQ_CMD_RANDVAR :
case SSEQ_CMD_CMP_EQ :
case SSEQ_CMD_CMP_GE :
case SSEQ_CMD_CMP_GT :
case SSEQ_CMD_CMP_LE :
case SSEQ_CMD_CMP_LT :
case SSEQ_CMD_CMP_NE :
return 3 ;
case SSEQ_CMD_OPENTRACK :
return 4 ;
case SSEQ_CMD_FROMVAR :
return 1 | ExtraByteOnNoteOrVarOrCmp ; // Technically 2 bytes with an additional 1, leaving 1 off because we will be reading it to determine if the additional byte is needed
case SSEQ_CMD_RANDOM :
return 4 | ExtraByteOnNoteOrVarOrCmp ; // Technically 5 bytes with an additional 1, leaving 1 off because we will be reading it to determine if the additional byte is needed
default :
return 0 ;
}
}
static auto varFuncSet = [ ] ( int16_t , int16_t value ) { return value ; } ;
static auto varFuncAdd = [ ] ( int16_t var , int16_t value ) - > int16_t { return var + value ; } ;
static auto varFuncSub = [ ] ( int16_t var , int16_t value ) - > int16_t { return var - value ; } ;
static auto varFuncMul = [ ] ( int16_t var , int16_t value ) - > int16_t { return var * value ; } ;
static auto varFuncDiv = [ ] ( int16_t var , int16_t value ) - > int16_t { return var / value ; } ;
static auto varFuncShift = [ ] ( int16_t var , int16_t value ) - > int16_t
{
if ( value < 0 )
return var > > - value ;
else
return var < < value ;
2013-10-10 21:13:18 -03:00
} ;
2014-11-04 22:56:15 -03:00
static auto varFuncRand = [ ] ( int16_t , int16_t value ) - > int16_t
{
if ( value < 0 )
return - ( std : : rand ( ) % ( - value + 1 ) ) ;
else
return std : : rand ( ) % ( value + 1 ) ;
} ;
static inline std : : function < int16_t ( int16_t , int16_t ) > VarFunc ( int cmd )
{
switch ( cmd )
{
case SSEQ_CMD_SETVAR :
return varFuncSet ;
case SSEQ_CMD_ADDVAR :
return varFuncAdd ;
case SSEQ_CMD_SUBVAR :
return varFuncSub ;
case SSEQ_CMD_MULVAR :
return varFuncMul ;
case SSEQ_CMD_DIVVAR :
return varFuncDiv ;
case SSEQ_CMD_SHIFTVAR :
return varFuncShift ;
case SSEQ_CMD_RANDVAR :
return varFuncRand ;
default :
return nullptr ;
}
}
static auto compareFuncEq = [ ] ( int16_t a , int16_t b ) { return a = = b ; } ;
static auto compareFuncGe = [ ] ( int16_t a , int16_t b ) { return a > = b ; } ;
static auto compareFuncGt = [ ] ( int16_t a , int16_t b ) { return a > b ; } ;
static auto compareFuncLe = [ ] ( int16_t a , int16_t b ) { return a < = b ; } ;
static auto compareFuncLt = [ ] ( int16_t a , int16_t b ) { return a < b ; } ;
static auto compareFuncNe = [ ] ( int16_t a , int16_t b ) { return a ! = b ; } ;
static inline std : : function < bool ( int16_t , int16_t ) > CompareFunc ( int cmd )
{
switch ( cmd )
{
case SSEQ_CMD_CMP_EQ :
return compareFuncEq ;
case SSEQ_CMD_CMP_GE :
return compareFuncGe ;
case SSEQ_CMD_CMP_GT :
return compareFuncGt ;
case SSEQ_CMD_CMP_LE :
return compareFuncLe ;
case SSEQ_CMD_CMP_LT :
return compareFuncLt ;
case SSEQ_CMD_CMP_NE :
return compareFuncNe ;
default :
return nullptr ;
}
}
2013-10-10 21:13:18 -03:00
2014-11-04 22:56:15 -03:00
// Original FSS Function: Track_Run
2013-10-10 21:13:18 -03:00
void Track : : Run ( )
{
// Indicate "heartbeat" for this track
this - > updateFlags . set ( TUF_LEN ) ;
// Exit if the track has already ended
if ( this - > state [ TS_END ] )
return ;
if ( this - > wait )
{
- - this - > wait ;
if ( this - > wait )
return ;
}
auto pData = & this - > pos ;
while ( ! this - > wait )
{
2014-11-04 22:56:15 -03:00
int cmd ;
if ( this - > overriding ( ) )
cmd = this - > overriding . cmd ;
else
cmd = read8 ( pData ) ;
2013-10-10 21:13:18 -03:00
if ( cmd < 0x80 )
{
// Note on
int key = cmd + this - > transpose ;
2014-11-04 22:56:15 -03:00
int vel = this - > overriding . val ( pData , read8 , true ) ;
int len = this - > overriding . val ( pData , readvl ) ;
2013-10-10 21:13:18 -03:00
if ( this - > state [ TS_NOTEWAIT ] )
this - > wait = len ;
if ( this - > state [ TS_TIEBIT ] )
this - > NoteOnTie ( key , vel ) ;
else
this - > NoteOn ( key , vel , len ) ;
}
else
2014-11-04 22:56:15 -03:00
{
int value ;
2013-10-10 21:13:18 -03:00
switch ( cmd )
{
//-----------------------------------------------------------------
// Main commands
//-----------------------------------------------------------------
2014-11-04 22:56:15 -03:00
case SSEQ_CMD_OPENTRACK :
{
int tNum = read8 ( pData ) ;
auto trackPos = & this - > ply - > sseq - > data [ read24 ( pData ) ] ;
int newTrack = this - > ply - > TrackAlloc ( ) ;
if ( newTrack ! = - 1 )
{
this - > ply - > tracks [ newTrack ] . Init ( newTrack , this - > ply , trackPos , tNum ) ;
this - > ply - > trackIds [ this - > ply - > nTracks + + ] = newTrack ;
}
break ;
}
2013-10-10 21:13:18 -03:00
case SSEQ_CMD_REST :
2014-11-04 22:56:15 -03:00
this - > wait = this - > overriding . val ( pData , readvl ) ;
2013-10-10 21:13:18 -03:00
break ;
case SSEQ_CMD_PATCH :
2014-11-04 22:56:15 -03:00
this - > patch = this - > overriding . val ( pData , readvl ) ;
2013-10-10 21:13:18 -03:00
break ;
case SSEQ_CMD_GOTO :
* pData = & this - > ply - > sseq - > data [ read24 ( pData ) ] ;
break ;
case SSEQ_CMD_CALL :
2014-11-04 22:56:15 -03:00
value = read24 ( pData ) ;
if ( this - > stackPos < FSS_TRACKSTACKSIZE )
{
const uint8_t * dest = & this - > ply - > sseq - > data [ value ] ;
this - > stack [ this - > stackPos + + ] = StackValue ( STACKTYPE_CALL , * pData ) ;
* pData = dest ;
}
2013-10-10 21:13:18 -03:00
break ;
case SSEQ_CMD_RET :
2014-11-04 22:56:15 -03:00
if ( this - > stackPos & & this - > stack [ this - > stackPos - 1 ] . type = = STACKTYPE_CALL )
* pData = this - > stack [ - - this - > stackPos ] . dest ;
2013-10-10 21:13:18 -03:00
break ;
case SSEQ_CMD_PAN :
2014-11-04 22:56:15 -03:00
this - > pan = this - > overriding . val ( pData , read8 ) - 64 ;
2013-10-10 21:13:18 -03:00
this - > updateFlags . set ( TUF_PAN ) ;
break ;
case SSEQ_CMD_VOL :
2014-11-04 22:56:15 -03:00
this - > vol = this - > overriding . val ( pData , read8 ) ;
2013-10-10 21:13:18 -03:00
this - > updateFlags . set ( TUF_VOL ) ;
break ;
case SSEQ_CMD_MASTERVOL :
2014-11-04 22:56:15 -03:00
this - > ply - > masterVol = Cnv_Sust ( this - > overriding . val ( pData , read8 ) ) ;
2013-10-10 21:13:18 -03:00
for ( uint8_t i = 0 ; i < this - > ply - > nTracks ; + + i )
this - > ply - > tracks [ this - > ply - > trackIds [ i ] ] . updateFlags . set ( TUF_VOL ) ;
break ;
case SSEQ_CMD_PRIO :
this - > prio = this - > ply - > prio + read8 ( pData ) ;
// Update here?
break ;
case SSEQ_CMD_NOTEWAIT :
this - > state . set ( TS_NOTEWAIT , ! ! read8 ( pData ) ) ;
break ;
case SSEQ_CMD_TIE :
this - > state . set ( TS_TIEBIT , ! ! read8 ( pData ) ) ;
this - > ReleaseAllNotes ( ) ;
break ;
case SSEQ_CMD_EXPR :
2014-11-04 22:56:15 -03:00
this - > expr = this - > overriding . val ( pData , read8 ) ;
2013-10-10 21:13:18 -03:00
this - > updateFlags . set ( TUF_VOL ) ;
break ;
case SSEQ_CMD_TEMPO :
this - > ply - > tempo = read16 ( pData ) ;
break ;
case SSEQ_CMD_END :
this - > state . set ( TS_END ) ;
return ;
case SSEQ_CMD_LOOPSTART :
2014-11-04 22:56:15 -03:00
value = this - > overriding . val ( pData , read8 ) ;
if ( this - > stackPos < FSS_TRACKSTACKSIZE )
{
this - > loopCount [ this - > stackPos ] = value ;
this - > stack [ this - > stackPos + + ] = StackValue ( STACKTYPE_LOOP , * pData ) ;
}
2013-10-10 21:13:18 -03:00
break ;
case SSEQ_CMD_LOOPEND :
2014-11-04 22:56:15 -03:00
if ( this - > stackPos & & this - > stack [ this - > stackPos - 1 ] . type = = STACKTYPE_LOOP )
2013-10-10 21:13:18 -03:00
{
2014-11-04 22:56:15 -03:00
const uint8_t * rPos = this - > stack [ this - > stackPos - 1 ] . dest ;
2013-10-10 21:13:18 -03:00
uint8_t & nR = this - > loopCount [ this - > stackPos - 1 ] ;
uint8_t prevR = nR ;
2014-11-04 22:56:15 -03:00
if ( ! prevR | | - - nR )
* pData = rPos ;
else
2013-10-10 21:13:18 -03:00
- - this - > stackPos ;
}
break ;
//-----------------------------------------------------------------
// Tuning commands
//-----------------------------------------------------------------
case SSEQ_CMD_TRANSPOSE :
2014-11-04 22:56:15 -03:00
this - > transpose = this - > overriding . val ( pData , read8 ) ;
2013-10-10 21:13:18 -03:00
break ;
case SSEQ_CMD_PITCHBEND :
2014-11-04 22:56:15 -03:00
this - > pitchBend = this - > overriding . val ( pData , read8 ) ;
2013-10-10 21:13:18 -03:00
this - > updateFlags . set ( TUF_TIMER ) ;
break ;
case SSEQ_CMD_PITCHBENDRANGE :
this - > pitchBendRange = read8 ( pData ) ;
this - > updateFlags . set ( TUF_TIMER ) ;
break ;
//-----------------------------------------------------------------
// Envelope-related commands
//-----------------------------------------------------------------
case SSEQ_CMD_ATTACK :
2014-11-04 22:56:15 -03:00
this - > a = this - > overriding . val ( pData , read8 ) ;
2013-10-10 21:13:18 -03:00
break ;
case SSEQ_CMD_DECAY :
2014-11-04 22:56:15 -03:00
this - > d = this - > overriding . val ( pData , read8 ) ;
2013-10-10 21:13:18 -03:00
break ;
case SSEQ_CMD_SUSTAIN :
2014-11-04 22:56:15 -03:00
this - > s = this - > overriding . val ( pData , read8 ) ;
2013-10-10 21:13:18 -03:00
break ;
case SSEQ_CMD_RELEASE :
2014-11-04 22:56:15 -03:00
this - > r = this - > overriding . val ( pData , read8 ) ;
2013-10-10 21:13:18 -03:00
break ;
//-----------------------------------------------------------------
// Portamento-related commands
//-----------------------------------------------------------------
case SSEQ_CMD_PORTAKEY :
this - > portaKey = read8 ( pData ) + this - > transpose ;
this - > state . set ( TS_PORTABIT ) ;
// Update here?
break ;
case SSEQ_CMD_PORTAFLAG :
this - > state . set ( TS_PORTABIT , ! ! read8 ( pData ) ) ;
// Update here?
break ;
case SSEQ_CMD_PORTATIME :
2014-11-04 22:56:15 -03:00
this - > portaTime = this - > overriding . val ( pData , read8 ) ;
2021-11-15 02:33:40 -03:00
this - > state . set ( TS_PORTABIT ) ;
2013-10-10 21:13:18 -03:00
// Update here?
break ;
case SSEQ_CMD_SWEEPPITCH :
2014-11-04 22:56:15 -03:00
this - > sweepPitch = this - > overriding . val ( pData , read16 ) ;
2021-11-15 02:33:40 -03:00
this - > state . set ( TS_PORTABIT ) ;
2013-10-10 21:13:18 -03:00
// Update here?
break ;
//-----------------------------------------------------------------
// Modulation-related commands
//-----------------------------------------------------------------
case SSEQ_CMD_MODDEPTH :
2014-11-04 22:56:15 -03:00
this - > modDepth = this - > overriding . val ( pData , read8 ) ;
2013-10-10 21:13:18 -03:00
this - > updateFlags . set ( TUF_MOD ) ;
break ;
case SSEQ_CMD_MODSPEED :
2014-11-04 22:56:15 -03:00
this - > modSpeed = this - > overriding . val ( pData , read8 ) ;
2013-10-10 21:13:18 -03:00
this - > updateFlags . set ( TUF_MOD ) ;
break ;
case SSEQ_CMD_MODTYPE :
this - > modType = read8 ( pData ) ;
this - > updateFlags . set ( TUF_MOD ) ;
break ;
case SSEQ_CMD_MODRANGE :
this - > modRange = read8 ( pData ) ;
this - > updateFlags . set ( TUF_MOD ) ;
break ;
case SSEQ_CMD_MODDELAY :
2014-11-04 22:56:15 -03:00
this - > modDelay = this - > overriding . val ( pData , read16 ) ;
2013-10-10 21:13:18 -03:00
this - > updateFlags . set ( TUF_MOD ) ;
break ;
//-----------------------------------------------------------------
2014-11-04 22:56:15 -03:00
// Randomness-related commands
2013-10-10 21:13:18 -03:00
//-----------------------------------------------------------------
2014-11-04 22:56:15 -03:00
case SSEQ_CMD_RANDOM :
{
this - > overriding ( ) = true ;
this - > overriding . cmd = read8 ( pData ) ;
if ( ( this - > overriding . cmd > = SSEQ_CMD_SETVAR & & this - > overriding . cmd < = SSEQ_CMD_CMP_NE ) | | this - > overriding . cmd < 0x80 )
this - > overriding . extraValue = read8 ( pData ) ;
int16_t minVal = read16 ( pData ) ;
int16_t maxVal = read16 ( pData ) ;
this - > overriding . value = ( std : : rand ( ) % ( maxVal - minVal + 1 ) ) + minVal ;
2013-10-10 21:13:18 -03:00
break ;
2014-11-04 22:56:15 -03:00
}
2013-10-10 21:13:18 -03:00
2014-11-04 22:56:15 -03:00
//-----------------------------------------------------------------
// Variable-related commands
//-----------------------------------------------------------------
case SSEQ_CMD_FROMVAR :
this - > overriding ( ) = true ;
this - > overriding . cmd = read8 ( pData ) ;
if ( ( this - > overriding . cmd > = SSEQ_CMD_SETVAR & & this - > overriding . cmd < = SSEQ_CMD_CMP_NE ) | | this - > overriding . cmd < 0x80 )
this - > overriding . extraValue = read8 ( pData ) ;
this - > overriding . value = this - > ply - > variables [ read8 ( pData ) ] ;
break ;
case SSEQ_CMD_SETVAR :
case SSEQ_CMD_ADDVAR :
case SSEQ_CMD_SUBVAR :
case SSEQ_CMD_MULVAR :
case SSEQ_CMD_DIVVAR :
case SSEQ_CMD_SHIFTVAR :
case SSEQ_CMD_RANDVAR :
{
int8_t varNo = this - > overriding . val ( pData , read8 , true ) ;
value = this - > overriding . val ( pData , read16 ) ;
if ( cmd = = SSEQ_CMD_DIVVAR & & ! value ) // Division by 0, skip it to prevent crashing
2013-10-10 21:13:18 -03:00
break ;
2014-11-04 22:56:15 -03:00
this - > ply - > variables [ varNo ] = VarFunc ( cmd ) ( this - > ply - > variables [ varNo ] , value ) ;
break ;
}
2013-10-10 21:13:18 -03:00
2014-11-04 22:56:15 -03:00
//-----------------------------------------------------------------
// Conditional-related commands
//-----------------------------------------------------------------
case SSEQ_CMD_CMP_EQ :
case SSEQ_CMD_CMP_GE :
case SSEQ_CMD_CMP_GT :
case SSEQ_CMD_CMP_LE :
case SSEQ_CMD_CMP_LT :
case SSEQ_CMD_CMP_NE :
2013-10-10 21:13:18 -03:00
{
2014-11-04 22:56:15 -03:00
int8_t varNo = this - > overriding . val ( pData , read8 , true ) ;
value = this - > overriding . val ( pData , read16 ) ;
this - > lastComparisonResult = CompareFunc ( cmd ) ( this - > ply - > variables [ varNo ] , value ) ;
2013-10-10 21:13:18 -03:00
break ;
}
2014-11-04 22:56:15 -03:00
case SSEQ_CMD_IF :
if ( ! this - > lastComparisonResult )
{
int nextCmd = read8 ( pData ) ;
uint8_t cmdBytes = SseqCommandByteCount ( nextCmd ) ;
bool variableBytes = ! ! ( cmdBytes & VariableByteCount ) ;
bool extraByte = ! ! ( cmdBytes & ExtraByteOnNoteOrVarOrCmp ) ;
cmdBytes & = ~ ( VariableByteCount | ExtraByteOnNoteOrVarOrCmp ) ;
if ( extraByte )
{
int extraCmd = read8 ( pData ) ;
if ( ( extraCmd > = SSEQ_CMD_SETVAR & & extraCmd < = SSEQ_CMD_CMP_NE ) | | extraCmd < 0x80 )
+ + cmdBytes ;
}
* pData + = cmdBytes ;
if ( variableBytes )
readvl ( pData ) ;
}
2013-10-10 21:13:18 -03:00
break ;
default :
2014-11-04 22:56:15 -03:00
* pData + = SseqCommandByteCount ( cmd ) ;
2013-10-10 21:13:18 -03:00
}
2014-11-04 22:56:15 -03:00
}
if ( cmd ! = SSEQ_CMD_RANDOM & & cmd ! = SSEQ_CMD_FROMVAR )
this - > overriding ( ) = false ;
2013-10-10 21:13:18 -03:00
}
}