/* ** Changes for the 1.4 release are commented. You can do ** a search for "1.4" and merge them into your own replay ** code. ** ** Changes for 1.5 are marked also. ** ** ... as are those for 1.6 ** ** ... and for 1.8 */ #include #include #include #include #include "hvl_replay.h" #include "hvl_tables.h" #undef min #define min(a,b) (((a) < (b)) ? (a) : (b)) int8 waves[WAVES_SIZE]; uint32 panning_left[256], panning_right[256]; void hvl_GenPanningTables( void ) { uint32 i; float64 aa, ab; // Sine based panning table aa = (3.14159265f*2.0f)/4.0f; // Quarter of the way through the sinewave == top peak ab = 0.0f; // Start of the climb from zero for( i=0; i<256; i++ ) { panning_left[i] = (uint32)(sin(aa)*255.0f); panning_right[i] = (uint32)(sin(ab)*255.0f); aa += (3.14159265*2.0f/4.0f)/256.0f; ab += (3.14159265*2.0f/4.0f)/256.0f; } panning_left[255] = 0; panning_right[0] = 0; } void hvl_GenSawtooth( int8 *buf, uint32 len ) { uint32 i; int32 val, add; add = 256 / (len-1); val = -128; for( i=0; i> 2; d1 = 128/d5; d4 = -(d2 >> 1); val = 0; for( i=0; i> 16); if (top > 127) in = 127 << 16; else if (top < -128) in = -128 * (1 << 16); return in; } void hvl_GenFilterWaves( int8 *buf, int8 *lowbuf, int8 *highbuf ) { const int16 * mid_table = &filter_thing[0]; const int16 * low_table = &filter_thing[1395]; int32 freq; int32 i; for( i=0, freq = 25; i<31; i++, freq += 9 ) { uint32 wv; int8 *a0 = buf; for( wv=0; wv<6+6+0x20+1; wv++ ) { int32 in, fre, high, mid, low; uint32 j; mid = *mid_table++ << 8; low = *low_table++ << 8; for( j=0; j<=lentab[wv]; j++ ) { in = a0[j] << 16; high = clipshifted8( in - mid - low ); fre = (high >> 8) * freq; mid = clipshifted8(mid + fre); fre = (mid >> 8) * freq; low = clipshifted8(low + fre); *highbuf++ = high >> 16; *lowbuf++ = low >> 16; } a0 += lentab[wv]+1; } } } void hvl_GenWhiteNoise( int8 *buf, uint32 len ) { uint32 ays; ays = 0x41595321; do { uint16 ax, bx; int8 s; s = ays; if( ays & 0x100 ) { s = 0x7F; if( ays & 0x8000 ) s = 0x80; } *buf++ = s; len--; ays = (ays >> 5) | (ays << 27); ays = (ays & 0xffffff00) | ((ays & 0xff) ^ 0x9a); bx = ays; ays = (ays << 2) | (ays >> 30); ax = ays; bx += ax; ax ^= bx; ays = (ays & 0xffff0000) | ax; ays = (ays >> 3) | (ays << 29); } while( len ); } void hvl_reset_some_stuff( struct hvl_tune *ht ) { uint32 i; for( i=0; iht_Voices[i].vc_Delta=~0; ht->ht_Voices[i].vc_OverrideTranspose=1000; // 1.5 ht->ht_Voices[i].vc_SamplePos=ht->ht_Voices[i].vc_Track=ht->ht_Voices[i].vc_Transpose=ht->ht_Voices[i].vc_NextTrack = ht->ht_Voices[i].vc_NextTranspose = 0; ht->ht_Voices[i].vc_ADSRVolume=ht->ht_Voices[i].vc_InstrPeriod=ht->ht_Voices[i].vc_TrackPeriod=ht->ht_Voices[i].vc_VibratoPeriod=ht->ht_Voices[i].vc_NoteMaxVolume=ht->ht_Voices[i].vc_PerfSubVolume=ht->ht_Voices[i].vc_TrackMasterVolume=0; ht->ht_Voices[i].vc_NewWaveform=ht->ht_Voices[i].vc_Waveform=ht->ht_Voices[i].vc_PlantSquare=ht->ht_Voices[i].vc_PlantPeriod=ht->ht_Voices[i].vc_IgnoreSquare=0; ht->ht_Voices[i].vc_TrackOn=ht->ht_Voices[i].vc_FixedNote=ht->ht_Voices[i].vc_VolumeSlideUp=ht->ht_Voices[i].vc_VolumeSlideDown=ht->ht_Voices[i].vc_HardCut=ht->ht_Voices[i].vc_HardCutRelease=ht->ht_Voices[i].vc_HardCutReleaseF=0; ht->ht_Voices[i].vc_PeriodSlideSpeed=ht->ht_Voices[i].vc_PeriodSlidePeriod=ht->ht_Voices[i].vc_PeriodSlideLimit=ht->ht_Voices[i].vc_PeriodSlideOn=ht->ht_Voices[i].vc_PeriodSlideWithLimit=0; ht->ht_Voices[i].vc_PeriodPerfSlideSpeed=ht->ht_Voices[i].vc_PeriodPerfSlidePeriod=ht->ht_Voices[i].vc_PeriodPerfSlideOn=ht->ht_Voices[i].vc_VibratoDelay=ht->ht_Voices[i].vc_VibratoCurrent=ht->ht_Voices[i].vc_VibratoDepth=ht->ht_Voices[i].vc_VibratoSpeed=0; ht->ht_Voices[i].vc_SquareOn=ht->ht_Voices[i].vc_SquareInit=ht->ht_Voices[i].vc_SquareLowerLimit=ht->ht_Voices[i].vc_SquareUpperLimit=ht->ht_Voices[i].vc_SquarePos=ht->ht_Voices[i].vc_SquareSign=ht->ht_Voices[i].vc_SquareSlidingIn=ht->ht_Voices[i].vc_SquareReverse=0; ht->ht_Voices[i].vc_FilterOn=ht->ht_Voices[i].vc_FilterInit=ht->ht_Voices[i].vc_FilterLowerLimit=ht->ht_Voices[i].vc_FilterUpperLimit=ht->ht_Voices[i].vc_FilterPos=ht->ht_Voices[i].vc_FilterSign=ht->ht_Voices[i].vc_FilterSpeed=ht->ht_Voices[i].vc_FilterSlidingIn=ht->ht_Voices[i].vc_IgnoreFilter=0; ht->ht_Voices[i].vc_PerfCurrent=ht->ht_Voices[i].vc_PerfSpeed=ht->ht_Voices[i].vc_WaveLength=ht->ht_Voices[i].vc_NoteDelayOn=ht->ht_Voices[i].vc_NoteCutOn=0; ht->ht_Voices[i].vc_AudioPeriod=ht->ht_Voices[i].vc_AudioVolume=ht->ht_Voices[i].vc_VoiceVolume=ht->ht_Voices[i].vc_VoicePeriod=ht->ht_Voices[i].vc_VoiceNum=ht->ht_Voices[i].vc_WNRandom=0; ht->ht_Voices[i].vc_SquareWait=ht->ht_Voices[i].vc_FilterWait=ht->ht_Voices[i].vc_PerfWait=ht->ht_Voices[i].vc_NoteDelayWait=ht->ht_Voices[i].vc_NoteCutWait=0; ht->ht_Voices[i].vc_PerfList=0; ht->ht_Voices[i].vc_RingSamplePos=ht->ht_Voices[i].vc_RingDelta=ht->ht_Voices[i].vc_RingPlantPeriod=ht->ht_Voices[i].vc_RingAudioPeriod=ht->ht_Voices[i].vc_RingNewWaveform=ht->ht_Voices[i].vc_RingWaveform=ht->ht_Voices[i].vc_RingFixedPeriod=ht->ht_Voices[i].vc_RingBasePeriod=0; ht->ht_Voices[i].vc_RingMixSource = NULL; ht->ht_Voices[i].vc_RingAudioSource = NULL; memset(&ht->ht_Voices[i].vc_SquareTempBuffer,0,0x80); memset(&ht->ht_Voices[i].vc_ADSR,0,sizeof(struct hvl_envelope)); memset(&ht->ht_Voices[i].vc_VoiceBuffer,0,0x281); memset(&ht->ht_Voices[i].vc_RingVoiceBuffer,0,0x281); } for( i=0; iht_Voices[i].vc_WNRandom = 0x280; ht->ht_Voices[i].vc_VoiceNum = i; ht->ht_Voices[i].vc_TrackMasterVolume = 0x40; ht->ht_Voices[i].vc_TrackOn = 1; ht->ht_Voices[i].vc_MixSource = ht->ht_Voices[i].vc_VoiceBuffer; ht->ht_Voices[i].vc_LastAmp[0] = 0; ht->ht_Voices[i].vc_LastAmp[1] = 0; ht->ht_Voices[i].vc_LastClock[0] = 0; ht->ht_Voices[i].vc_LastClock[1] = 0; } hvl_blip_clear(ht->ht_BlipBuffers[0]); hvl_blip_clear(ht->ht_BlipBuffers[1]); } BOOL hvl_InitSubsong( struct hvl_tune *ht, uint32 nr ) { uint32 PosNr, i; if( nr > ht->ht_SubsongNr ) return FALSE; ht->ht_SongNum = nr; PosNr = 0; if( nr ) PosNr = ht->ht_Subsongs[nr-1]; ht->ht_PosNr = PosNr; ht->ht_PosJump = 0; ht->ht_PatternBreak = 0; ht->ht_NoteNr = 0; ht->ht_PosJumpNote = 0; ht->ht_Tempo = 6; ht->ht_StepWaitFrames = 0; ht->ht_GetNewPosition = 1; ht->ht_SongEndReached = 0; ht->ht_PlayingTime = 0; for( i=0; iht_Voices[i+0].vc_Pan = ht->ht_defpanleft; ht->ht_Voices[i+0].vc_SetPan = ht->ht_defpanleft; // 1.4 ht->ht_Voices[i+0].vc_PanMultLeft = panning_left[ht->ht_defpanleft]; ht->ht_Voices[i+0].vc_PanMultRight = panning_right[ht->ht_defpanleft]; ht->ht_Voices[i+1].vc_Pan = ht->ht_defpanright; ht->ht_Voices[i+1].vc_SetPan = ht->ht_defpanright; // 1.4 ht->ht_Voices[i+1].vc_PanMultLeft = panning_left[ht->ht_defpanright]; ht->ht_Voices[i+1].vc_PanMultRight = panning_right[ht->ht_defpanright]; ht->ht_Voices[i+2].vc_Pan = ht->ht_defpanright; ht->ht_Voices[i+2].vc_SetPan = ht->ht_defpanright; // 1.4 ht->ht_Voices[i+2].vc_PanMultLeft = panning_left[ht->ht_defpanright]; ht->ht_Voices[i+2].vc_PanMultRight = panning_right[ht->ht_defpanright]; ht->ht_Voices[i+3].vc_Pan = ht->ht_defpanleft; ht->ht_Voices[i+3].vc_SetPan = ht->ht_defpanleft; // 1.4 ht->ht_Voices[i+3].vc_PanMultLeft = panning_left[ht->ht_defpanleft]; ht->ht_Voices[i+3].vc_PanMultRight = panning_right[ht->ht_defpanleft]; } hvl_reset_some_stuff( ht ); return TRUE; } void hvl_InitReplayer( void ) { hvl_GenPanningTables(); hvl_GenSawtooth( &waves[WO_SAWTOOTH_04], 0x04 ); hvl_GenSawtooth( &waves[WO_SAWTOOTH_08], 0x08 ); hvl_GenSawtooth( &waves[WO_SAWTOOTH_10], 0x10 ); hvl_GenSawtooth( &waves[WO_SAWTOOTH_20], 0x20 ); hvl_GenSawtooth( &waves[WO_SAWTOOTH_40], 0x40 ); hvl_GenSawtooth( &waves[WO_SAWTOOTH_80], 0x80 ); hvl_GenTriangle( &waves[WO_TRIANGLE_04], 0x04 ); hvl_GenTriangle( &waves[WO_TRIANGLE_08], 0x08 ); hvl_GenTriangle( &waves[WO_TRIANGLE_10], 0x10 ); hvl_GenTriangle( &waves[WO_TRIANGLE_20], 0x20 ); hvl_GenTriangle( &waves[WO_TRIANGLE_40], 0x40 ); hvl_GenTriangle( &waves[WO_TRIANGLE_80], 0x80 ); hvl_GenSquare( &waves[WO_SQUARES] ); hvl_GenWhiteNoise( &waves[WO_WHITENOISE], WHITENOISELEN ); hvl_GenFilterWaves( &waves[WO_TRIANGLE_04], &waves[WO_LOWPASSES], &waves[WO_HIGHPASSES] ); } struct hvl_tune *hvl_load_ahx( const uint8 *buf, uint32 buflen, uint32 defstereo, uint32 freq ) { const uint8 *bptr; const TEXT *nptr; uint32 i, j, k, l, posn, insn, ssn, hs, trkn, trkl; struct hvl_tune *ht; struct hvl_plsentry *ple; int32 defgain[] = { 71, 72, 76, 85, 100 }; if ( buflen < 14 ) return NULL; posn = ((buf[6]&0x0f)<<8)|buf[7]; insn = buf[12]; ssn = buf[13]; trkl = buf[10]; trkn = buf[11]; hs = sizeof( struct hvl_tune ); hs += sizeof( struct hvl_position ) * posn; hs += sizeof( struct hvl_instrument ) * (insn+1); hs += sizeof( uint16 ) * ssn; hs += hvl_blip_size( 256 ) * 2; // Calculate the size of all instrument PList buffers bptr = &buf[14]; bptr += ssn*2; // Skip past the subsong list bptr += posn*4*2; // Skip past the positions bptr += trkn*trkl*3; if((buf[6]&0x80)==0) bptr += trkl*3; // *NOW* we can finally calculate PList space for( i=1; i<=insn; i++ ) { if ( bptr + 21 > buf + buflen ) return NULL; hs += bptr[21] * sizeof( struct hvl_plsentry ); bptr += 22 + bptr[21]*4; } ht = malloc( hs ); if( !ht ) { return NULL; } ht->ht_Frequency = freq; ht->ht_FreqF = (float64)freq; ht->ht_Positions = (struct hvl_position *)(&ht[1]); ht->ht_Instruments = (struct hvl_instrument *)(&ht->ht_Positions[posn]); ht->ht_Subsongs = (uint16 *)(&ht->ht_Instruments[(insn+1)]); ht->ht_BlipBuffers[0] = (hvl_blip_t *)(&ht->ht_Subsongs[ssn]); ht->ht_BlipBuffers[1] = (hvl_blip_t *)((uint8 *)(ht->ht_BlipBuffers[0]) + hvl_blip_size(256)); ple = (struct hvl_plsentry *)(((uint8 *)ht->ht_BlipBuffers[1]) + hvl_blip_size(256)); hvl_blip_new_inplace(ht->ht_BlipBuffers[0], 256); hvl_blip_new_inplace(ht->ht_BlipBuffers[1], 256); hvl_blip_set_rates(ht->ht_BlipBuffers[0], 65536, 1); hvl_blip_set_rates(ht->ht_BlipBuffers[1], 65536, 1); ht->ht_WaveformTab[0] = &waves[WO_TRIANGLE_04]; ht->ht_WaveformTab[1] = &waves[WO_SAWTOOTH_04]; ht->ht_WaveformTab[3] = &waves[WO_WHITENOISE]; ht->ht_Channels = 4; ht->ht_PositionNr = posn; ht->ht_Restart = (buf[8]<<8)|buf[9]; ht->ht_SpeedMultiplier = ((buf[6]>>5)&3)+1; ht->ht_TrackLength = trkl; ht->ht_TrackNr = trkn; ht->ht_InstrumentNr = insn; ht->ht_SubsongNr = ssn; ht->ht_defstereo = defstereo; ht->ht_defpanleft = stereopan_left[ht->ht_defstereo]; ht->ht_defpanright = stereopan_right[ht->ht_defstereo]; ht->ht_mixgain = (defgain[ht->ht_defstereo]*256)/100; if( ht->ht_Restart >= ht->ht_PositionNr ) ht->ht_Restart = ht->ht_PositionNr-1; // Do some validation if( ( ht->ht_PositionNr > 1000 ) || ( ht->ht_TrackLength > 64 ) || ( ht->ht_InstrumentNr > 64 ) ) { free( ht ); return NULL; } bptr = &buf[(buf[4]<<8)|buf[5]]; i = min( 128, (uint32) (buf + buflen - bptr) ); strncpy( ht->ht_Name, (TEXT *)bptr, i ); if ( i < 128 ) ht->ht_Name[ i ] = 0; nptr = (TEXT *)bptr+strlen( ht->ht_Name )+1; if ( (uint8*) nptr > buf + buflen ) { free( ht ); return NULL; } bptr = &buf[14]; // Subsongs for( i=0; iht_SubsongNr; i++ ) { ht->ht_Subsongs[i] = (bptr[0]<<8)|bptr[1]; if( ht->ht_Subsongs[i] >= ht->ht_PositionNr ) ht->ht_Subsongs[i] = 0; bptr += 2; } // Position list for( i=0; iht_PositionNr; i++ ) { for( j=0; j<4; j++ ) { ht->ht_Positions[i].pos_Track[j] = *bptr++; ht->ht_Positions[i].pos_Transpose[j] = *(int8 *)bptr++; } } // Tracks for( i=0; i<=ht->ht_TrackNr; i++ ) { if( ( ( buf[6]&0x80 ) == 0x80 ) && ( i == 0 ) ) { for( j=0; jht_TrackLength; j++ ) { ht->ht_Tracks[i][j].stp_Note = 0; ht->ht_Tracks[i][j].stp_Instrument = 0; ht->ht_Tracks[i][j].stp_FX = 0; ht->ht_Tracks[i][j].stp_FXParam = 0; ht->ht_Tracks[i][j].stp_FXb = 0; ht->ht_Tracks[i][j].stp_FXbParam = 0; } continue; } for( j=0; jht_TrackLength; j++ ) { ht->ht_Tracks[i][j].stp_Note = (bptr[0]>>2)&0x3f; ht->ht_Tracks[i][j].stp_Instrument = ((bptr[0]&0x3)<<4) | (bptr[1]>>4); ht->ht_Tracks[i][j].stp_FX = bptr[1]&0xf; ht->ht_Tracks[i][j].stp_FXParam = bptr[2]; ht->ht_Tracks[i][j].stp_FXb = 0; ht->ht_Tracks[i][j].stp_FXbParam = 0; bptr += 3; } } // Instruments for( i=1; i<=ht->ht_InstrumentNr; i++ ) { if( nptr < (TEXT *)(buf+buflen) ) { strncpy( ht->ht_Instruments[i].ins_Name, nptr, 128 ); nptr += strlen( nptr )+1; } else { ht->ht_Instruments[i].ins_Name[0] = 0; } ht->ht_Instruments[i].ins_Volume = bptr[0]; ht->ht_Instruments[i].ins_FilterSpeed = ((bptr[1]>>3)&0x1f)|((bptr[12]>>2)&0x20); ht->ht_Instruments[i].ins_WaveLength = bptr[1]&0x07; ht->ht_Instruments[i].ins_Envelope.aFrames = bptr[2]; ht->ht_Instruments[i].ins_Envelope.aVolume = bptr[3]; ht->ht_Instruments[i].ins_Envelope.dFrames = bptr[4]; ht->ht_Instruments[i].ins_Envelope.dVolume = bptr[5]; ht->ht_Instruments[i].ins_Envelope.sFrames = bptr[6]; ht->ht_Instruments[i].ins_Envelope.rFrames = bptr[7]; ht->ht_Instruments[i].ins_Envelope.rVolume = bptr[8]; ht->ht_Instruments[i].ins_FilterLowerLimit = bptr[12]&0x7f; ht->ht_Instruments[i].ins_VibratoDelay = bptr[13]; ht->ht_Instruments[i].ins_HardCutReleaseFrames = (bptr[14]>>4)&0x07; ht->ht_Instruments[i].ins_HardCutRelease = bptr[14]&0x80?1:0; ht->ht_Instruments[i].ins_VibratoDepth = bptr[14]&0x0f; ht->ht_Instruments[i].ins_VibratoSpeed = bptr[15]; ht->ht_Instruments[i].ins_SquareLowerLimit = bptr[16]; ht->ht_Instruments[i].ins_SquareUpperLimit = bptr[17]; ht->ht_Instruments[i].ins_SquareSpeed = bptr[18]; ht->ht_Instruments[i].ins_FilterUpperLimit = bptr[19]&0x3f; ht->ht_Instruments[i].ins_PList.pls_Speed = bptr[20]; ht->ht_Instruments[i].ins_PList.pls_Length = bptr[21]; ht->ht_Instruments[i].ins_PList.pls_Entries = ple; ple += bptr[21]; bptr += 22; for( j=0; jht_Instruments[i].ins_PList.pls_Length; j++ ) { k = (bptr[0]>>5)&7; if( k == 6 ) k = 12; if( k == 7 ) k = 15; l = (bptr[0]>>2)&7; if( l == 6 ) l = 12; if( l == 7 ) l = 15; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_FX[1] = k; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_FX[0] = l; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_Waveform = ((bptr[0]<<1)&6) | (bptr[1]>>7); ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_Fixed = (bptr[1]>>6)&1; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_Note = bptr[1]&0x3f; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_FXParam[0] = bptr[2]; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_FXParam[1] = bptr[3]; // 1.6: Strip "toggle filter" commands if the module is // version 0 (pre-filters). This is what AHX also does. if( ( buf[3] == 0 ) && ( l == 4 ) && ( (bptr[2]&0xf0) != 0 ) ) ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_FXParam[0] &= 0x0f; if( ( buf[3] == 0 ) && ( k == 4 ) && ( (bptr[3]&0xf0) != 0 ) ) ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_FXParam[1] &= 0x0f; // 1.8 bptr += 4; } } hvl_InitSubsong( ht, 0 ); return ht; } struct hvl_tune *hvl_LoadTune( const uint8 *buf, uint32 buflen, uint32 freq, uint32 defstereo ) { struct hvl_tune *ht; const uint8 *bptr; const TEXT *nptr; uint32 i, j, posn, insn, ssn, chnn, hs, trkl, trkn; struct hvl_plsentry *ple; if ( !buf || buflen < 4 ) return NULL; if( ( buf[0] == 'T' ) && ( buf[1] == 'H' ) && ( buf[2] == 'X' ) && ( buf[3] < 3 ) ) return hvl_load_ahx( buf, buflen, defstereo, freq ); if( ( buf[0] != 'H' ) || ( buf[1] != 'V' ) || ( buf[2] != 'L' ) || ( buf[3] > 1 ) ) { return NULL; } if ( buflen < 14 ) return NULL; posn = ((buf[6]&0x0f)<<8)|buf[7]; insn = buf[12]; ssn = buf[13]; chnn = (buf[8]>>2)+4; trkl = buf[10]; trkn = buf[11]; hs = sizeof( struct hvl_tune ); hs += sizeof( struct hvl_position ) * posn; hs += sizeof( struct hvl_instrument ) * (insn+1); hs += sizeof( uint16 ) * ssn; hs += hvl_blip_size(256) * 2; // Calculate the size of all instrument PList buffers bptr = &buf[16]; bptr += ssn*2; // Skip past the subsong list bptr += posn*chnn*2; // Skip past the positions // Skip past the tracks // 1.4: Fixed two really stupid bugs that cancelled each other // out if the module had a blank first track (which is how // come they were missed. for( i=((buf[6]&0x80)==0x80)?1:0; i<=trkn; i++ ) for( j=0; j buf + buflen ) return NULL; if( bptr[0] == 0x3f ) { bptr++; continue; } bptr += 5; } // *NOW* we can finally calculate PList space for( i=1; i<=insn; i++ ) { if ( bptr + 21 > buf + buflen ) return NULL; hs += bptr[21] * sizeof( struct hvl_plsentry ); bptr += 22 + bptr[21]*5; } ht = malloc( hs ); if( !ht ) { return NULL; } ht->ht_Version = buf[3]; // 1.5 ht->ht_Frequency = freq; ht->ht_FreqF = (float64)freq; ht->ht_Positions = (struct hvl_position *)(&ht[1]); ht->ht_Instruments = (struct hvl_instrument *)(&ht->ht_Positions[posn]); ht->ht_Subsongs = (uint16 *)(&ht->ht_Instruments[(insn+1)]); ht->ht_BlipBuffers[0] = (hvl_blip_t *)(&ht->ht_Subsongs[ssn]); ht->ht_BlipBuffers[1] = (hvl_blip_t *)(((uint8 *)ht->ht_BlipBuffers[0]) + hvl_blip_size(256)); ple = (struct hvl_plsentry *)(((uint8 *)ht->ht_BlipBuffers[1]) + hvl_blip_size(256)); hvl_blip_new_inplace(ht->ht_BlipBuffers[0], 256); hvl_blip_new_inplace(ht->ht_BlipBuffers[1], 256); hvl_blip_set_rates(ht->ht_BlipBuffers[0], 65536, 1); hvl_blip_set_rates(ht->ht_BlipBuffers[1], 65536, 1); ht->ht_WaveformTab[0] = &waves[WO_TRIANGLE_04]; ht->ht_WaveformTab[1] = &waves[WO_SAWTOOTH_04]; ht->ht_WaveformTab[3] = &waves[WO_WHITENOISE]; ht->ht_PositionNr = posn; ht->ht_Channels = (buf[8]>>2)+4; ht->ht_Restart = ((buf[8]&3)<<8)|buf[9]; ht->ht_SpeedMultiplier = ((buf[6]>>5)&3)+1; ht->ht_TrackLength = buf[10]; ht->ht_TrackNr = buf[11]; ht->ht_InstrumentNr = insn; ht->ht_SubsongNr = ssn; ht->ht_mixgain = (buf[14]<<8)/100; ht->ht_defstereo = buf[15]; ht->ht_defpanleft = stereopan_left[ht->ht_defstereo]; ht->ht_defpanright = stereopan_right[ht->ht_defstereo]; if( ht->ht_Restart >= ht->ht_PositionNr ) ht->ht_Restart = ht->ht_PositionNr-1; // Do some validation if( ( ht->ht_PositionNr > 1000 ) || ( ht->ht_TrackLength > 64 ) || ( ht->ht_InstrumentNr > 64 ) ) { free( ht ); return NULL; } bptr = &buf[(buf[4]<<8)|buf[5]]; if ( bptr > buf + buflen ) { free( ht ); return NULL; } i = min( 128, (uint32) (buf + buflen - bptr) ); strncpy( ht->ht_Name, (TEXT *)bptr, i ); if ( i < 128 ) ht->ht_Name[ i ] = 0; nptr = (TEXT *)bptr+strlen( ht->ht_Name )+1; if ( (uint8 *)nptr > buf + buflen ) { free( ht ); return NULL; } bptr = &buf[16]; // Subsongs for( i=0; iht_SubsongNr; i++ ) { ht->ht_Subsongs[i] = (bptr[0]<<8)|bptr[1]; bptr += 2; } // Position list for( i=0; iht_PositionNr; i++ ) { for( j=0; jht_Channels; j++ ) { ht->ht_Positions[i].pos_Track[j] = *bptr++; ht->ht_Positions[i].pos_Transpose[j] = *(int8 *)bptr++; } } // Tracks for( i=0; i<=ht->ht_TrackNr; i++ ) { if( ( ( buf[6]&0x80 ) == 0x80 ) && ( i == 0 ) ) { for( j=0; jht_TrackLength; j++ ) { ht->ht_Tracks[i][j].stp_Note = 0; ht->ht_Tracks[i][j].stp_Instrument = 0; ht->ht_Tracks[i][j].stp_FX = 0; ht->ht_Tracks[i][j].stp_FXParam = 0; ht->ht_Tracks[i][j].stp_FXb = 0; ht->ht_Tracks[i][j].stp_FXbParam = 0; } continue; } for( j=0; jht_TrackLength; j++ ) { if( bptr[0] == 0x3f ) { ht->ht_Tracks[i][j].stp_Note = 0; ht->ht_Tracks[i][j].stp_Instrument = 0; ht->ht_Tracks[i][j].stp_FX = 0; ht->ht_Tracks[i][j].stp_FXParam = 0; ht->ht_Tracks[i][j].stp_FXb = 0; ht->ht_Tracks[i][j].stp_FXbParam = 0; bptr++; continue; } ht->ht_Tracks[i][j].stp_Note = bptr[0]; ht->ht_Tracks[i][j].stp_Instrument = bptr[1]; ht->ht_Tracks[i][j].stp_FX = bptr[2]>>4; ht->ht_Tracks[i][j].stp_FXParam = bptr[3]; ht->ht_Tracks[i][j].stp_FXb = bptr[2]&0xf; ht->ht_Tracks[i][j].stp_FXbParam = bptr[4]; bptr += 5; } } // Instruments for( i=1; i<=ht->ht_InstrumentNr; i++ ) { if( nptr < (TEXT *)(buf+buflen) ) { strncpy( ht->ht_Instruments[i].ins_Name, nptr, 128 ); nptr += strlen( nptr )+1; } else { ht->ht_Instruments[i].ins_Name[0] = 0; } ht->ht_Instruments[i].ins_Volume = bptr[0]; ht->ht_Instruments[i].ins_FilterSpeed = ((bptr[1]>>3)&0x1f)|((bptr[12]>>2)&0x20); ht->ht_Instruments[i].ins_WaveLength = bptr[1]&0x07; ht->ht_Instruments[i].ins_Envelope.aFrames = bptr[2]; ht->ht_Instruments[i].ins_Envelope.aVolume = bptr[3]; ht->ht_Instruments[i].ins_Envelope.dFrames = bptr[4]; ht->ht_Instruments[i].ins_Envelope.dVolume = bptr[5]; ht->ht_Instruments[i].ins_Envelope.sFrames = bptr[6]; ht->ht_Instruments[i].ins_Envelope.rFrames = bptr[7]; ht->ht_Instruments[i].ins_Envelope.rVolume = bptr[8]; ht->ht_Instruments[i].ins_FilterLowerLimit = bptr[12]&0x7f; ht->ht_Instruments[i].ins_VibratoDelay = bptr[13]; ht->ht_Instruments[i].ins_HardCutReleaseFrames = (bptr[14]>>4)&0x07; ht->ht_Instruments[i].ins_HardCutRelease = bptr[14]&0x80?1:0; ht->ht_Instruments[i].ins_VibratoDepth = bptr[14]&0x0f; ht->ht_Instruments[i].ins_VibratoSpeed = bptr[15]; ht->ht_Instruments[i].ins_SquareLowerLimit = bptr[16]; ht->ht_Instruments[i].ins_SquareUpperLimit = bptr[17]; ht->ht_Instruments[i].ins_SquareSpeed = bptr[18]; ht->ht_Instruments[i].ins_FilterUpperLimit = bptr[19]&0x3f; ht->ht_Instruments[i].ins_PList.pls_Speed = bptr[20]; ht->ht_Instruments[i].ins_PList.pls_Length = bptr[21]; ht->ht_Instruments[i].ins_PList.pls_Entries = ple; ple += bptr[21]; bptr += 22; for( j=0; jht_Instruments[i].ins_PList.pls_Length; j++ ) { ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_FX[0] = bptr[0]&0xf; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_FX[1] = (bptr[1]>>3)&0xf; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_Waveform = bptr[1]&7; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_Fixed = (bptr[2]>>6)&1; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_Note = bptr[2]&0x3f; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_FXParam[0] = bptr[3]; ht->ht_Instruments[i].ins_PList.pls_Entries[j].ple_FXParam[1] = bptr[4]; bptr += 5; } } hvl_InitSubsong( ht, 0 ); return ht; } void hvl_FreeTune( struct hvl_tune *ht ) { if( !ht ) return; free( ht ); } void hvl_process_stepfx_1( struct hvl_tune *ht, struct hvl_voice *voice, int32 FX, int32 FXParam ) { switch( FX ) { case 0x0: // Position Jump HI if( ((FXParam&0x0f) > 0) && ((FXParam&0x0f) <= 9) ) ht->ht_PosJump = FXParam & 0xf; break; case 0x5: // Volume Slide + Tone Portamento case 0xa: // Volume Slide voice->vc_VolumeSlideDown = FXParam & 0x0f; voice->vc_VolumeSlideUp = FXParam >> 4; break; case 0x7: // Panning if( FXParam > 127 ) FXParam -= 256; voice->vc_Pan = (FXParam+128); voice->vc_SetPan = (FXParam+128); // 1.4 voice->vc_PanMultLeft = panning_left[voice->vc_Pan]; voice->vc_PanMultRight = panning_right[voice->vc_Pan]; break; case 0xb: // Position jump ht->ht_PosJump = ht->ht_PosJump*100 + (FXParam & 0x0f) + (FXParam >> 4)*10; ht->ht_PatternBreak = 1; if( ht->ht_PosJump <= ht->ht_PosNr ) ht->ht_SongEndReached = 1; break; case 0xd: // Pattern break ht->ht_PosJump = ht->ht_PosNr+1; ht->ht_PosJumpNote = (FXParam & 0x0f) + (FXParam>>4)*10; ht->ht_PatternBreak = 1; if( ht->ht_PosJumpNote > ht->ht_TrackLength ) ht->ht_PosJumpNote = 0; break; case 0xe: // Extended commands switch( FXParam >> 4 ) { case 0xc: // Note cut if( (FXParam & 0x0f) < ht->ht_Tempo ) { voice->vc_NoteCutWait = FXParam & 0x0f; if( voice->vc_NoteCutWait ) { voice->vc_NoteCutOn = 1; voice->vc_HardCutRelease = 0; } } break; // 1.6: 0xd case removed } break; case 0xf: // Speed ht->ht_Tempo = FXParam; if( FXParam == 0 ) ht->ht_SongEndReached = 1; break; } } void hvl_process_stepfx_2( struct hvl_tune *ht, struct hvl_voice *voice, int32 FX, int32 FXParam, int32 *Note ) { switch( FX ) { case 0x9: // Set squarewave offset voice->vc_SquarePos = FXParam >> (5 - voice->vc_WaveLength); // voice->vc_PlantSquare = 1; voice->vc_IgnoreSquare = 1; break; case 0x3: // Tone portamento if( FXParam != 0 ) voice->vc_PeriodSlideSpeed = FXParam; case 0x5: // Tone portamento + volume slide if( *Note ) { int32 new, diff; new = period_tab[*Note]; diff = period_tab[voice->vc_TrackPeriod]; diff -= new; new = diff + voice->vc_PeriodSlidePeriod; if( new ) voice->vc_PeriodSlideLimit = -diff; } voice->vc_PeriodSlideOn = 1; voice->vc_PeriodSlideWithLimit = 1; *Note = 0; break; } } void hvl_process_stepfx_3( struct hvl_tune *ht, struct hvl_voice *voice, int32 FX, int32 FXParam ) { int32 i; switch( FX ) { case 0x01: // Portamento up (period slide down) voice->vc_PeriodSlideSpeed = -FXParam; voice->vc_PeriodSlideOn = 1; voice->vc_PeriodSlideWithLimit = 0; break; case 0x02: // Portamento down voice->vc_PeriodSlideSpeed = FXParam; voice->vc_PeriodSlideOn = 1; voice->vc_PeriodSlideWithLimit = 0; break; case 0x04: // Filter override if( ( FXParam == 0 ) || ( FXParam == 0x40 ) ) break; if( FXParam < 0x40 ) { voice->vc_IgnoreFilter = FXParam; break; } if( FXParam > 0x7f ) break; voice->vc_FilterPos = FXParam - 0x40; break; case 0x0c: // Volume FXParam &= 0xff; if( FXParam <= 0x40 ) { voice->vc_NoteMaxVolume = FXParam; break; } if( (FXParam -= 0x50) < 0 ) break; // 1.6 if( FXParam <= 0x40 ) { for( i=0; iht_Channels; i++ ) ht->ht_Voices[i].vc_TrackMasterVolume = FXParam; break; } if( (FXParam -= 0xa0-0x50) < 0 ) break; // 1.6 if( FXParam <= 0x40 ) voice->vc_TrackMasterVolume = FXParam; break; case 0xe: // Extended commands; switch( FXParam >> 4 ) { case 0x1: // Fineslide up voice->vc_PeriodSlidePeriod -= (FXParam & 0x0f); // 1.8 voice->vc_PlantPeriod = 1; break; case 0x2: // Fineslide down voice->vc_PeriodSlidePeriod += (FXParam & 0x0f); // 1.8 voice->vc_PlantPeriod = 1; break; case 0x4: // Vibrato control voice->vc_VibratoDepth = FXParam & 0x0f; break; case 0x0a: // Fine volume up voice->vc_NoteMaxVolume += FXParam & 0x0f; if( voice->vc_NoteMaxVolume > 0x40 ) voice->vc_NoteMaxVolume = 0x40; break; case 0x0b: // Fine volume down voice->vc_NoteMaxVolume -= FXParam & 0x0f; if( voice->vc_NoteMaxVolume < 0 ) voice->vc_NoteMaxVolume = 0; break; case 0x0f: // Misc flags (1.5) if( ht->ht_Version < 1 ) break; switch( FXParam & 0xf ) { case 1: voice->vc_OverrideTranspose = voice->vc_Transpose; break; } break; } break; } } void hvl_process_step( struct hvl_tune *ht, struct hvl_voice *voice ) { int32 Note, Instr, donenotedel; struct hvl_step *Step; if( voice->vc_TrackOn == 0 ) return; voice->vc_VolumeSlideUp = voice->vc_VolumeSlideDown = 0; Step = &ht->ht_Tracks[ht->ht_Positions[ht->ht_PosNr].pos_Track[voice->vc_VoiceNum]][ht->ht_NoteNr]; Note = Step->stp_Note; Instr = Step->stp_Instrument; // --------- 1.6: from here -------------- donenotedel = 0; // Do notedelay here if( ((Step->stp_FX&0xf)==0xe) && ((Step->stp_FXParam&0xf0)==0xd0) ) { if( voice->vc_NoteDelayOn ) { voice->vc_NoteDelayOn = 0; donenotedel = 1; } else { if( (Step->stp_FXParam&0x0f) < ht->ht_Tempo ) { voice->vc_NoteDelayWait = Step->stp_FXParam & 0x0f; if( voice->vc_NoteDelayWait ) { voice->vc_NoteDelayOn = 1; return; } } } } if( (donenotedel==0) && ((Step->stp_FXb&0xf)==0xe) && ((Step->stp_FXbParam&0xf0)==0xd0) ) { if( voice->vc_NoteDelayOn ) { voice->vc_NoteDelayOn = 0; } else { if( (Step->stp_FXbParam&0x0f) < ht->ht_Tempo ) { voice->vc_NoteDelayWait = Step->stp_FXbParam & 0x0f; if( voice->vc_NoteDelayWait ) { voice->vc_NoteDelayOn = 1; return; } } } } // --------- 1.6: to here -------------- if( Note ) voice->vc_OverrideTranspose = 1000; // 1.5 hvl_process_stepfx_1( ht, voice, Step->stp_FX&0xf, Step->stp_FXParam ); hvl_process_stepfx_1( ht, voice, Step->stp_FXb&0xf, Step->stp_FXbParam ); if( ( Instr ) && ( Instr <= ht->ht_InstrumentNr ) ) { struct hvl_instrument *Ins; int16 SquareLower, SquareUpper, d6, d3, d4; /* 1.4: Reset panning to last set position */ voice->vc_Pan = voice->vc_SetPan; voice->vc_PanMultLeft = panning_left[voice->vc_Pan]; voice->vc_PanMultRight = panning_right[voice->vc_Pan]; voice->vc_PeriodSlideSpeed = voice->vc_PeriodSlidePeriod = voice->vc_PeriodSlideLimit = 0; voice->vc_PerfSubVolume = 0x40; voice->vc_ADSRVolume = 0; voice->vc_Instrument = Ins = &ht->ht_Instruments[Instr]; voice->vc_SamplePos = 0; voice->vc_ADSR.aFrames = Ins->ins_Envelope.aFrames; voice->vc_ADSR.aVolume = voice->vc_ADSR.aFrames ? Ins->ins_Envelope.aVolume*256/voice->vc_ADSR.aFrames : Ins->ins_Envelope.aVolume * 256; // XXX voice->vc_ADSR.dFrames = Ins->ins_Envelope.dFrames; voice->vc_ADSR.dVolume = voice->vc_ADSR.dFrames ? (Ins->ins_Envelope.dVolume-Ins->ins_Envelope.aVolume)*256/voice->vc_ADSR.dFrames : Ins->ins_Envelope.dVolume * 256; // XXX voice->vc_ADSR.sFrames = Ins->ins_Envelope.sFrames; voice->vc_ADSR.rFrames = Ins->ins_Envelope.rFrames; voice->vc_ADSR.rVolume = voice->vc_ADSR.rFrames ? (Ins->ins_Envelope.rVolume-Ins->ins_Envelope.dVolume)*256/voice->vc_ADSR.rFrames : Ins->ins_Envelope.rVolume * 256; // XXX voice->vc_WaveLength = Ins->ins_WaveLength; voice->vc_NoteMaxVolume = Ins->ins_Volume; voice->vc_VibratoCurrent = 0; voice->vc_VibratoDelay = Ins->ins_VibratoDelay; voice->vc_VibratoDepth = Ins->ins_VibratoDepth; voice->vc_VibratoSpeed = Ins->ins_VibratoSpeed; voice->vc_VibratoPeriod = 0; voice->vc_HardCutRelease = Ins->ins_HardCutRelease; voice->vc_HardCut = Ins->ins_HardCutReleaseFrames; voice->vc_IgnoreSquare = voice->vc_SquareSlidingIn = 0; voice->vc_SquareWait = voice->vc_SquareOn = 0; SquareLower = Ins->ins_SquareLowerLimit >> (5 - voice->vc_WaveLength); SquareUpper = Ins->ins_SquareUpperLimit >> (5 - voice->vc_WaveLength); if( SquareUpper < SquareLower ) { int16 t = SquareUpper; SquareUpper = SquareLower; SquareLower = t; } voice->vc_SquareUpperLimit = SquareUpper; voice->vc_SquareLowerLimit = SquareLower; voice->vc_IgnoreFilter = voice->vc_FilterWait = voice->vc_FilterOn = 0; voice->vc_FilterSlidingIn = 0; d6 = Ins->ins_FilterSpeed; d3 = Ins->ins_FilterLowerLimit; d4 = Ins->ins_FilterUpperLimit; if( d3 & 0x80 ) d6 |= 0x20; if( d4 & 0x80 ) d6 |= 0x40; voice->vc_FilterSpeed = d6; d3 &= ~0x80; d4 &= ~0x80; if( d3 > d4 ) { int16 t = d3; d3 = d4; d4 = t; } voice->vc_FilterUpperLimit = d4; voice->vc_FilterLowerLimit = d3; voice->vc_FilterPos = 32; voice->vc_PerfWait = voice->vc_PerfCurrent = 0; voice->vc_PerfSpeed = Ins->ins_PList.pls_Speed; voice->vc_PerfList = &voice->vc_Instrument->ins_PList; voice->vc_RingMixSource = NULL; // No ring modulation voice->vc_RingSamplePos = 0; voice->vc_RingPlantPeriod = 0; voice->vc_RingNewWaveform = 0; } voice->vc_PeriodSlideOn = 0; hvl_process_stepfx_2( ht, voice, Step->stp_FX&0xf, Step->stp_FXParam, &Note ); hvl_process_stepfx_2( ht, voice, Step->stp_FXb&0xf, Step->stp_FXbParam, &Note ); if( Note ) { voice->vc_TrackPeriod = Note; voice->vc_PlantPeriod = 1; } hvl_process_stepfx_3( ht, voice, Step->stp_FX&0xf, Step->stp_FXParam ); hvl_process_stepfx_3( ht, voice, Step->stp_FXb&0xf, Step->stp_FXbParam ); } void hvl_plist_command_parse( struct hvl_tune *ht, struct hvl_voice *voice, int32 FX, int32 FXParam ) { switch( FX ) { case 0: if( ( FXParam > 0 ) && ( FXParam < 0x40 ) ) { if( voice->vc_IgnoreFilter ) { voice->vc_FilterPos = voice->vc_IgnoreFilter; voice->vc_IgnoreFilter = 0; } else { voice->vc_FilterPos = FXParam; } voice->vc_NewWaveform = 1; } break; case 1: voice->vc_PeriodPerfSlideSpeed = FXParam; voice->vc_PeriodPerfSlideOn = 1; break; case 2: voice->vc_PeriodPerfSlideSpeed = -FXParam; voice->vc_PeriodPerfSlideOn = 1; break; case 3: if( voice->vc_IgnoreSquare == 0 ) voice->vc_SquarePos = FXParam >> (5-voice->vc_WaveLength); else voice->vc_IgnoreSquare = 0; break; case 4: if( FXParam == 0 ) { voice->vc_SquareInit = (voice->vc_SquareOn ^= 1); voice->vc_SquareSign = 1; } else { if( FXParam & 0x0f ) { voice->vc_SquareInit = (voice->vc_SquareOn ^= 1); voice->vc_SquareSign = 1; if(( FXParam & 0x0f ) == 0x0f ) voice->vc_SquareSign = -1; } if( FXParam & 0xf0 ) { voice->vc_FilterInit = (voice->vc_FilterOn ^= 1); voice->vc_FilterSign = 1; if(( FXParam & 0xf0 ) == 0xf0 ) voice->vc_FilterSign = -1; } } break; case 5: voice->vc_PerfCurrent = FXParam; break; case 7: // Ring modulate with triangle if(( FXParam >= 1 ) && ( FXParam <= 0x3C )) { voice->vc_RingBasePeriod = FXParam; voice->vc_RingFixedPeriod = 1; } else if(( FXParam >= 0x81 ) && ( FXParam <= 0xBC )) { voice->vc_RingBasePeriod = FXParam-0x80; voice->vc_RingFixedPeriod = 0; } else { voice->vc_RingBasePeriod = 0; voice->vc_RingFixedPeriod = 0; voice->vc_RingNewWaveform = 0; voice->vc_RingAudioSource = NULL; // turn it off voice->vc_RingMixSource = NULL; break; } voice->vc_RingWaveform = 0; voice->vc_RingNewWaveform = 1; voice->vc_RingPlantPeriod = 1; break; case 8: // Ring modulate with sawtooth if(( FXParam >= 1 ) && ( FXParam <= 0x3C )) { voice->vc_RingBasePeriod = FXParam; voice->vc_RingFixedPeriod = 1; } else if(( FXParam >= 0x81 ) && ( FXParam <= 0xBC )) { voice->vc_RingBasePeriod = FXParam-0x80; voice->vc_RingFixedPeriod = 0; } else { voice->vc_RingBasePeriod = 0; voice->vc_RingFixedPeriod = 0; voice->vc_RingNewWaveform = 0; voice->vc_RingAudioSource = NULL; voice->vc_RingMixSource = NULL; break; } voice->vc_RingWaveform = 1; voice->vc_RingNewWaveform = 1; voice->vc_RingPlantPeriod = 1; break; /* New in HivelyTracker 1.4 */ case 9: if( FXParam > 127 ) FXParam -= 256; voice->vc_Pan = (FXParam+128); voice->vc_PanMultLeft = panning_left[voice->vc_Pan]; voice->vc_PanMultRight = panning_right[voice->vc_Pan]; break; case 12: if( FXParam <= 0x40 ) { voice->vc_NoteMaxVolume = FXParam; break; } if( (FXParam -= 0x50) < 0 ) break; if( FXParam <= 0x40 ) { voice->vc_PerfSubVolume = FXParam; break; } if( (FXParam -= 0xa0-0x50) < 0 ) break; if( FXParam <= 0x40 ) voice->vc_TrackMasterVolume = FXParam; break; case 15: voice->vc_PerfSpeed = voice->vc_PerfWait = FXParam; break; } } void hvl_process_frame( struct hvl_tune *ht, struct hvl_voice *voice ) { static uint8 Offsets[] = {0x00,0x04,0x04+0x08,0x04+0x08+0x10,0x04+0x08+0x10+0x20,0x04+0x08+0x10+0x20+0x40}; if( voice->vc_TrackOn == 0 ) return; if( voice->vc_NoteDelayOn ) { if( voice->vc_NoteDelayWait <= 0 ) hvl_process_step( ht, voice ); else voice->vc_NoteDelayWait--; } if( voice->vc_HardCut ) { int32 nextinst; if( ht->ht_NoteNr+1 < ht->ht_TrackLength ) nextinst = ht->ht_Tracks[voice->vc_Track][ht->ht_NoteNr+1].stp_Instrument; else nextinst = ht->ht_Tracks[voice->vc_NextTrack][0].stp_Instrument; if( nextinst ) { int32 d1; d1 = ht->ht_Tempo - voice->vc_HardCut; if( d1 < 0 ) d1 = 0; if( !voice->vc_NoteCutOn ) { voice->vc_NoteCutOn = 1; voice->vc_NoteCutWait = d1; voice->vc_HardCutReleaseF = -(d1-ht->ht_Tempo); } else { voice->vc_HardCut = 0; } } } if( voice->vc_NoteCutOn ) { if( voice->vc_NoteCutWait <= 0 ) { voice->vc_NoteCutOn = 0; if( voice->vc_HardCutRelease ) { voice->vc_ADSR.rVolume = -(voice->vc_ADSRVolume - (voice->vc_Instrument->ins_Envelope.rVolume << 8)) / voice->vc_HardCutReleaseF; voice->vc_ADSR.rFrames = voice->vc_HardCutReleaseF; voice->vc_ADSR.aFrames = voice->vc_ADSR.dFrames = voice->vc_ADSR.sFrames = 0; } else { voice->vc_NoteMaxVolume = 0; } } else { voice->vc_NoteCutWait--; } } // ADSR envelope if( voice->vc_ADSR.aFrames ) { voice->vc_ADSRVolume += voice->vc_ADSR.aVolume; if( --voice->vc_ADSR.aFrames <= 0 ) voice->vc_ADSRVolume = voice->vc_Instrument->ins_Envelope.aVolume << 8; } else if( voice->vc_ADSR.dFrames ) { voice->vc_ADSRVolume += voice->vc_ADSR.dVolume; if( --voice->vc_ADSR.dFrames <= 0 ) voice->vc_ADSRVolume = voice->vc_Instrument->ins_Envelope.dVolume << 8; } else if( voice->vc_ADSR.sFrames ) { voice->vc_ADSR.sFrames--; } else if( voice->vc_ADSR.rFrames ) { voice->vc_ADSRVolume += voice->vc_ADSR.rVolume; if( --voice->vc_ADSR.rFrames <= 0 ) voice->vc_ADSRVolume = voice->vc_Instrument->ins_Envelope.rVolume << 8; } // VolumeSlide voice->vc_NoteMaxVolume = voice->vc_NoteMaxVolume + voice->vc_VolumeSlideUp - voice->vc_VolumeSlideDown; if( voice->vc_NoteMaxVolume < 0 ) voice->vc_NoteMaxVolume = 0; else if( voice->vc_NoteMaxVolume > 0x40 ) voice->vc_NoteMaxVolume = 0x40; // Portamento if( voice->vc_PeriodSlideOn ) { if( voice->vc_PeriodSlideWithLimit ) { int32 d0, d2; d0 = voice->vc_PeriodSlidePeriod - voice->vc_PeriodSlideLimit; d2 = voice->vc_PeriodSlideSpeed; if( d0 > 0 ) d2 = -d2; if( d0 ) { int32 d3; d3 = (d0 + d2) ^ d0; if( d3 >= 0 ) d0 = voice->vc_PeriodSlidePeriod + d2; else d0 = voice->vc_PeriodSlideLimit; voice->vc_PeriodSlidePeriod = d0; voice->vc_PlantPeriod = 1; } } else { voice->vc_PeriodSlidePeriod += voice->vc_PeriodSlideSpeed; voice->vc_PlantPeriod = 1; } } // Vibrato if( voice->vc_VibratoDepth ) { if( voice->vc_VibratoDelay <= 0 ) { voice->vc_VibratoPeriod = (vib_tab[voice->vc_VibratoCurrent] * voice->vc_VibratoDepth) >> 7; voice->vc_PlantPeriod = 1; voice->vc_VibratoCurrent = (voice->vc_VibratoCurrent + voice->vc_VibratoSpeed) & 0x3f; } else { voice->vc_VibratoDelay--; } } // PList if( voice->vc_PerfList != 0 ) { if( voice->vc_Instrument && voice->vc_PerfCurrent < voice->vc_Instrument->ins_PList.pls_Length ) { if( --voice->vc_PerfWait <= 0 ) { uint32 i; int32 cur; cur = voice->vc_PerfCurrent++; voice->vc_PerfWait = voice->vc_PerfSpeed; if( voice->vc_PerfList->pls_Entries[cur].ple_Waveform ) { voice->vc_Waveform = voice->vc_PerfList->pls_Entries[cur].ple_Waveform-1; voice->vc_NewWaveform = 1; voice->vc_PeriodPerfSlideSpeed = voice->vc_PeriodPerfSlidePeriod = 0; } // Holdwave voice->vc_PeriodPerfSlideOn = 0; for( i=0; i<2; i++ ) hvl_plist_command_parse( ht, voice, voice->vc_PerfList->pls_Entries[cur].ple_FX[i]&0xff, voice->vc_PerfList->pls_Entries[cur].ple_FXParam[i]&0xff ); // GetNote if( voice->vc_PerfList->pls_Entries[cur].ple_Note ) { voice->vc_InstrPeriod = voice->vc_PerfList->pls_Entries[cur].ple_Note; voice->vc_PlantPeriod = 1; voice->vc_FixedNote = voice->vc_PerfList->pls_Entries[cur].ple_Fixed; } } } else { if( voice->vc_PerfWait ) voice->vc_PerfWait--; else voice->vc_PeriodPerfSlideSpeed = 0; } } // PerfPortamento if( voice->vc_PeriodPerfSlideOn ) { voice->vc_PeriodPerfSlidePeriod -= voice->vc_PeriodPerfSlideSpeed; if( voice->vc_PeriodPerfSlidePeriod ) voice->vc_PlantPeriod = 1; } if( voice->vc_Waveform == 3-1 && voice->vc_SquareOn ) { if( --voice->vc_SquareWait <= 0 ) { int32 d1, d2, d3; d1 = voice->vc_SquareLowerLimit; d2 = voice->vc_SquareUpperLimit; d3 = voice->vc_SquarePos; if( voice->vc_SquareInit ) { voice->vc_SquareInit = 0; if( d3 <= d1 ) { voice->vc_SquareSlidingIn = 1; voice->vc_SquareSign = 1; } else if( d3 >= d2 ) { voice->vc_SquareSlidingIn = 1; voice->vc_SquareSign = -1; } } // NoSquareInit if( d1 == d3 || d2 == d3 ) { if( voice->vc_SquareSlidingIn ) voice->vc_SquareSlidingIn = 0; else voice->vc_SquareSign = -voice->vc_SquareSign; } d3 += voice->vc_SquareSign; voice->vc_SquarePos = d3; voice->vc_PlantSquare = 1; voice->vc_SquareWait = voice->vc_Instrument->ins_SquareSpeed; } } if( voice->vc_FilterOn && --voice->vc_FilterWait <= 0 ) { uint32 i, FMax; int32 d1, d2, d3; d1 = voice->vc_FilterLowerLimit; d2 = voice->vc_FilterUpperLimit; d3 = voice->vc_FilterPos; if( voice->vc_FilterInit ) { voice->vc_FilterInit = 0; if( d3 <= d1 ) { voice->vc_FilterSlidingIn = 1; voice->vc_FilterSign = 1; } else if( d3 >= d2 ) { voice->vc_FilterSlidingIn = 1; voice->vc_FilterSign = -1; } } // NoFilterInit FMax = (voice->vc_FilterSpeed < 3) ? (5-voice->vc_FilterSpeed) : 1; for( i=0; ivc_FilterSlidingIn ) voice->vc_FilterSlidingIn = 0; else voice->vc_FilterSign = -voice->vc_FilterSign; } d3 += voice->vc_FilterSign; } if( d3 < 1 ) d3 = 1; if( d3 > 63 ) d3 = 63; voice->vc_FilterPos = d3; voice->vc_NewWaveform = 1; voice->vc_FilterWait = voice->vc_FilterSpeed - 3; if( voice->vc_FilterWait < 1 ) voice->vc_FilterWait = 1; } if( voice->vc_Waveform == 3-1 || voice->vc_PlantSquare ) { // CalcSquare uint32 i; int32 Delta; int8 *SquarePtr; int32 X; SquarePtr = &waves[WO_SQUARES+(voice->vc_FilterPos-0x20)*(0xfc+0xfc+0x80*0x1f+0x80+0x280*3)]; X = voice->vc_SquarePos << (5 - voice->vc_WaveLength); if( X > 0x20 ) { X = 0x40 - X; voice->vc_SquareReverse = 1; } // OkDownSquare if( X > 0 ) SquarePtr += (X-1) << 7; Delta = 32 >> voice->vc_WaveLength; ht->ht_WaveformTab[2] = voice->vc_SquareTempBuffer; for( i=0; i<(1<vc_WaveLength)*4; i++ ) { voice->vc_SquareTempBuffer[i] = *SquarePtr; SquarePtr += Delta; } voice->vc_NewWaveform = 1; voice->vc_Waveform = 3-1; voice->vc_PlantSquare = 0; } if( voice->vc_Waveform == 4-1 ) voice->vc_NewWaveform = 1; if( voice->vc_RingNewWaveform ) { int8 *rasrc; if( voice->vc_RingWaveform > 1 ) voice->vc_RingWaveform = 1; rasrc = ht->ht_WaveformTab[voice->vc_RingWaveform]; rasrc += Offsets[voice->vc_WaveLength]; voice->vc_RingAudioSource = rasrc; } if( voice->vc_NewWaveform ) { int8 *AudioSource; AudioSource = ht->ht_WaveformTab[voice->vc_Waveform]; if( voice->vc_Waveform != 3-1 ) AudioSource += (voice->vc_FilterPos-0x20)*(0xfc+0xfc+0x80*0x1f+0x80+0x280*3); if( voice->vc_Waveform < 3-1) { // GetWLWaveformlor2 AudioSource += Offsets[voice->vc_WaveLength]; } if( voice->vc_Waveform == 4-1 ) { // AddRandomMoving AudioSource += ( voice->vc_WNRandom & (2*0x280-1) ) & ~1; // GoOnRandom voice->vc_WNRandom += 2239384; voice->vc_WNRandom = ((((voice->vc_WNRandom >> 8) | (voice->vc_WNRandom << 24)) + 782323) ^ 75) - 6735; } voice->vc_AudioSource = AudioSource; } // Ring modulation period calculation if( voice->vc_RingAudioSource ) { voice->vc_RingAudioPeriod = voice->vc_RingBasePeriod; if( !(voice->vc_RingFixedPeriod) ) { if( voice->vc_OverrideTranspose != 1000 ) // 1.5 voice->vc_RingAudioPeriod += voice->vc_OverrideTranspose + voice->vc_TrackPeriod - 1; else voice->vc_RingAudioPeriod += voice->vc_Transpose + voice->vc_TrackPeriod - 1; } if( voice->vc_RingAudioPeriod > 5*12 ) voice->vc_RingAudioPeriod = 5*12; if( voice->vc_RingAudioPeriod < 0 ) voice->vc_RingAudioPeriod = 0; voice->vc_RingAudioPeriod = period_tab[voice->vc_RingAudioPeriod]; if( !(voice->vc_RingFixedPeriod) ) voice->vc_RingAudioPeriod += voice->vc_PeriodSlidePeriod; voice->vc_RingAudioPeriod += voice->vc_PeriodPerfSlidePeriod + voice->vc_VibratoPeriod; if( voice->vc_RingAudioPeriod > 0x0d60 ) voice->vc_RingAudioPeriod = 0x0d60; if( voice->vc_RingAudioPeriod < 0x0071 ) voice->vc_RingAudioPeriod = 0x0071; } // Normal period calculation voice->vc_AudioPeriod = voice->vc_InstrPeriod; if( !(voice->vc_FixedNote) ) { if( voice->vc_OverrideTranspose != 1000 ) // 1.5 voice->vc_AudioPeriod += voice->vc_OverrideTranspose + voice->vc_TrackPeriod - 1; else voice->vc_AudioPeriod += voice->vc_Transpose + voice->vc_TrackPeriod - 1; } if( voice->vc_AudioPeriod > 5*12 ) voice->vc_AudioPeriod = 5*12; if( voice->vc_AudioPeriod < 0 ) voice->vc_AudioPeriod = 0; voice->vc_AudioPeriod = period_tab[voice->vc_AudioPeriod]; if( !(voice->vc_FixedNote) ) voice->vc_AudioPeriod += voice->vc_PeriodSlidePeriod; voice->vc_AudioPeriod += voice->vc_PeriodPerfSlidePeriod + voice->vc_VibratoPeriod; if( voice->vc_AudioPeriod > 0x0d60 ) voice->vc_AudioPeriod = 0x0d60; if( voice->vc_AudioPeriod < 0x0071 ) voice->vc_AudioPeriod = 0x0071; voice->vc_AudioVolume = (((((((voice->vc_ADSRVolume >> 8) * voice->vc_NoteMaxVolume) >> 6) * voice->vc_PerfSubVolume) >> 6) * voice->vc_TrackMasterVolume) >> 6); } void hvl_set_audio( struct hvl_voice *voice, float64 freqf ) { if( voice->vc_TrackOn == 0 ) { voice->vc_VoiceVolume = 0; return; } voice->vc_VoiceVolume = voice->vc_AudioVolume; if( voice->vc_PlantPeriod ) { float64 freq2; uint32 idelta; voice->vc_PlantPeriod = 0; voice->vc_VoicePeriod = voice->vc_AudioPeriod; freq2 = Period2Freq( voice->vc_AudioPeriod ); idelta = (uint32)(freqf / freq2 * 65536.f); if( idelta == 0 ) idelta = 1; voice->vc_Delta = idelta; } if( voice->vc_NewWaveform ) { int8 *src; src = voice->vc_AudioSource; if( voice->vc_Waveform == 4-1 ) { memcpy( &voice->vc_VoiceBuffer[0], src, 0x280 ); } else { uint32 i, WaveLoops; WaveLoops = (1 << (5 - voice->vc_WaveLength)) * 5; for( i=0; ivc_VoiceBuffer[i*4*(1<vc_WaveLength)], src, 4*(1<vc_WaveLength) ); } voice->vc_VoiceBuffer[0x280] = voice->vc_VoiceBuffer[0]; voice->vc_MixSource = voice->vc_VoiceBuffer; } /* Ring Modulation */ if( voice->vc_RingPlantPeriod ) { float64 freq2; uint32 idelta; voice->vc_RingPlantPeriod = 0; freq2 = Period2Freq( voice->vc_RingAudioPeriod ); idelta = (uint32)(freqf / freq2 * 65536.f); if( idelta == 0 ) idelta = 1; voice->vc_RingDelta = idelta; } if( voice->vc_RingNewWaveform ) { int8 *src; uint32 i, WaveLoops; src = voice->vc_RingAudioSource; WaveLoops = (1 << (5 - voice->vc_WaveLength)) * 5; for( i=0; ivc_RingVoiceBuffer[i*4*(1<vc_WaveLength)], src, 4*(1<vc_WaveLength) ); voice->vc_RingVoiceBuffer[0x280] = voice->vc_RingVoiceBuffer[0]; voice->vc_RingMixSource = voice->vc_RingVoiceBuffer; } } void hvl_play_irq( struct hvl_tune *ht ) { uint32 i; if( ht->ht_StepWaitFrames <= 0 ) { if( ht->ht_GetNewPosition ) { int32 nextpos = (ht->ht_PosNr+1==ht->ht_PositionNr)?0:(ht->ht_PosNr+1); for( i=0; iht_Channels; i++ ) { ht->ht_Voices[i].vc_Track = ht->ht_Positions[ht->ht_PosNr].pos_Track[i]; ht->ht_Voices[i].vc_Transpose = ht->ht_Positions[ht->ht_PosNr].pos_Transpose[i]; ht->ht_Voices[i].vc_NextTrack = ht->ht_Positions[nextpos].pos_Track[i]; ht->ht_Voices[i].vc_NextTranspose = ht->ht_Positions[nextpos].pos_Transpose[i]; } ht->ht_GetNewPosition = 0; } for( i=0; iht_Channels; i++ ) hvl_process_step( ht, &ht->ht_Voices[i] ); ht->ht_StepWaitFrames = ht->ht_Tempo; } for( i=0; iht_Channels; i++ ) hvl_process_frame( ht, &ht->ht_Voices[i] ); ht->ht_PlayingTime++; if( ht->ht_Tempo > 0 && --ht->ht_StepWaitFrames <= 0 ) { if( !ht->ht_PatternBreak ) { ht->ht_NoteNr++; if( ht->ht_NoteNr >= ht->ht_TrackLength ) { ht->ht_PosJump = ht->ht_PosNr+1; ht->ht_PosJumpNote = 0; ht->ht_PatternBreak = 1; } } if( ht->ht_PatternBreak ) { ht->ht_PatternBreak = 0; ht->ht_PosNr = ht->ht_PosJump; ht->ht_NoteNr = ht->ht_PosJumpNote; if( ht->ht_PosNr == ht->ht_PositionNr ) { ht->ht_SongEndReached = 1; ht->ht_PosNr = ht->ht_Restart; } ht->ht_PosJumpNote = 0; ht->ht_PosJump = 0; ht->ht_GetNewPosition = 1; } } for( i=0; iht_Channels; i++ ) hvl_set_audio( &ht->ht_Voices[i], ht->ht_Frequency ); } void hvl_mixchunk( struct hvl_tune *ht, uint32 samples, int8 *buf1, int8 *buf2, int32 bufmod ) { int8 *src[MAX_CHANNELS]; int8 *rsrc[MAX_CHANNELS]; uint32 delta[MAX_CHANNELS]; uint32 rdelta[MAX_CHANNELS]; int32 vol[MAX_CHANNELS]; uint32 pos[MAX_CHANNELS]; uint32 rpos[MAX_CHANNELS]; // uint32 cnt; int32 panl[MAX_CHANNELS]; int32 panr[MAX_CHANNELS]; // uint32 vu[MAX_CHANNELS]; int32 last_amp[MAX_CHANNELS][2]; uint32 last_clock[MAX_CHANNELS][2]; uint32 clock, rclock, next_clock, current_clock, target_clock; int32 j, blip_deltal, blip_deltar, last_ampl, last_ampr; uint32 i, chans, loops; chans = ht->ht_Channels; for( i=0; iht_Voices[i].vc_Delta; vol[i] = ht->ht_Voices[i].vc_VoiceVolume; pos[i] = ht->ht_Voices[i].vc_SamplePos; src[i] = ht->ht_Voices[i].vc_MixSource; panl[i] = ht->ht_Voices[i].vc_PanMultLeft; panr[i] = ht->ht_Voices[i].vc_PanMultRight; /* Ring Modulation */ rdelta[i]= ht->ht_Voices[i].vc_RingDelta; rpos[i] = ht->ht_Voices[i].vc_RingSamplePos; rsrc[i] = ht->ht_Voices[i].vc_RingMixSource; last_amp[i][0] = ht->ht_Voices[i].vc_LastAmp[0]; last_amp[i][1] = ht->ht_Voices[i].vc_LastAmp[1]; last_clock[i][0] = ht->ht_Voices[i].vc_LastClock[0]; last_clock[i][1] = ht->ht_Voices[i].vc_LastClock[1]; // vu[i] = 0; } do { loops = samples; if (loops > 256) loops = 256; samples -= loops; target_clock = loops << 16; // Inner loop for( i=0; i>7; if( rclock < next_clock ) { rclock += rdelta[i]; rpos[i] = (rpos[i] + 1) % 0x280; } } j *= vol[i]; // if( abs( j ) > vu[i] ) vu[i] = abs( j ); blip_deltal = ((j * panl[i]) >> 7) - last_ampl; blip_deltar = ((j * panr[i]) >> 7) - last_ampr; last_ampl += blip_deltal; last_ampr += blip_deltar; if( blip_deltal ) hvl_blip_add_delta( ht->ht_BlipBuffers[0], current_clock, blip_deltal ); if( blip_deltar ) hvl_blip_add_delta( ht->ht_BlipBuffers[1], current_clock, blip_deltar ); current_clock = next_clock; } clock -= target_clock; if( rsrc[i] ) rclock -= target_clock; last_clock[i][0] = clock; last_clock[i][1] = rclock; last_amp[i][0] = last_ampl; last_amp[i][1] = last_ampr; } hvl_blip_end_frame( ht->ht_BlipBuffers[0], target_clock ); hvl_blip_end_frame( ht->ht_BlipBuffers[1], target_clock ); hvl_blip_read_samples( ht->ht_BlipBuffers[0], (int*)buf1, loops, ht->ht_mixgain ); hvl_blip_read_samples( ht->ht_BlipBuffers[1], (int*)buf2, loops, ht->ht_mixgain ); buf1 += bufmod * loops; buf2 += bufmod * loops; } while( samples > 0 ); for( i=0; iht_Voices[i].vc_SamplePos = pos[i]; ht->ht_Voices[i].vc_RingSamplePos = rpos[i]; ht->ht_Voices[i].vc_LastAmp[0] = last_amp[i][0]; ht->ht_Voices[i].vc_LastAmp[1] = last_amp[i][1]; ht->ht_Voices[i].vc_LastClock[0] = last_clock[i][0]; ht->ht_Voices[i].vc_LastClock[1] = last_clock[i][1]; // ht->ht_Voices[i].vc_VUMeter = vu[i]; } } void hvl_DecodeFrame( struct hvl_tune *ht, int8 *buf1, int8 *buf2, int32 bufmod ) { uint32 samples, loops; samples = ht->ht_Frequency/50/ht->ht_SpeedMultiplier; loops = ht->ht_SpeedMultiplier; do { hvl_play_irq( ht ); hvl_mixchunk( ht, samples, buf1, buf2, bufmod ); buf1 += samples * bufmod; buf2 += samples * bufmod; loops--; } while( loops ); }