kolibrios/programs/develop/libraries/ufmod/core.asm

3374 lines
73 KiB
NASM
Raw Normal View History

; CORE.ASM
; --------
; uFMOD public source code release. Provided as-is.
if VIBRATO_OR_TREMOLO
sin127 db 00h,0Ch,19h,25h,31h,3Ch,47h,51h,5Ah,62h,6Ah,70h,75h,7Ah,7Dh,7Eh
db 7Fh,7Eh,7Dh,7Ah,75h,70h,6Ah,62h,5Ah,51h,47h,3Ch,31h,25h,19h,0Ch
endif
if INSTRUMENTVIBRATO_ON
sin64 db 00h,02h,03h,05h,06h,08h,09h,0Bh,0Ch,0Eh,10h,11h,13h,14h,16h,17h
db 18h,1Ah,1Bh,1Dh,1Eh,20h,21h,22h,24h,25h,26h,27h,29h,2Ah,2Bh,2Ch
db 2Dh,2Eh,2Fh,30h,31h,32h,33h,34h,35h,36h,37h,38h,38h,39h,3Ah,3Bh
db 3Bh,3Ch,3Ch,3Dh,3Dh,3Eh,3Eh,3Eh,3Fh,3Fh,3Fh,40h,40h,40h,40h,40h
endif
if AMIGAPERIODS_ON
f0_0833 dd 8.3333336e-2
f13_375 dd 1.3375e1
endif
f0_0013 dd 1.302083375e-3
f8363_0 dd 8.3630004275e3
; Mixer ramping
Ramp:
; [arg0] - ptr. to end of buffer
; ESI - _mod+36
; EDI - length
; EDX - buffer
; LOOP THROUGH CHANNELS
mov ecx,[esi+FMUSIC_MODULE.Channels-36]
push ebx
push ebp
loop_ch:
push esi
mov esi,[ecx+FSOUND_CHANNEL.fsptr] ; load the correct SAMPLE pointer for this channel
test esi,esi ; if(!fsptr) skip this channel!
jz MixExit_1
push edx ; mix buffer
push edx ; cur. mix buffer pointer
mov ebx,[ecx+FSOUND_CHANNEL.mixpos]
; Set up a mix counter. See what will happen first, will the output buffer
; end be reached first? or will the end of the sample be reached first? whatever
; is smallest will be the mixcount.
push edi
CalculateLoopCount:
cmp BYTE PTR [ecx+FSOUND_CHANNEL.speeddir],0
mov edx,[esi+FSOUND_SAMPLE.loopstart]
mov eax,[ecx+FSOUND_CHANNEL.mixposlo]
jne samplesleftbackwards
; work out how many samples left from mixpos to loop end
add edx,[esi+FSOUND_SAMPLE.looplen]
sub edx,ebx
ja submixpos
mov edx,[esi+FSOUND_SAMPLE._length]
sub edx,ebx
submixpos:
; edx : samples left (loopstart+looplen-mixpos)
neg edx
neg eax
adc edx,ebx
samplesleftbackwards:
; work out how many samples left from mixpos to loop start
neg edx
add edx,ebx
js MixExit
; edx:eax now contains number of samples left to mix
mov ebp,[ecx+FSOUND_CHANNEL.speedlo]
shrd eax,edx,5
mov ebx,[ecx+FSOUND_CHANNEL.speedhi]
shr edx,5
shrd ebp,ebx,5
jnz speedok ; divide by 0 check
mov ebp,FREQ_40HZ_p
mov DWORD PTR [ecx+FSOUND_CHANNEL.speedlo],FREQ_40HZ_f
speedok:
div ebp
xor ebp,ebp
neg edx
adc eax,ebp
jz DoOutputbuffEnd
mov ebx,OFFSET uFMOD_fopen
cmp eax,edi
; set a flag to say mix will end when end of output buffer is reached
seta [ebx-22] ; mix_endflag
jae staywithoutputbuffend
xchg eax,edi
staywithoutputbuffend:
if RAMP_NONE
else
movzx eax,WORD PTR [ecx+FSOUND_CHANNEL.ramp_count]
; VOLUME RAMP SETUP
; Reasons to ramp
; 1 volume change
; 2 sample starts (just treat as volume change - 0 to volume)
; 3 sample ends (ramp last n number of samples from volume to 0)
; now if the volume has changed, make end condition equal a volume ramp
test eax,eax
endif
mov edx,[ecx+FSOUND_CHANNEL.leftvolume]
mov ebp,[ecx+FSOUND_CHANNEL.rightvolume]
if RAMP_NONE
mov [ecx+FSOUND_CHANNEL.ramp_leftvolume],ebp
mov [ecx+FSOUND_CHANNEL.ramp_rightvolume],edx
else
mov [ebx-16],edi ; mmf+4 <- remember mix count before modifying it
jz volumerampstart
; if it tries to continue an old ramp, but the target has changed,
; set up a new ramp
cmp dx,[ecx+FSOUND_CHANNEL.ramp_lefttarget]
jne volumerampstart
cmp bp,[ecx+FSOUND_CHANNEL.ramp_righttarget]
je volumerampclamp ; restore old ramp
volumerampstart:
; SETUP NEW RAMP
mov [ecx+FSOUND_CHANNEL.ramp_lefttarget],dx
shl edx,volumeramps_pow
sub edx,[ecx+FSOUND_CHANNEL.ramp_leftvolume]
xor eax,eax
sar edx,volumeramps_pow
mov DWORD PTR [ecx+FSOUND_CHANNEL.ramp_leftspeed],edx
jz novolumerampL
mov al,volumerampsteps
novolumerampL:
mov [ecx+FSOUND_CHANNEL.ramp_righttarget],bp
shl ebp,volumeramps_pow
sub ebp,[ecx+FSOUND_CHANNEL.ramp_rightvolume]
sar ebp,volumeramps_pow
mov DWORD PTR [ecx+FSOUND_CHANNEL.ramp_rightspeed],ebp
jz novolumerampR
mov al,volumerampsteps
novolumerampR:
test eax,eax
mov [ecx+FSOUND_CHANNEL.ramp_count],ax
jz volumerampend
volumerampclamp:
cmp edi,eax
jbe volumerampend ; dont clamp mixcount
mov edi,eax
volumerampend:
mov eax,[ecx+FSOUND_CHANNEL.ramp_leftspeed]
mov [ebx],eax ; ramp_leftspeed
mov eax,[ecx+FSOUND_CHANNEL.ramp_rightspeed]
mov [ebx+4],eax ; ramp_rightspeed
endif
mov [ebx-20],edi ; mmf
; SET UP ALL OF THE REGISTERS HERE FOR THE INNER LOOP
; edx : speed
; ebx : mixpos
; ebp : speed low
; esi : destination pointer
; edi : counter
mov ebx,[ecx+FSOUND_CHANNEL.mixpos]
lea ebx,[ebx*2+esi+FSOUND_SAMPLE.buff]
push esi
cmp BYTE PTR [ecx+FSOUND_CHANNEL.speeddir],0
mov esi,[esp+8] ; <- cur. mix buffer
mov edx,[ecx+FSOUND_CHANNEL.speedhi]
mov ebp,[ecx+FSOUND_CHANNEL.speedlo]
je MixLoop16
; neg edx:ebp
neg ebp
not edx
sbb edx,-1
align 4
MixLoop16:
push edi
push edx
movsx edi,WORD PTR [ebx]
movsx eax,WORD PTR [ebx+2]
mov edx,[ecx+FSOUND_CHANNEL.mixposlo]
sub eax,edi
shr edx,1 ; force unsigned
imul edx
shl edi,volumeramps_pow-1
shld edx,eax,volumeramps_pow
add edx,edi
if RAMP_NONE
mov eax,edx
imul edx,[ecx+FSOUND_CHANNEL.ramp_rightvolume]
add [esi],edx
imul DWORD PTR [ecx+FSOUND_CHANNEL.ramp_leftvolume]
add [esi+4],eax
else
xchg eax,edx
mov edi,eax
imul DWORD PTR [ecx+FSOUND_CHANNEL.ramp_rightvolume]
shrd eax,edx,volumeramps_pow-1
rol edx,1
and edx,1
add eax,edx
sar eax,1
add [esi],eax
xchg eax,edi
imul DWORD PTR [ecx+FSOUND_CHANNEL.ramp_leftvolume]
shrd eax,edx,volumeramps_pow-1
rol edx,1
and edx,1
add eax,edx
mov edi,[uFMOD_fread]
sar eax,1
add [esi+4],eax
mov edx,[uFMOD_fopen]
add [ecx+FSOUND_CHANNEL.ramp_rightvolume],edi ; + cur_ramp_rightspeed
add [ecx+FSOUND_CHANNEL.ramp_leftvolume],edx ; + cur_ramp_leftspeed
endif
pop edx
xor eax,eax
add [ecx+FSOUND_CHANNEL.mixposlo],ebp
pop edi
adc eax,edx
add esi,8
dec edi
lea ebx,[ebx+eax*2]
jnz MixLoop16
mov edi,[esp+20h] ; find out how many OUTPUT samples left to mix
mov [esp+8],esi ; update cur. mix buffer
sub edi,esi
shr edi,3 ; edi <- # of samples left
pop esi ; esi <- sample pointer
lea eax,[esi+FSOUND_SAMPLE.buff]
sub ebx,eax
shr ebx,1
mov [ecx+FSOUND_CHANNEL.mixpos],ebx
if RAMP_NONE
xor edx,edx
else
; DID A VOLUME RAMP JUST HAPPEN?
movzx edx,WORD PTR [ecx+FSOUND_CHANNEL.ramp_count]
test edx,edx
jz DoOutputbuffEnd
mov eax,[mmf]
cdq
sub [ecx+FSOUND_CHANNEL.ramp_count],ax
; if(!rampcount) a ramp has FINISHED, so finish the rest of the mix
jnz DoOutputbuffEnd
sub eax,[mmf+4]
; clear out the ramp speeds
mov [ecx+FSOUND_CHANNEL.ramp_leftspeed],edx
neg eax
mov [ecx+FSOUND_CHANNEL.ramp_rightspeed],edx
; is it 0 because ramp ended only? or both ended together?
; if sample ended together with ramp... problems... loop isn't handled
sbb edx,edx
; start again and continue rest of mix
test edi,edx
jnz CalculateLoopCount ; dont start again if nothing left
xor edx,edx
endif
DoOutputbuffEnd:
cmp [mix_endflag],dl
jne MixExit
movzx eax,BYTE PTR [esi+FSOUND_SAMPLE.loopmode]
; SWITCH ON LOOP MODE TYPE
dec eax ; check for normal loop (FSOUND_LOOP_NORMAL = 1)
jnz CheckBidiLoop
mov eax,[esi+FSOUND_SAMPLE.loopstart]
mov ebp,[esi+FSOUND_SAMPLE.looplen]
add eax,ebp
cmp ebx,eax
jbe rewind_ok
sub ebx,eax
xchg eax,ebx
div ebp
rewind_ok:
sub ebp,edx
sub ebx,ebp
jmp ChkLoop_OK
CheckBidiLoop:
dec eax ; FSOUND_LOOP_BIDI = 2
neg eax
adc edx,-1
and [ecx+FSOUND_CHANNEL.mixposlo],edx
and [ecx+FSOUND_CHANNEL.mixpos],edx
and [ecx+FSOUND_CHANNEL.fsptr],edx
jz MixExit
cmp [ecx+FSOUND_CHANNEL.speeddir],al ; FSOUND_MIXDIR_FORWARDS
je BidiForward
BidiBackwards:
mov eax,[esi+FSOUND_SAMPLE.loopstart]
neg ebp
dec eax
sub ebp,1
dec BYTE PTR [ecx+FSOUND_CHANNEL.speeddir] ; set FSOUND_MIXDIR_FORWARDS
sbb eax,ebx
mov ebx,[esi+FSOUND_SAMPLE.loopstart]
add ebx,eax
cmp eax,[esi+FSOUND_SAMPLE.looplen]
jl BidiFinish
BidiForward:
mov eax,[esi+FSOUND_SAMPLE.loopstart]
add eax,[esi+FSOUND_SAMPLE.looplen]
lea edx,[eax-1]
sbb eax,ebx
neg ebp
xchg eax,ebx
sub ebp,1
adc ebx,edx
inc BYTE PTR [ecx+FSOUND_CHANNEL.speeddir] ; go backwards
cmp ebx,[esi+FSOUND_SAMPLE.loopstart]
jl BidiBackwards
BidiFinish:
mov [ecx+FSOUND_CHANNEL.mixposlo],ebp
ChkLoop_OK:
test edi,edi
mov [ecx+FSOUND_CHANNEL.mixpos],ebx
jnz CalculateLoopCount
MixExit:
pop edi
pop eax ; discard cur. mix buffer pointer
pop edx
MixExit_1:
add ecx,FSOUND_CHANNEL_size
pop esi
cmp ecx,[esi+FMUSIC_MODULE.uFMOD_Ch-36]
jl loop_ch
pop ebp
pop ebx
ret
if AMIGAPERIODS_ON
AmigaPeriod:
; [sptr] in ECX
; note in EAX
; ESI != 0
mov edx,132
push edi
sub edx,eax
push esi
test eax,eax
push edx
movsx eax,BYTE PTR [ecx+FSOUND_SAMPLE.finetune]
mov edi,edx
jz _do_inc
cdq
shl edx,1
_do_inc:
inc edx
exp2:
fild DWORD PTR [esp]
fmul DWORD PTR [f0_0833] ; /12.0f
fld st0
frndint
fsub st1,st0
fxch st1
f2xm1
fld1
faddp st1,st0
fscale
fstp st1
fmul DWORD PTR [f13_375] ; *13.375f
fistp DWORD PTR [esp]
test esi,esi
pop ecx
jz exp2_end
sub edi,edx
push edi
xor esi,esi
mov edi,ecx
jmp exp2
exp2_end:
sub ecx,edi
test edx,edx
jns _do_imul
neg ecx
_do_imul:
imul ecx
and edx,127 ; +2^7-1
add eax,edx
sar eax,7
pop esi
add eax,edi
pop edi
ret
endif ; AMIGAPERIODS_ON
; DESCRIPTION: To carry out a vibrato at a certain depth and speed
if VIBRATO_OR_VOLSLIDE
if TREMOLO_ON
VibratoOrTremolo:
; cptr+2 = ESI
movzx ecx,BYTE PTR [esi+FMUSIC_CHANNEL.vibpos-2]
mov al,[esi+FMUSIC_CHANNEL.wavecontrol-2]
mov edx,ecx
add dl,[esi+FMUSIC_CHANNEL.vibspeed-2]
and edx,3Fh
and eax,3 ; switch(cptr->wavecontrol&3)
mov [esi+FMUSIC_CHANNEL.vibpos-2],dl
jz vibrato_c0
; C2 : Sqare wave
rol ecx,27
sbb edx,edx
xor edx,7Fh
or edx,1
dec eax
jnz vibrato_default
; C1 : Triangle wave (ramp down)
shr edx,24
ror ecx,23
add edx,ecx
neg edx
jmp vibrato_default
vibrato_c0:
; C0 : Sine wave
; delta = 127 sin(2 Pi x/64)
mov eax,ecx
and ecx,1Fh
shr eax,6
movzx edx,BYTE PTR [OFFSET sin127+ecx]
sbb eax,eax
xor edx,eax
sub edx,eax
vibrato_default:
movsx eax,BYTE PTR [esi+FMUSIC_CHANNEL.vibdepth-2]
imul edx ; delta *= cptr->vibdepth
sar eax,5
ret
endif
Vibrato:
; cptr+2 = ESI
if TREMOLO_ON
call VibratoOrTremolo
sar eax,1
else
movzx ecx,BYTE PTR [esi+FMUSIC_CHANNEL.vibpos-2]
mov al,[esi+FMUSIC_CHANNEL.wavecontrol-2]
mov edx,ecx
add dl,[esi+FMUSIC_CHANNEL.vibspeed-2]
and edx,3Fh
and eax,3 ; switch(cptr->wavecontrol&3)
mov [esi+FMUSIC_CHANNEL.vibpos-2],dl
jz vibrato_c0
; C2 : Sqare wave
rol ecx,27
sbb edx,edx
xor edx,7Fh
or edx,1
dec eax
jnz vibrato_default
; C1 : Triangle wave (ramp down)
shr edx,24
ror ecx,23
add edx,ecx
neg edx
jmp vibrato_default
vibrato_c0:
; C0 : Sine wave
; delta = 127 sin(2 Pi x/64)
mov eax,ecx
and ecx,1Fh
shr eax,6
movzx edx,BYTE PTR [OFFSET sin127+ecx]
sbb eax,eax
xor edx,eax
sub edx,eax
vibrato_default:
movsx eax,BYTE PTR [esi+FMUSIC_CHANNEL.vibdepth-2]
imul edx ; delta *= cptr->vibdepth
sar eax,6
endif
mov [esi+FMUSIC_CHANNEL.freqdelta-2],eax
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_FREQ
ret
endif ; VIBRATO_OR_VOLSLIDE
if TREMOLO_ON
Tremolo:
; cptr+2 = ESI
if VIBRATO_OR_VOLSLIDE
push esi
add esi,FMUSIC_CHANNEL.tremolopos-FMUSIC_CHANNEL.vibpos
call VibratoOrTremolo
pop esi
else
movzx ecx,BYTE PTR [esi+FMUSIC_CHANNEL.tremolopos-2]
mov al,[esi+FMUSIC_CHANNEL.wavecontrol-2]
mov edx,ecx
add dl,[esi+FMUSIC_CHANNEL.tremolospeed-2]
and edx,3Fh
and eax,3 ; switch(cptr->wavecontrol&3)
mov [esi+FMUSIC_CHANNEL.tremolopos-2],dl
jz tremolo_c0
; C2 : Sqare wave
rol ecx,27
sbb edx,edx
xor edx,7Fh
or edx,1
dec eax
jnz tremolo_default
; C1 : Triangle wave (ramp down)
shr edx,24
ror ecx,23
add edx,ecx
neg edx
jmp tremolo_default
tremolo_c0:
; C0 : Sine wave
; delta = 127 sin(2 Pi x/64)
mov eax,ecx
and ecx,1Fh
shr eax,6
movzx edx,BYTE PTR [OFFSET sin127+ecx]
sbb eax,eax
xor edx,eax
sub edx,eax
tremolo_default:
movsx eax,BYTE PTR [esi+FMUSIC_CHANNEL.tremolodepth-2]
imul edx
sar eax,5
endif
mov [esi+FMUSIC_CHANNEL.voldelta-2],eax
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME
ret
endif ; TREMOLO_ON
if PORTATO_OR_VOLSLIDE
Portamento:
; cptr+2 = ESI
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_FREQ
mov eax,[esi+FMUSIC_CHANNEL.freq-2]
mov ecx,[esi+FMUSIC_CHANNEL.portatarget-2]
movzx edx,BYTE PTR [esi+FMUSIC_CHANNEL.portaspeed-2]
shl edx,2
sub eax,ecx
jg porta_do_sub
add eax,edx
jg _do_trim
jmp _no_trim
porta_do_sub:
sub eax,edx
jl _do_trim
_no_trim:
add ecx,eax
_do_trim:
mov [esi+FMUSIC_CHANNEL.freq-2],ecx
ret
endif ; PORTATO_OR_VOLSLIDE
if VOLUME_OR_PANENVELOPE
Envelope:
; cptr+2 = ESI
; env_iptr = ECX
; control = AL
env_type equ -4
envstopped equ -8
envdelta equ -12
env_value equ -16
valfrac equ -20
; env_tick = -24
sustain_l2 equ -26
sustain_l1 equ -27
sustain_loop equ -28
env_next equ -32
env_pos equ -36
push edi
push ebx
push ebp
mov ebp,esp
; Initialize local vars with PAN/VOL data
lea edi,[ecx+FMUSIC_INSTRUMENT.PANPoints]
xor ebx,ebx
if PANENVELOPE_ON
mov edx,DWORD PTR [edi+FMUSIC_INSTRUMENT.PANsustain-FMUSIC_INSTRUMENT.PANPoints]
mov [ebp+sustain_loop],edx ; load PANsustain, PANLoopStart and PANLoopEnd
mov cl,BYTE PTR [edi+FMUSIC_INSTRUMENT.PANtype-FMUSIC_INSTRUMENT.PANPoints]
movzx edx,BYTE PTR [edi+FMUSIC_INSTRUMENT.PANnumpoints-FMUSIC_INSTRUMENT.PANPoints]
endif
or [esi+FMUSIC_CHANNEL.notectrl-2],al ; cptr->notectrl |= control
if PANENVELOPE_ON
if VOLUMEENVELOPE_ON
cmp al,FMUSIC_VOLUME ; is it FMUSIC_VOLUME or FMUSIC_PAN?
endif
lea eax,[esi+FMUSIC_CHANNEL.envpanstopped-2]
endif
if VOLUMEENVELOPE_ON
if PANENVELOPE_ON
jnz pan_or_vol_ok
endif
; control = FMUSIC_VOLUME
add ebx,FMUSIC_CHANNEL.envvol-FMUSIC_CHANNEL.envpan
mov eax,DWORD PTR [edi+FMUSIC_INSTRUMENT.VOLsustain-FMUSIC_INSTRUMENT.PANPoints]
mov [ebp+sustain_loop],eax ; load VOLsustain, VOLLoopStart and VOLLoopEnd
mov cl,BYTE PTR [edi+FMUSIC_INSTRUMENT.VOLtype-FMUSIC_INSTRUMENT.PANPoints]
movzx edx,BYTE PTR [edi+FMUSIC_INSTRUMENT.VOLnumpoints-FMUSIC_INSTRUMENT.PANPoints]
lea eax,[esi+FMUSIC_CHANNEL.envvolstopped-2]
add edi,FMUSIC_INSTRUMENT.VOLPoints-FMUSIC_INSTRUMENT.PANPoints
pan_or_vol_ok:
endif
cmp BYTE PTR [eax],dh
jne goto_envelope_ret
push ecx ; -> env_type
push eax ; -> envstopped
lea ecx,[esi+ebx+FMUSIC_CHANNEL.envpanpos-2]
lea eax,[esi+ebx+FMUSIC_CHANNEL.envpandelta-2]
push eax ; -> envdelta
lea eax,[esi+ebx+FMUSIC_CHANNEL.envpan-2]
push eax ; -> env_value
lea eax,[esi+ebx+FMUSIC_CHANNEL.envpanfrac-2]
lea ebx,[esi+ebx+FMUSIC_CHANNEL.envpantick-2]
push eax ; -> valfrac
mov eax,[ecx]
cmp eax,edx ; if(*pos>=numpoints) envelop out of bound
push ebx ; -> env_tick
jge envelope_done
movzx eax,WORD PTR [edi+eax*4]
cmp [ebx],eax ; if(*tick == points[(*pos)<<1]) we are at the correct tick for the position
jnz add_envdelta
test BYTE PTR [ebp+env_type],FMUSIC_ENVELOPE_LOOP
jz loop_ok
movzx eax,BYTE PTR [ebp+sustain_l2]
cmp [ecx],eax
jnz loop_ok ; if((type&FMUSIC_ENVELOPE_LOOP) && *pos == loopend) handle loop
movzx eax,BYTE PTR [ebp+sustain_l1]
mov [ecx],eax ; *pos = loopstart
movzx eax,WORD PTR [edi+eax*4]
mov [ebx],eax ; *tick = points[(*pos)<<1]
loop_ok:
mov eax,[ecx]
mov [ebp+env_pos],eax
lea eax,[edi+eax*4]
dec edx
movzx ebx,WORD PTR [eax] ; get tick at this point
cmp [ecx],edx
mov edx,[eax+4]
mov edi,edx
movzx eax,WORD PTR [eax+2]
mov [ebp+env_next],edx ; get tick at next point
mov edx,[ebp+env_value]
mov [edx],eax ; *value = points[(currpos<<1)+1]
jne env_continue
; if it is at the last position, abort the envelope and continue last value
mov eax,[ebp+envstopped]
inc BYTE PTR [eax] ; *envstopped = TRUE
goto_envelope_ret:
jmp Envelope_Ret
env_continue:
shl eax,16
sub edi,eax
xchg eax,edi
xor ax,ax
; sustain
test BYTE PTR [ebp+env_type],FMUSIC_ENVELOPE_SUSTAIN
jz not_sustain
movzx edx,BYTE PTR [ebp+sustain_loop]
cmp [ebp+env_pos],edx
jne not_sustain
cmp BYTE PTR [esi+FMUSIC_CHANNEL.keyoff-2],al
je Envelope_Ret
not_sustain:
; interpolate 2 points to find delta step
inc DWORD PTR [ecx] ; (*pos)++
mov ecx,[ebp+valfrac]
mov [ecx],edi ; *valfrac = curr
mov edi,[ebp+envdelta]
movzx ecx,WORD PTR [ebp+env_next]
and DWORD PTR [edi],0 ; *envdelta = 0
sub ecx,ebx
jz envelope_done
cdq
idiv ecx
mov [edi],eax ; *envdelta = (next-curr)/(nexttick-currtick)
jmp envelope_done
add_envdelta:
; interpolate
mov eax,[ebp+envdelta]
mov ecx,[eax]
mov eax,[ebp+valfrac]
add [eax],ecx ; *valfrac += *envdelta
envelope_done:
pop edx ; <- env_tick
pop eax ; <- valfrac
pop ecx ; <- env_value
mov eax,[eax]
inc DWORD PTR [edx] ; (*tick)++
sar eax,16
mov [ecx],eax ; *value = *valfrac >> 16
Envelope_Ret:
leave
pop ebx
pop edi
ret
endif ; VOLUME_OR_PANENVELOPE
if VOLUMEBYTE_ON
VolByte:
; volume = EDX
; cptr+2 = ESI
sub edx,16
jb switch_volume
cmp edx,40h
ja switch_volume
; if(volume >= 0x10 && volume <= 0x50)
mov [esi+FMUSIC_CHANNEL.volume-2],edx
switch_volume:
mov eax,edx
and edx,0Fh
shr eax,4 ; switch(volume>>4)
sub eax,5
jz case_6
dec eax
jz case_7
dec eax
jz case_6
dec eax
jz case_7
sub eax,2
jbe case_AB
dec eax
jz case_C
dec eax
jz case_D
dec eax
jz case_E
dec eax
jnz vol_default
; case 0xF
test edx,edx
jz vol_z
shl dl,4
mov [esi+FMUSIC_CHANNEL.portaspeed-2],dl
vol_z:
and BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],NOT_FMUSIC_TRIGGER
if PORTATO_OR_VOLSLIDE
mov eax,[esi+FMUSIC_CHANNEL.period-2]
mov [esi+FMUSIC_CHANNEL.portatarget-2],eax ; cptr->portatarget = cptr->period
endif
vol_default:
ret
case_6: ; / case 8
neg edx
case_7: ; / case 9
add [esi+FMUSIC_CHANNEL.volume-2],edx
ret
case_AB:
mov [esi+eax+FMUSIC_CHANNEL.vibspeed-1],dl
ret
case_C:
shl edx,4
mov [esi+FMUSIC_CHANNEL.pan-2],edx
xchg eax,edx
case_D:
neg edx
case_E:
add [esi+FMUSIC_CHANNEL.pan-2],edx
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_PAN
ret
endif ; VOLUMEBYTE_ON
if TREMOR_ON
Tremor:
; cptr+2 = ESI
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME
mov dx,WORD PTR [esi+FMUSIC_CHANNEL.tremorpos-2]
cmp dl,dh
jbe inc_pos
mov ecx,[esi+FMUSIC_CHANNEL.volume-2]
neg ecx
mov [esi+FMUSIC_CHANNEL.voldelta-2],ecx
inc_pos:
add dh,[esi+FMUSIC_CHANNEL.tremoroff-2]
cmp dl,dh
jbe Tremor_Ret
mov dl,-1
Tremor_Ret:
inc dl
mov [esi+FMUSIC_CHANNEL.tremorpos-2],dl
ret
endif ; TREMOR_ON
SetBPM:
; bpm = ECX
test ecx,ecx
mov eax,FSOUND_MixRate*5/2
jz SetBPM_Ret
cdq
div ecx
SetBPM_Ret:
mov DWORD PTR [_mod+FMUSIC_MODULE.mixer_samplespertick],eax
ret
; Loads an XM stream into memory. Returns non-zero on success.
LoadXM:
loadxm_count1 equ -4
loadxm_numpat equ -8
loadxm_fnumpat equ -12
loadxm_count2 equ -16
loadxm_skip equ -20
loadxm_s0loopmode equ -38
loadxm_s0bytes equ -42
loadxm_s0looplen equ -48
loadxm_s0loopstart equ -52
loadxm_sample_2 equ -56
loadxm_pat_size equ -63
loadxm_pat equ -68
loadxm_tmp29 equ -91
loadxm_tmp27 equ -93
loadxm_tmp equ -120
mov eax,OFFSET _mod
push ebp
mov esi,eax
mov ebp,esp
mov edx,FMUSIC_MODULE_size
; buf : EAX
; size : EDX
call [uFMOD_fread]
xor ecx,ecx
mov eax,[esi+FMUSIC_MODULE.mixer_samplespertick]
push ecx ; -> loadxm_count1
; GOTO PATTERN DATA
lea eax,[eax+60]
; pos : EAX
; org : ECX
; !org : Z
call uFMOD_lseek
add esp,-116
push ebx
; SAVE TRACK TITLE
if INFO_API_ON
push 20 ; a title has max. 20 chars
lea edx,[esi+17]
mov edi,OFFSET szTtl
if UCODE
xor eax,eax
endif
pop ecx
loadxm_ttl:
mov al,[edx]
inc edx
cmp al,20h ; copy only printable chars
jl loadxm_ttl_ok
if UCODE
stosw
else
stosb
endif
loadxm_ttl_ok:
dec ecx
jnz loadxm_ttl
xchg eax,ecx
stosd
else
xor eax,eax
endif
; COUNT NUM. OF PATTERNS
movzx ecx,WORD PTR [esi+FMUSIC_MODULE.numorders]
movzx ebx,WORD PTR [esi+FMUSIC_MODULE.numpatternsmem]
neg ebx
mov edi,esi
sbb edx,edx
and ecx,edx
neg ebx
dec ecx
movzx edx,dl
mov [ebp+loadxm_fnumpat],ebx
if CHK4VALIDITY
cmp ecx,edx
ja loadxm_R
endif
loadxm_for_pats:
mov dl,[esi+FMUSIC_MODULE.orderlist]
cmp edx,eax
jbe loadxm_for_continue
xchg eax,edx
loadxm_for_continue:
inc esi
dec ecx
jns loadxm_for_pats
mov [ebp+loadxm_numpat],eax
inc eax
mov esi,edi
; ALLOCATE THE PATTERN ARRAY (whatever is bigger: fnumpat or numpat) & CHANNEL POOL
cmp eax,ebx
jae loadxm_pats_ok2
xchg eax,ebx
loadxm_pats_ok2:
movzx ecx,BYTE PTR [esi+FMUSIC_MODULE.numinsts]
imul ecx,FMUSIC_INSTRUMENT_size
mov [esi+FMUSIC_MODULE.numpatternsmem],ax
lea edi,[ecx+eax*FMUSIC_PATTERN_size]
mov eax,edi
sub edi,ecx
movzx ecx,BYTE PTR [esi+FMUSIC_MODULE.numchannels_xm]
if CHK4VALIDITY
cmp ecx,64
jle loadxm_numchan_ok
xor ecx,ecx
loadxm_numchan_ok:
endif
mov [esi+FMUSIC_MODULE.numchannels],ecx
mov ebx,ecx
shl ebx,7 ; *FSOUND_CHANNEL_size*2 == *FMUSIC_CHANNEL_size
if CHK4VALIDITY
jz loadxm_R
endif
mov [ebp+loadxm_count2],ecx
lea eax,[eax+ebx*2]
; numbytes : EAX
call alloc
lea edx,[eax+ebx]
mov [esi+FMUSIC_MODULE.Channels],eax
mov [esi+FMUSIC_MODULE.uFMOD_Ch],edx
mov ebx,FMUSIC_CHANNEL_size ; = FSOUND_CHANNEL_size*2
loop_2:
mov BYTE PTR [eax+FSOUND_CHANNEL.speedhi],1
mov [edx+FMUSIC_CHANNEL.cptr],eax
add eax,ebx
add edx,ebx
dec DWORD PTR [ebp+loadxm_count2]
jnz loop_2
mov [esi],edx ; FMUSIC_MODULE.pattern
add edi,edx
movzx ecx,WORD PTR [esi+FMUSIC_MODULE.defaultbpm]
mov [esi+FMUSIC_MODULE.instrument],edi
mov edi,edx
; bpm : ECX
call SetBPM
push 64
movzx ecx,WORD PTR [esi+FMUSIC_MODULE.defaultspeed]
pop DWORD PTR [esi+FMUSIC_MODULE.globalvolume]
mov [esi+FMUSIC_MODULE.speed],ecx
; ALLOCATE INSTRUMENT ARRAY
mov eax,[ebp+loadxm_fnumpat]
; READ & UNPACK PATTERNS
loadxm_load_pats:
push 9
lea eax,[ebp+loadxm_pat]
pop edx
; buf : EAX
; size : EDX
call [uFMOD_fread]
; ALLOCATE PATTERN BUFFER
mov eax,[ebp+loadxm_pat_size] ; length of pattern & packed pattern size
mov ecx,[esi+FMUSIC_MODULE.numchannels]
cmp eax,10000h
mov [edi],eax
movzx eax,ax
jb loadxm_ldpats_continue ; skip an empty pattern
if CHK4VALIDITY
cmp eax,257
sbb edx,edx
and eax,edx
jz loadxm_R
endif
mul ecx
mov [ebp+loadxm_count2],eax
lea eax,[eax+eax*4] ; x SIZE FMUSIC_NOTE
; numbytes : EAX
call alloc
mov [edi+FMUSIC_PATTERN.data],eax
xchg eax,ebx
loadxm_for_rowsxchan:
push esi
mov esi,[uFMOD_fread]
xor edx,edx
lea eax,[ebp+loadxm_skip]
inc edx
; buf : EAX
; size : EDX
call esi ; uFMOD_fread
movzx edx,BYTE PTR [ebp+loadxm_skip]
test dl,80h
jz loadxm_noskip
and edx,1
jz loadxm_nonote
mov eax,ebx ; &nptr->note
; buf : EAX
; size : EDX
call esi ; uFMOD_fread
loadxm_nonote:
test BYTE PTR [ebp+loadxm_skip],2
jz loadxm_nonumber
xor edx,edx
lea eax,[ebx+1] ; &nptr->number
inc edx
; buf : EAX
; size : EDX
call esi ; uFMOD_fread
loadxm_nonumber:
test BYTE PTR [ebp+loadxm_skip],4
jz loadxm_novolume
xor edx,edx
lea eax,[ebx+2] ; &nptr->volume
inc edx
; buf : EAX
; size : EDX
call esi ; uFMOD_fread
loadxm_novolume:
test BYTE PTR [ebp+loadxm_skip],8
jz loadxm_noeffect
xor edx,edx
lea eax,[ebx+3] ; &nptr->effect
inc edx
; buf : EAX
; size : EDX
call esi ; uFMOD_fread
loadxm_noeffect:
test BYTE PTR [ebp+loadxm_skip],16
jz loadxm_isnote97
xor edx,edx
lea eax,[ebx+4] ; &nptr->eparam
inc edx
jmp loadxm_skip_read
loadxm_noskip:
test edx,edx
jz loadxm_skip_z
mov [ebx],dl
loadxm_skip_z:
lea eax,[ebx+1]
mov dl,4
loadxm_skip_read:
; buf : EAX
; size : EDX
call esi ; uFMOD_fread
loadxm_isnote97:
pop esi
inc ebx
mov dl,BYTE PTR [esi+FMUSIC_MODULE.numinsts]
cmp [ebx],dl
jbe loadxm_number_ok
mov BYTE PTR [ebx],0
loadxm_number_ok:
add ebx,4
dec DWORD PTR [ebp+loadxm_count2]
jnz loadxm_for_rowsxchan
loadxm_ldpats_continue:
inc DWORD PTR [ebp+loadxm_count1]
mov eax,[ebp+loadxm_fnumpat]
add edi,8
cmp eax,[ebp+loadxm_count1]
ja loadxm_load_pats
; allocate and clean out any extra patterns
mov ecx,[ebp+loadxm_numpat]
cmp ecx,eax
jb loadxm_extrapats_ok
mov ebx,[esi] ; FMUSIC_MODULE.pattern
mov eax,[esi+FMUSIC_MODULE.numchannels]
push esi
lea esi,[ebx+ecx*FMUSIC_PATTERN_size]
lea edi,[eax+eax*4]
shl edi,6 ; numchannels*64*SIZE FMUSIC_NOTE
loadxm_for_extrapats:
dec DWORD PTR [ebp+loadxm_numpat]
mov eax,edi
mov BYTE PTR [esi],64 ; pptr->rows = 64
; Allocate memory for pattern buffer
; numbytes : EAX
call alloc
mov [esi+FMUSIC_PATTERN.data],eax
sub esi,FMUSIC_PATTERN_size
mov eax,[ebp+loadxm_fnumpat]
cmp [ebp+loadxm_numpat],eax
jae loadxm_for_extrapats
pop esi
loadxm_extrapats_ok:
xor eax,eax
mov [esi+FMUSIC_MODULE.mixer_samplesleft],eax
mov [esi+FMUSIC_MODULE.tick],eax
if PATTERNDELAY_ON
lea edi,[esi+FMUSIC_MODULE.patterndelay]
stosd
else
lea edi,[esi+FMUSIC_MODULE.nextorder]
endif
stosd
stosd
; Load instrument information
mov al,BYTE PTR [esi+FMUSIC_MODULE.numinsts]
test al,al
jz loadxm_ret1
mov [ebp+loadxm_count1],al
mov ebx,[esi+FMUSIC_MODULE.instrument]
loadxm_for_instrs:
push 33
lea eax,[ebp+loadxm_tmp]
pop edx
; buf : EAX
; size : EDX
call [uFMOD_fread] ; instrument size & name
mov esi,[ebp+loadxm_tmp] ; firstsampleoffset = tmp[0]
mov dl,[ebp+loadxm_tmp27]
sub esi,33
test dl,dl
jz loadxm_inst_ok
if CHK4VALIDITY
xor eax,eax
cmp DWORD PTR [ebp+loadxm_tmp29],41
sbb ecx,ecx
not ecx
or edx,ecx
cmp dl,16
ja loadxm_R ; if(numsamples > 16) goto error
endif
mov edx,208
lea eax,[ebx+FMUSIC_INSTRUMENT.keymap]
sub esi,edx
; buf : EAX
; size : EDX
call [uFMOD_fread]
loadxm_inst_ok:
xor ecx,ecx
xchg eax,esi
inc ecx ; SEEK_CUR
; pos : EAX
; org : ECX
; !org : Z
call uFMOD_lseek
lea edx,[ebx+FMUSIC_INSTRUMENT.VOLfade]
xor eax,eax
mov cx,[edx]
shl ecx,1
cmp BYTE PTR [edx+FMUSIC_INSTRUMENT.VOLnumpoints-FMUSIC_INSTRUMENT.VOLfade],2
mov [edx],cx ; iptr->VOLfade *= 2
jnb ladxm_voltype_ok
mov BYTE PTR [edx+FMUSIC_INSTRUMENT.VOLtype-FMUSIC_INSTRUMENT.VOLfade],al
ladxm_voltype_ok:
cmp BYTE PTR [edx+FMUSIC_INSTRUMENT.PANnumpoints-FMUSIC_INSTRUMENT.VOLfade],2
jnb loadxm_PANtype_ok
mov BYTE PTR [edx+FMUSIC_INSTRUMENT.PANtype-FMUSIC_INSTRUMENT.VOLfade],al
loadxm_PANtype_ok:
cmp [ebp+loadxm_tmp27],al
je loadx_for_loadsamp_end
mov [ebp+loadxm_numpat],eax
mov [ebp+loadxm_fnumpat],ebx ; FMUSIC_INSTRUMENT.sample
loadxm_for_samp:
lea eax,[ebp+loadxm_sample_2]
mov edx,[ebp+loadxm_tmp29]
; buf : EAX
; size : EDX
call [uFMOD_fread]
mov esi,[ebp+loadxm_s0loopstart]
mov edi,[ebp+loadxm_s0looplen]
mov al,[ebp+loadxm_s0bytes]
mov ecx,eax
shr eax,4 ; sample[0].bytes >>= 4
and al,1 ; [b 4] : 8/16 bit sample data
mov [ebp+loadxm_s0bytes],al
jz loadxm_s0bytes_ok
shr DWORD PTR [ebp+loadxm_sample_2],1
shr esi,1
shr edi,1
loadxm_s0bytes_ok:
mov eax,[ebp+loadxm_sample_2]
cmp eax,esi
jg loadxm_loopstart_ok
mov esi,eax
loadxm_loopstart_ok:
lea edx,[esi+edi]
sub edx,eax
js loadxm_looplen_ok
sub edi,edx
loadxm_looplen_ok:
and ecx,3 ; [b 0-1] : loop type
jz loadxm_reset_sample
test edi,edi
jnz loadxm_s0loop_ok
loadxm_reset_sample:
xor esi,esi
xor ecx,ecx
mov edi,eax
loadxm_s0loop_ok:
mov [ebp+loadxm_s0loopstart],esi
mov [ebp+loadxm_s0looplen],edi
mov [ebp+loadxm_s0loopmode],cl
lea eax,[eax+eax+26] ; sample[0].length*2+SIZE FSOUND_SAMPLE+4
; numbytes : EAX
call alloc
mov ecx,[ebp+loadxm_fnumpat]
mov [ecx],eax
; memcpy(iptr->sample[count2],sample,sizeof(FSOUND_SAMPLE))
inc DWORD PTR [ebp+loadxm_numpat]
add DWORD PTR [ebp+loadxm_fnumpat],4
push 5
xchg eax,edi
mov eax,[ebp+loadxm_numpat]
pop ecx
cmp al,[ebp+loadxm_tmp27]
lea esi,[ebp+loadxm_sample_2]
rep movsd
jb loadxm_for_samp
; Load sample data
mov [ebp+loadxm_numpat],ecx
; ebx <- FMUSIC_INSTRUMENT.sample
loadx_for_loadsamp:
mov esi,[ebx+ecx*4]
xor eax,eax
mov edx,[esi]
mov ch,[esi+FSOUND_SAMPLE.Resved]
mov cl,[esi+FSOUND_SAMPLE.bytes]
if CHK4VALIDITY
test edx,0FFC00000h
jnz loadxm_R
endif
add esi,FSOUND_SAMPLE.buff
if ADPCM_ON
cmp ch,0ADh ; ModPlug 4-bit ADPCM
jne loadxm_regular_samp
inc edx
mov edi,esi
sar edx,1
push ebx
push edx
lea edx,[edx+edx*2]
add edi,edx ; ptr = buff+compressed_length*3
; Read in the compression table
lea edx,[eax+16] ; edx = 16
lea eax,[ebp+loadxm_sample_2]
mov ebx,eax
; buf : EAX
; size : EDX
call [uFMOD_fread]
; Read in the sample data
pop edx
mov eax,edi
; buf : EAX
; size : EDX
call [uFMOD_fread]
; Decompress sample data
mov edx,esi
xor ecx,ecx ; delta
loadxm_unpack_loop:
cmp edx,edi
jge loadxm_unpack_ok
mov al,[edi]
mov ah,al
and al,0Fh
xlatb
shr ah,4
inc edi
add ch,al
mov al,ah
xlatb
add al,ch
shl eax,24
or ecx,eax
mov [edx],ecx
shr ecx,16 ; ch <- delta
add edx,4
jmp loadxm_unpack_loop
loadxm_unpack_ok:
pop ebx
jmp loadxm_chk_loop_bidi
loadxm_regular_samp:
endif
shl edx,cl ; sptr->length << sptr->bytes
mov eax,esi
; buf : EAX
; size : EDX
call [uFMOD_fread]
mov ecx,DWORD PTR [esi+FSOUND_SAMPLE._length-FSOUND_SAMPLE.buff]
lea edi,[ecx+esi] ; buff = sptr->buff+sptr->length
lea eax,[edi+ecx] ; ptr = buff+sptr->length
xor edx,edx
cmp BYTE PTR [esi+FSOUND_SAMPLE.bytes-FSOUND_SAMPLE.buff],dl
jne loadxm_16bit_ok
; Promote to 16 bits
loadxm_to16bits:
dec eax
dec edi
dec eax
mov dh,[edi]
cmp eax,edi
mov [eax],dx
ja loadxm_to16bits
xor edx,edx
loadxm_16bit_ok:
mov eax,esi
; Do delta conversion
loadxm_do_delta_conv:
add dx,[eax]
mov [eax],dx
dec ecx
lea eax,[eax+2]
jg loadxm_do_delta_conv
js loadxm_loops_ok
loadxm_chk_loop_bidi:
mov eax,DWORD PTR [esi+FSOUND_SAMPLE.looplen-FSOUND_SAMPLE.buff]
mov ecx,DWORD PTR [esi+FSOUND_SAMPLE.loopstart-FSOUND_SAMPLE.buff]
add eax,ecx
cmp BYTE PTR [esi+FSOUND_SAMPLE.loopmode-FSOUND_SAMPLE.buff],2 ; LOOP_BIDI
lea eax,[esi+eax*2]
jnz loadxm_chk_loop_normal
mov cx,[eax-2]
jmp loadxm_fix_loop
loadxm_chk_loop_normal:
cmp BYTE PTR [esi+FSOUND_SAMPLE.loopmode-FSOUND_SAMPLE.buff],1 ; LOOP_NORMAL
jnz loadxm_loops_ok
mov cx,WORD PTR [esi+ecx*2]
loadxm_fix_loop:
mov [eax],cx
loadxm_loops_ok:
inc DWORD PTR [ebp+loadxm_numpat]
mov ecx,[ebp+loadxm_numpat]
cmp cl,[ebp+loadxm_tmp27]
jb loadx_for_loadsamp
loadx_for_loadsamp_end:
add ebx,FMUSIC_INSTRUMENT_size
dec BYTE PTR [ebp+loadxm_count1]
jnz loadxm_for_instrs
loadxm_ret1:
inc eax
loadxm_R:
pop ebx
donote_R:
leave
ret
DoNote:
; mod+36 = ESI
var_mod equ -4
donote_sptr equ -8
donote_jumpflag equ -10
donote_porta equ -12
donote_oldpan equ -16
donote_currtick equ -20
donote_oldfreq equ -24
donote_iptr equ -28
; Point our note pointer to the correct pattern buffer, and to the
; correct offset in this buffer indicated by row and number of channels
mov eax,[esi+FMUSIC_MODULE.order-36]
push ebp
movzx ebx,BYTE PTR [eax+esi+FMUSIC_MODULE.orderlist-36]
mov ebp,esp
mov eax,[esi+FMUSIC_MODULE.row-36]
lea ebx,[ecx+ebx*FMUSIC_PATTERN_size]
mov ecx,[esi+FMUSIC_MODULE.numchannels-36]
if PATTERNBREAK_ON
if PATTERNJUMP_ON
mov BYTE PTR [ebp+donote_jumpflag],ch
endif
endif
mul ecx
lea edi,[eax+eax*4] ; x SIZE FMUSIC_NOTE
push esi
add edi,[ebx+FMUSIC_PATTERN.data] ; mod->pattern[mod->orderlist[mod->order]].data+(mod->row*mod->numchannels)
sub esp,24
; Loop through each channel in the row
shl ecx,7 ; x FMUSIC_CHANNEL_size
jz donote_R
push esi
mov esi,[esi+FMUSIC_MODULE.uFMOD_Ch-36]
push ebx
inc esi
inc esi
add ecx,esi
donote_for_channels:
push ecx
mov bl,[edi+FMUSIC_NOTE.eparam]
mov al,[edi+FMUSIC_NOTE.effect]
and ebx,0Fh
cmp al,FMUSIC_XM_PORTATO
je donote_doporta
cmp al,FMUSIC_XM_PORTATOVOLSLIDE
donote_doporta:
setz [ebp+donote_porta]
; First store note and instrument number if there was one
mov cl,[edi+FMUSIC_NOTE.number]
jz donote_rem_note
dec cl
js donote_rem_inst
mov [esi+FMUSIC_CHANNEL.inst-2],cl ; remember the instrument #
donote_rem_inst:
mov cl,[edi] ; get current note
dec ecx
cmp cl,96
jae donote_rem_note
mov [esi+FMUSIC_CHANNEL.note-2],cl ; remember the note
donote_rem_note:
movzx ecx,BYTE PTR [esi+FMUSIC_CHANNEL.inst-2]
mov eax,[ebp+var_mod]
imul ecx,FMUSIC_INSTRUMENT_size
add ecx,[eax+FMUSIC_MODULE.instrument-36]
movzx eax,BYTE PTR [esi+FMUSIC_CHANNEL.note-2]
cdq
mov al,[eax+ecx+FMUSIC_INSTRUMENT.keymap]
cmp al,16
mov [ebp+donote_iptr],ecx
jae donote_set_sptr
mov edx,[ecx+eax*4+FMUSIC_INSTRUMENT.sample]
donote_set_sptr:
test edx,edx
jnz donote_valid_sptr
mov edx,OFFSET DummySamp
donote_valid_sptr:
mov [ebp+donote_sptr],edx
if NOTEDELAY_ON
mov ecx,[esi+FMUSIC_CHANNEL.freq-2]
mov eax,[esi+FMUSIC_CHANNEL.volume-2]
mov [ebp+donote_oldfreq],ecx
mov ecx,[esi+FMUSIC_CHANNEL.pan-2]
mov [ebp+donote_currtick],eax
mov [ebp+donote_oldpan],ecx
endif
if TREMOLO_ON
; if there is no more tremolo, set volume to volume + last tremolo delta
mov al,[edi+FMUSIC_NOTE.effect]
cmp al,FMUSIC_XM_TREMOLO
je donote_tremolo_vol
cmp BYTE PTR [esi+FMUSIC_CHANNEL.recenteffect-2],FMUSIC_XM_TREMOLO
jne donote_tremolo_vol
mov ecx,[esi+FMUSIC_CHANNEL.voldelta-2]
add [esi+FMUSIC_CHANNEL.volume-2],ecx
donote_tremolo_vol:
mov [esi+FMUSIC_CHANNEL.recenteffect-2],al
endif
xor ecx,ecx
mov [esi+FMUSIC_CHANNEL.voldelta-2],ecx
mov [esi+FMUSIC_CHANNEL.freqdelta-2],ecx
mov BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME_OR_FREQ
; PROCESS NOTE
mov cl,[edi] ; note
dec ecx
cmp cl,96
jae donote_note_ok
; get note according to relative note
movsx eax,BYTE PTR [edx+FSOUND_SAMPLE.relative]
add ecx,eax
mov eax,[ebp+var_mod]
mov [esi+FMUSIC_CHANNEL.realnote-2],cl
; Get period according to realnote and finetune
test BYTE PTR [eax+FMUSIC_MODULE.flags-36],1
je donote_flagsn1
mov eax,[ebp+donote_sptr]
movsx eax,BYTE PTR [eax+FSOUND_SAMPLE.finetune]
cdq
shl ecx,6
sub eax,edx
sar eax,1
lea eax,[ecx+eax-7680]
neg eax
if AMIGAPERIODS_ON
jmp donote_chk_porta
donote_flagsn1:
xchg eax,ecx ; note : EAX
mov ecx,[ebp+donote_sptr] ; [sptr] : ECX
; ESI != 0
call AmigaPeriod
donote_chk_porta:
mov [esi+FMUSIC_CHANNEL.period-2],eax
else
mov [esi+FMUSIC_CHANNEL.period-2],eax
donote_flagsn1:
mov eax,[esi+FMUSIC_CHANNEL.period-2]
endif
; Frequency only changes if there are no portamento effects
cmp BYTE PTR [ebp+donote_porta],0
jne donote_freq_ok
mov [esi+FMUSIC_CHANNEL.freq-2],eax
donote_freq_ok:
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_TRIGGER
donote_note_ok:
; PROCESS INSTRUMENT NUMBER
cmp BYTE PTR [edi+FMUSIC_NOTE.number],0
je donote_zcptr_ok
mov eax,[ebp+donote_sptr]
; DESCRIPTION: Reset current channel
push edi
push 9
movzx ecx,BYTE PTR [eax+FSOUND_SAMPLE.defvol]
mov [esi+FMUSIC_CHANNEL.volume-2],ecx
pop ecx
movzx eax,BYTE PTR [eax+FSOUND_SAMPLE.defpan]
mov [esi+FMUSIC_CHANNEL.pan-2],eax
push 64
xor eax,eax
pop DWORD PTR [esi+FMUSIC_CHANNEL.envvol-2]
push 32
lea edi,[esi+FMUSIC_CHANNEL.envvoltick-2]
pop DWORD PTR [esi+FMUSIC_CHANNEL.envpan-2]
mov DWORD PTR [esi+FMUSIC_CHANNEL.fadeoutvol-2],65536
; memset(&cptr->envvoltick,0,36)
rep stosd
; Retrigger tremolo and vibrato waveforms
mov cl,[esi+FMUSIC_CHANNEL.wavecontrol-2]
pop edi
cmp cl,4Fh
jge z_tremolopos_ok
mov BYTE PTR [esi+FMUSIC_CHANNEL.tremolopos-2],al ; = 0
z_tremolopos_ok:
test cl,0Ch
jnz z_vibpos_ok
mov BYTE PTR [esi+FMUSIC_CHANNEL.vibpos-2],al ; = 0
z_vibpos_ok:
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME_OR_PAN
donote_zcptr_ok:
if VOLUMEBYTE_ON
; PROCESS VOLUME BYTE
movzx edx,BYTE PTR [edi+FMUSIC_NOTE.uvolume]
; volume : EDX
; cptr+2 : ESI
call VolByte
endif
; PROCESS KEY OFF
cmp BYTE PTR [edi],97 ; note
jae donote_set_keyoff
cmp BYTE PTR [edi+FMUSIC_NOTE.effect],FMUSIC_XM_KEYOFF
jne donote_keyoff_ok
donote_set_keyoff:
inc BYTE PTR [esi+FMUSIC_CHANNEL.keyoff-2]
donote_keyoff_ok:
; PROCESS ENVELOPES
if VOLUMEENVELOPE_ON
mov ecx,[ebp+donote_iptr]
test BYTE PTR [ecx+FMUSIC_INSTRUMENT.VOLtype],1
jz donote_no_voltype
mov al,FMUSIC_VOLUME
; cptr+2 : ESI
; env_iptr : ECX
; control : AL
call Envelope
jmp donote_volenv_ok
donote_no_voltype:
endif
cmp BYTE PTR [esi+FMUSIC_CHANNEL.keyoff-2],0
je donote_volenv_ok
and DWORD PTR [esi+FMUSIC_CHANNEL.envvol-2],0
donote_volenv_ok:
if PANENVELOPE_ON
mov ecx,[ebp+donote_iptr]
test BYTE PTR [ecx+FMUSIC_INSTRUMENT.PANtype],1
je donote_no_pantype
mov al,FMUSIC_PAN
; cptr+2 : ESI
; env_iptr : ECX
; control : AL
call Envelope
donote_no_pantype:
endif
; PROCESS VOLUME FADEOUT
cmp BYTE PTR [esi+FMUSIC_CHANNEL.keyoff-2],0
mov ecx,[ebp+donote_iptr]
je donote_fadevol_ok
movzx eax,WORD PTR [ecx+FMUSIC_INSTRUMENT.VOLfade]
sub [esi+FMUSIC_CHANNEL.fadeoutvol-2],eax
jns donote_fadevol_ok
and DWORD PTR [esi+FMUSIC_CHANNEL.fadeoutvol-2],0
donote_fadevol_ok:
; PROCESS TICK 0 EFFECTS
movzx eax,BYTE PTR [edi+FMUSIC_NOTE.effect]
dec eax ; skip FMUSIC_XM_ARPEGGIO
movzx edx,BYTE PTR [edi+FMUSIC_NOTE.eparam]
if EXTRAFINEPORTA_ON
cmp al,32
else
if TREMOR_ON
cmp al,28
else
if MULTIRETRIG_ON
cmp al,26
else
if PANSLIDE_ON
cmp al,24
else
if SETENVELOPEPOS_ON
cmp al,20
else
if GLOBALVOLSLIDE_ON
cmp al,16
else
if SETGLOBALVOLUME_ON
cmp al,15
else
if SETSPEED_ON
cmp al,14
else
cmp al,13
endif
endif
endif
endif
endif
endif
endif
endif
ja donote_s1_brk
test edx,edx
call DWORD PTR [eax*4+S1_TBL]
donote_s1_brk:
if INSTRUMENTVIBRATO_ON
push DWORD PTR [ebp+donote_iptr]
endif
push DWORD PTR [ebp+donote_sptr]
; cptr+2 : ESI
call DoFlags
sub esi,-(FMUSIC_CHANNEL_size)
pop ecx
add edi,FMUSIC_NOTE_size
cmp esi,ecx
jl donote_for_channels
pop ebx
pop esi
leave
S1_r:
ret
S1_TBL:
if PORTAUP_OR_DOWN_ON
dd S1_C1
dd S1_C1
else
dd S1_r
dd S1_r
endif
if PORTATO_ON
dd S1_C3
else
dd S1_r
endif
if VIBRATO_ON
dd S1_C4
else
dd S1_r
endif
if PORTATOVOLSLIDE_ON
dd S1_C5
else
dd S1_r
endif
if VIBRATOVOLSLIDE_ON
dd S1_C6
else
dd S1_r
endif
if TREMOLO_ON
dd S1_C7
else
dd S1_r
endif
if SETPANPOSITION_ON
dd S1_C8
else
dd S1_r
endif
if SETSAMPLEOFFSET_ON
dd S1_C9
else
dd S1_r
endif
if VOLUMESLIDE_ON
dd S1_C10
else
dd S1_r
endif
if PATTERNJUMP_ON
dd S1_C11
else
dd S1_r
endif
if SETVOLUME_ON
dd S1_C12
else
dd S1_r
endif
if PATTERNBREAK_ON
dd S1_C13
else
dd S1_r
endif
dd S1_C14
if EXTRAFINEPORTA_ON
if SETSPEED_ON
dd S1_C15
else
dd S1_r
endif
if SETGLOBALVOLUME_ON
dd S1_C16
else
dd S1_r
endif
if GLOBALVOLSLIDE_ON
dd S1_C17
else
dd S1_r
endif
dd S1_r ; unassigned effect ordinal [18]
dd S1_r ; unassigned effect ordinal [19]
dd S1_r ; skip FMUSIC_XM_KEYOFF
if SETENVELOPEPOS_ON
dd S1_C21
else
dd S1_r
endif
dd S1_r ; unassigned effect ordinal [22]
dd S1_r ; unassigned effect ordinal [23]
dd S1_r ; unassigned effect ordinal [24]
if PANSLIDE_ON
dd S1_C25
else
dd S1_r
endif
dd S1_r ; unassigned effect ordinal [26]
if MULTIRETRIG_ON
dd S1_C27
else
dd S1_r
endif
dd S1_r ; unassigned effect ordinal [28]
if TREMOR_ON
dd S1_C29
else
dd S1_r
endif
dd S1_r ; unassigned effect ordinal [30]
dd S1_r ; unassigned effect ordinal [31]
dd S1_r ; unassigned effect ordinal [32]
dd S1_C33
else
if TREMOR_ON
if SETSPEED_ON
dd S1_C15
else
dd S1_r
endif
if SETGLOBALVOLUME_ON
dd S1_C16
else
dd S1_r
endif
if GLOBALVOLSLIDE_ON
dd S1_C17
else
dd S1_r
endif
dd S1_r
dd S1_r
dd S1_r
if SETENVELOPEPOS_ON
dd S1_C21
else
dd S1_r
endif
dd S1_r
dd S1_r
dd S1_r
if PANSLIDE_ON
dd S1_C25
else
dd S1_r
endif
dd S1_r
if MULTIRETRIG_ON
dd S1_C27
else
dd S1_r
endif
dd S1_r
dd S1_C29
else
if MULTIRETRIG_ON
if SETSPEED_ON
dd S1_C15
else
dd S1_r
endif
if SETGLOBALVOLUME_ON
dd S1_C16
else
dd S1_r
endif
if GLOBALVOLSLIDE_ON
dd S1_C17
else
dd S1_r
endif
dd S1_r
dd S1_r
dd S1_r
if SETENVELOPEPOS_ON
dd S1_C21
else
dd S1_r
endif
dd S1_r
dd S1_r
dd S1_r
if PANSLIDE_ON
dd S1_C25
else
dd S1_r
endif
dd S1_r
dd S1_C27
else
if PANSLIDE_ON
if SETSPEED_ON
dd S1_C15
else
dd S1_r
endif
if SETGLOBALVOLUME_ON
dd S1_C16
else
dd S1_r
endif
if GLOBALVOLSLIDE_ON
dd S1_C17
else
dd S1_r
endif
dd S1_r
dd S1_r
dd S1_r
if SETENVELOPEPOS_ON
dd S1_C21
else
dd S1_r
endif
dd S1_r
dd S1_r
dd S1_r
dd S1_C25
else
if SETENVELOPEPOS_ON
if SETSPEED_ON
dd S1_C15
else
dd S1_r
endif
if SETGLOBALVOLUME_ON
dd S1_C16
else
dd S1_r
endif
if GLOBALVOLSLIDE_ON
dd S1_C17
else
dd S1_r
endif
dd S1_r
dd S1_r
dd S1_r
dd S1_C21
else
if GLOBALVOLSLIDE_ON
if SETSPEED_ON
dd S1_C15
else
dd S1_r
endif
if SETGLOBALVOLUME_ON
dd S1_C16
else
dd S1_r
endif
dd S1_C17
else
if SETGLOBALVOLUME_ON
if SETSPEED_ON
dd S1_C15
else
dd S1_r
endif
dd S1_C16
else
if SETSPEED_ON
dd S1_C15
endif
endif
endif
endif
endif
endif
endif
endif
if PORTAUP_OR_DOWN_ON
S1_C1:
jz donote_xm_porta_end
mov [esi+FMUSIC_CHANNEL.portaupdown-2],dl
donote_xm_porta_end:
ret
endif
if PORTATO_ON
S1_C3:
jz donote_xm_portato_end
mov [esi+FMUSIC_CHANNEL.portaspeed-2],dl
donote_xm_portato_end:
if PORTATOVOLSLIDE_ON
jmp donote_xm_portavolsl_end
else
mov eax,[esi+FMUSIC_CHANNEL.period-2]
and BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],NOT_FMUSIC_TRIGGER_OR_FRQ
mov [esi+FMUSIC_CHANNEL.portatarget-2],eax
ret
endif
endif
if PORTATOVOLSLIDE_ON
S1_C5:
jz donote_xm_portavolsl_end
mov [esi+FMUSIC_CHANNEL.volslide-2],dl
donote_xm_portavolsl_end:
mov eax,[esi+FMUSIC_CHANNEL.period-2]
and BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],NOT_FMUSIC_TRIGGER_OR_FRQ
mov [esi+FMUSIC_CHANNEL.portatarget-2],eax
ret
endif
if VIBRATO_ON
S1_C4:
shr edx,4
jz donote_vib_x_ok
mov [esi+FMUSIC_CHANNEL.vibspeed-2],dl
donote_vib_x_ok:
test ebx,ebx
jz donote_vib_y_ok
mov BYTE PTR [esi+FMUSIC_CHANNEL.vibdepth-2],bl
donote_vib_y_ok:
if VIBRATOVOLSLIDE_ON
xor eax,eax
else
; cptr+2 : ESI
jmp Vibrato
endif
endif
if VIBRATOVOLSLIDE_ON
S1_C6:
jz donote_xm_vibvolsl_end
mov [esi+FMUSIC_CHANNEL.volslide-2],dl
donote_xm_vibvolsl_end:
; cptr+2 : ESI
jmp Vibrato
endif
if TREMOLO_ON
S1_C7:
shr edx,4
jz donote_trem_x_ok
mov [esi+FMUSIC_CHANNEL.tremolospeed-2],dl
donote_trem_x_ok:
test ebx,ebx
jz donote_trem_y_ok
mov [esi+FMUSIC_CHANNEL.tremolodepth-2],bl
donote_trem_y_ok:
ret
endif
if SETPANPOSITION_ON
if PANSLIDE_ON
else
S1_C8:
mov [esi+FMUSIC_CHANNEL.pan-2],edx
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_PAN
ret
endif
endif
if SETSAMPLEOFFSET_ON
S1_C9:
shl edx,8
jz donote_soffset_ok
mov [esi+FMUSIC_CHANNEL.sampleoffset-2],edx
donote_soffset_ok:
mov ecx,[ebp+donote_sptr]
mov edx,[ecx+FSOUND_SAMPLE.loopstart]
add edx,[ecx+FSOUND_SAMPLE.looplen]
mov eax,[esi+FMUSIC_CHANNEL.sampleoffset-2]
cmp eax,edx
mov ecx,[esi+FMUSIC_CHANNEL.cptr-2]
jb donote_set_offset
xor eax,eax
and BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],NOT_FMUSIC_TRIGGER
mov [ecx+FSOUND_CHANNEL.mixpos],eax
mov [ecx+FSOUND_CHANNEL.mixposlo],eax
donote_set_offset:
mov [ecx+FSOUND_CHANNEL.fsampleoffset],eax
ret
endif
if VOLUMESLIDE_ON
S1_C10:
jz donote_volslide_ok
mov [esi+FMUSIC_CHANNEL.volslide-2],dl
donote_volslide_ok:
ret
endif
if PATTERNJUMP_ON
S1_C11:
mov eax,[ebp+var_mod]
and DWORD PTR [eax+FMUSIC_MODULE.nextrow-36],0
mov [eax+FMUSIC_MODULE.nextorder-36],edx
if PATTERNBREAK_ON
inc BYTE PTR [ebp+donote_jumpflag]
donote_set_nextord:
endif
movzx ecx,WORD PTR [eax+FMUSIC_MODULE.numorders-36]
cmp [eax+FMUSIC_MODULE.nextorder-36],ecx
jl donote_nextorder_ok
and DWORD PTR [eax+FMUSIC_MODULE.nextorder-36],0
donote_nextorder_ok:
ret
endif
if PATTERNBREAK_ON
S1_C13:
shr edx,4
lea edx,[edx+edx*4]
lea ecx,[ebx+edx*2] ; paramx*10+paramy
mov eax,[ebp+var_mod]
mov [eax+FMUSIC_MODULE.nextrow-36],ecx
if PATTERNJUMP_ON
cmp BYTE PTR [ebp+donote_jumpflag],0
jne donote_nextorder_ok
endif
mov ecx,[eax+FMUSIC_MODULE.order-36]
inc ecx
mov [eax+FMUSIC_MODULE.nextorder-36],ecx
if PATTERNJUMP_ON
jmp donote_set_nextord
else
movzx ecx,WORD PTR [eax+FMUSIC_MODULE.numorders-36]
cmp [eax+FMUSIC_MODULE.nextorder-36],ecx
jl donote_jump_pat
and DWORD PTR [eax+FMUSIC_MODULE.nextorder-36],0
donote_jump_pat:
ret
endif
endif
if SETSPEED_ON
S1_C15:
cmp dl,20h
mov ecx,edx
jae donote_setbpm
mov eax,[ebp+var_mod]
mov [eax+FMUSIC_MODULE.speed-36],ecx
ret
donote_setbpm:
; bpm : ECX
jmp SetBPM
endif
if GLOBALVOLSLIDE_ON
S1_C17:
jz donote_globalvsl_ok
mov ecx,[ebp+var_mod]
mov [ecx+FMUSIC_MODULE.globalvsl-36],dl
donote_globalvsl_ok:
ret
endif
if SETENVELOPEPOS_ON
S1_C21:
test BYTE PTR [ecx+FMUSIC_INSTRUMENT.VOLtype],1
je donote_envelope_r
lea ebx,[ecx+FMUSIC_INSTRUMENT.VOLPoints+4]
; Search and reinterpolate new envelope position
movzx ecx,BYTE PTR [ecx+FMUSIC_INSTRUMENT.VOLnumpoints]
xor eax,eax
cmp dx,[ebx]
jbe donote_env_endwhile
donote_envwhile:
cmp eax,ecx ; if(currpos == iptr->VOLnumpoints) break
je donote_env_endwhile
inc eax
cmp dx,[ebx+eax*4] ; if(current->eparam > iptr->VOLPoints[(currpos+1)<<1]) break
ja donote_envwhile
donote_env_endwhile:
mov [esi+FMUSIC_CHANNEL.envvolpos-2],eax
; if it is at the last position, abort the envelope and continue last volume
dec ecx
cmp eax,ecx
setnl [esi+FMUSIC_CHANNEL.envvolstopped-2]
jl donote_env_continue
movzx eax,WORD PTR [ebx+ecx*4-2]
mov [esi+FMUSIC_CHANNEL.envvol-2],eax ; cptr->envvol = iptr->VOLPoints[((iptr->VOLnumpoints-1)<<1)+1]
donote_envelope_r:
ret
donote_env_continue:
mov [esi+FMUSIC_CHANNEL.envvoltick-2],edx
mov ecx,[ebx+eax*4-4] ; get tick at this point + VOL at this point
mov edx,ecx
movzx ecx,cx
mov [ebp+donote_currtick],ecx
mov ecx,[ebx+eax*4] ; get tick at next point + VOL at next point
mov eax,ecx
movzx ecx,cx
xor dx,dx
; interpolate 2 points to find delta step
sub ecx,[ebp+donote_currtick]
push edx
jz donote_no_tickdiff
xor ax,ax
sub eax,edx
cdq
idiv ecx
xchg eax,ecx
donote_no_tickdiff:
mov [esi+FMUSIC_CHANNEL.envvoldelta-2],ecx
mov eax,[esi+FMUSIC_CHANNEL.envvoltick-2]
sub eax,[ebp+donote_currtick]
imul ecx
pop edx
add eax,edx
mov [esi+FMUSIC_CHANNEL.envvolfrac-2],eax
sar eax,16
mov [esi+FMUSIC_CHANNEL.envvol-2],eax
inc DWORD PTR [esi+FMUSIC_CHANNEL.envvolpos-2]
ret
endif
if PANSLIDE_ON
S1_C25:
jz donote_panslide_ok
mov [esi+FMUSIC_CHANNEL.panslide-2],dl
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_PAN
donote_panslide_ok:
ret
endif
if MULTIRETRIG_ON
S1_C27:
jz donote_multiretrig_ok
shr edx,4
mov dh,bl
mov WORD PTR [esi+FMUSIC_CHANNEL.retrigx-2],dx
donote_multiretrig_ok:
ret
endif
if TREMOR_ON
S1_C29:
jz donote_do_tremor
shr edx,4
mov dh,bl
mov WORD PTR [esi+FMUSIC_CHANNEL.tremoron-2],dx
donote_do_tremor:
; cptr : ESI
jmp Tremor
endif
if EXTRAFINEPORTA_ON
S1_C33:
shr edx,4
dec edx
jnz donote_paramx_n1
test ebx,ebx
jz donote_paramy_z1
mov [esi+FMUSIC_CHANNEL.xtraportaup-2],bl
donote_paramy_z1:
movzx eax,BYTE PTR [esi+FMUSIC_CHANNEL.xtraportaup-2]
sub [esi+FMUSIC_CHANNEL.freq-2],eax
donote_paramx_n1:
dec edx
jnz donote_paramx_n2
test ebx,ebx
jz donote_paramy_z2
mov [esi+FMUSIC_CHANNEL.xtraportadown-2],bl
donote_paramy_z2:
movzx eax,BYTE PTR [esi+FMUSIC_CHANNEL.xtraportadown-2]
add [esi+FMUSIC_CHANNEL.freq-2],eax
donote_paramx_n2:
endif
S2_r:
ret
S1_C14:
shr edx,4
dec edx ; skip FMUSIC_XM_SETFILTER
if FINEPORTAUP_ON
else
dec edx
endif
if PATTERNDELAY_ON
cmp dl,13
else
if NOTEDELAY_ON
cmp dl,12
else
if FINEVOLUMESLIDE_ON
cmp dl,10
else
if SETPANPOSITION16_ON
cmp dl,7
else
if SETTREMOLOWAVE_ON
cmp dl,6
else
if PATTERNLOOP_ON
cmp dl,5
else
cmp dl,4
endif
endif
endif
endif
endif
endif
if FINEPORTAUP_ON
ja S2_r
else
jae S2_r
endif
donote_do_special:
test ebx,ebx
jmp DWORD PTR [edx*4+S2_TBL]
S2_TBL:
if FINEPORTAUP_ON
dd S2_C1
endif
if FINEPORTADOWN_ON
dd S2_C2
else
dd S2_r
endif
dd S2_r ; skip FMUSIC_XM_SETGLISSANDO
if SETVIBRATOWAVE_ON
dd S2_C4
else
dd S2_r
endif
if SETFINETUNE_ON
dd S2_C5
else
dd S2_r
endif
if PATTERNDELAY_ON
if PATTERNLOOP_ON
dd S2_C6
else
dd S2_r
endif
if SETTREMOLOWAVE_ON
dd S2_C7
else
dd S2_r
endif
if SETPANPOSITION16_ON
dd S2_C8
else
dd S2_r
endif
dd S2_r ; skip FMUSIC_XM_RETRIG
if FINEVOLUMESLIDE_ON
dd S2_C10
dd S2_C11
else
dd S2_r
dd S2_r
endif
dd S2_r ; skip FMUSIC_XM_NOTECUT
if NOTEDELAY_ON
dd S2_C13
else
dd S2_r
endif
dd S2_C14
else
if NOTEDELAY_ON
if PATTERNLOOP_ON
dd S2_C6
else
dd S2_r
endif
if SETTREMOLOWAVE_ON
dd S2_C7
else
dd S2_r
endif
if SETPANPOSITION16_ON
dd S2_C8
else
dd S2_r
endif
dd S2_r ; skip FMUSIC_XM_RETRIG
if FINEVOLUMESLIDE_ON
dd S2_C10
dd S2_C11
else
dd S2_r
dd S2_r
endif
dd S2_r
dd S2_C13
else
if FINEVOLUMESLIDE_ON
if PATTERNLOOP_ON
dd S2_C6
else
dd S2_r
endif
if SETTREMOLOWAVE_ON
dd S2_C7
else
dd S2_r
endif
if SETPANPOSITION16_ON
dd S2_C8
else
dd S2_r
endif
dd S2_r
dd S2_C10
dd S2_C11
else
if SETPANPOSITION16_ON
if PATTERNLOOP_ON
dd S2_C6
else
dd S2_r
endif
if SETTREMOLOWAVE_ON
dd S2_C7
else
dd S2_r
endif
dd S2_C8
else
if SETTREMOLOWAVE_ON
if PATTERNLOOP_ON
dd S2_C6
else
dd S2_r
endif
dd S2_C7
else
if PATTERNLOOP_ON
dd S2_C6
endif
endif
endif
endif
endif
endif
if FINEPORTAUP_ON
S2_C1:
jz donote_finepup_ok
mov [esi+FMUSIC_CHANNEL.fineportaup-2],bl
donote_finepup_ok:
movzx eax,BYTE PTR [esi+FMUSIC_CHANNEL.fineportaup-2]
shl eax,2
sub [esi+FMUSIC_CHANNEL.freq-2],eax
ret
endif
if FINEPORTADOWN_ON
S2_C2:
jz donote_finepdown_ok
mov [esi+FMUSIC_CHANNEL.fineportadown-2],bl
donote_finepdown_ok:
movzx eax,BYTE PTR [esi+FMUSIC_CHANNEL.fineportadown-2]
shl eax,2
add [esi+FMUSIC_CHANNEL.freq-2],eax
ret
endif
if SETVIBRATOWAVE_ON
S2_C4:
and BYTE PTR [esi+FMUSIC_CHANNEL.wavecontrol-2],0F0h
or BYTE PTR [esi+FMUSIC_CHANNEL.wavecontrol-2],bl
ret
endif
if SETFINETUNE_ON
S2_C5:
mov eax,[ebp+donote_sptr]
mov [eax+FSOUND_SAMPLE.finetune],bl
ret
endif
if PATTERNLOOP_ON
S2_C6:
jnz donote_not_paramy
mov eax,[ebp+var_mod]
mov eax,[eax+FMUSIC_MODULE.row-36]
mov [esi+FMUSIC_CHANNEL.patlooprow-2],eax
ret
donote_not_paramy:
mov cl,[esi+FMUSIC_CHANNEL.patloopno-2]
dec cl
jns donote_patloopno_ok
mov ecx,ebx
donote_patloopno_ok:
mov [esi+FMUSIC_CHANNEL.patloopno-2],cl
jz donote_patloopno_end
mov eax,[esi+FMUSIC_CHANNEL.patlooprow-2]
mov ecx,[ebp+var_mod]
mov [ecx+FMUSIC_MODULE.nextrow-36],eax
donote_patloopno_end:
ret
endif
if SETTREMOLOWAVE_ON
S2_C7:
and BYTE PTR [esi+FMUSIC_CHANNEL.wavecontrol-2],0Fh
shl ebx,4
or BYTE PTR [esi+FMUSIC_CHANNEL.wavecontrol-2],bl
ret
endif
if SETPANPOSITION16_ON
S2_C8:
shl ebx,4
mov [esi+FMUSIC_CHANNEL.pan-2],ebx
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_PAN
ret
endif
if FINEVOLUMESLIDE_ON
S2_C10:
neg ebx
S2_C11:
jz donote_finevols_ok
mov [esi+FMUSIC_CHANNEL.finevslup-2],bl
donote_finevols_ok:
movsx eax,BYTE PTR [esi+FMUSIC_CHANNEL.finevslup-2]
sub [esi+FMUSIC_CHANNEL.volume-2],eax
ret
endif
if NOTEDELAY_ON
S2_C13:
mov eax,[ebp+donote_oldfreq]
mov edx,[ebp+donote_currtick]
mov [esi+FMUSIC_CHANNEL.freq-2],eax
mov eax,[ebp+donote_oldpan]
mov [esi+FMUSIC_CHANNEL.pan-2],eax
mov BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],0
if SETVOLUME_ON
else
mov [esi+FMUSIC_CHANNEL.volume-2],edx
ret
endif
endif
if SETVOLUME_ON
S1_C12:
mov [esi+FMUSIC_CHANNEL.volume-2],edx
ret
endif
if PATTERNDELAY_ON
S2_C14:
mov ecx,[ebp+var_mod]
imul ebx,DWORD PTR [ecx+FMUSIC_MODULE.speed-36]
mov [ecx+FMUSIC_MODULE.patterndelay-36],ebx
ret
endif
DoEffs:
; mod+36 = ESI
; var_mod equ -4
doeff_current equ -8
; Point our note pointer to the correct pattern buffer, and to the
; correct offset in this buffer indicated by row and number of channels
mov eax,[esi+FMUSIC_MODULE.order-36]
push ebp
mov bl,[eax+esi+FMUSIC_MODULE.orderlist-36]
mov eax,[esi+FMUSIC_MODULE.row-36]
mul DWORD PTR [esi+FMUSIC_MODULE.numchannels-36]
lea eax,[eax+eax*4] ; x SIZE FMUSIC_NOTE
mov ebp,esp
; mod->pattern[mod->orderlist[mod->order]].data+(mod->row*mod->numchannels)
add eax,[ecx+ebx*FMUSIC_PATTERN_size+FMUSIC_PATTERN.data]
push esi ; -> var_mod
push eax ; -> doeff_current
mov eax,[esi+FMUSIC_MODULE.numchannels-36]
shl eax,7 ; x FMUSIC_CHANNEL_size
push esi
mov esi,[esi+FMUSIC_MODULE.uFMOD_Ch-36]
inc esi
inc esi
add eax,esi
doeff_for_channels:
push eax
movzx edi,BYTE PTR [esi+FMUSIC_CHANNEL.inst-2]
mov edx,[ebp+var_mod]
imul edi,FMUSIC_INSTRUMENT_size
movzx eax,BYTE PTR [esi+FMUSIC_CHANNEL.note-2]
add edi,[edx+FMUSIC_MODULE.instrument-36]
cdq
mov al,[eax+edi+FMUSIC_INSTRUMENT.keymap]
cmp al,16
jae doeff_set_sptr
mov edx,[edi+eax*4+FMUSIC_INSTRUMENT.sample]
doeff_set_sptr:
test edx,edx
jnz doeff_valid_sptr
mov edx,OFFSET DummySamp
doeff_valid_sptr:
xor ebx,ebx
if INSTRUMENTVIBRATO_ON
push edi ; iptr
endif
push edx ; sptr
mov [esi+FMUSIC_CHANNEL.voldelta-2],ebx
mov [esi+FMUSIC_CHANNEL.freqdelta-2],ebx
mov [esi+FMUSIC_CHANNEL.notectrl-2],bl
; PROCESS ENVELOPES
if VOLUMEENVELOPE_ON
test BYTE PTR [edi+FMUSIC_INSTRUMENT.VOLtype],1
je doeff_no_voltype
mov al,FMUSIC_VOLUME
mov ecx,edi
; cptr+2 : ESI
; env_iptr : ECX
; control : AL
call Envelope
doeff_no_voltype:
endif
if PANENVELOPE_ON
test BYTE PTR [edi+FMUSIC_INSTRUMENT.PANtype],1
je doeff_no_pantype
mov al,FMUSIC_PAN
mov ecx,edi
; cptr+2 : ESI
; env_iptr : ECX
; control : AL
call Envelope
doeff_no_pantype:
endif
; PROCESS VOLUME FADEOUT
cmp [esi+FMUSIC_CHANNEL.keyoff-2],bl
je doeff_fadevol_ok
movzx eax,WORD PTR [edi+FMUSIC_INSTRUMENT.VOLfade]
sub [esi+FMUSIC_CHANNEL.fadeoutvol-2],eax
jns doeff_fadevol_ns
mov [esi+FMUSIC_CHANNEL.fadeoutvol-2],ebx
doeff_fadevol_ns:
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME
doeff_fadevol_ok:
if VOLUMEBYTE_ON
mov eax,[ebp+doeff_current]
movzx eax,BYTE PTR [eax+FMUSIC_NOTE.uvolume]
mov ecx,eax
shr eax,4
and cl,0Fh
sub al,6
jz doeff_case_vol6
dec eax
jz doeff_case_vol7
if VIBRATO_ON
sub al,4
jz doeff_case_volB
dec eax
dec eax
else
sub al,6
endif
jz doeff_case_volD
dec eax
if PORTATO_ON
jz doeff_case_volE
dec eax
jnz doeff_volbyte_end
; cptr+2 : ESI
call Portamento
jmp doeff_volbyte_end
else
jnz doeff_volbyte_end
endif
doeff_case_volE:
neg ecx
doeff_case_volD:
sub [esi+FMUSIC_CHANNEL.pan-2],ecx
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_PAN
jmp doeff_volbyte_end
if VIBRATO_ON
doeff_case_volB:
mov [esi+FMUSIC_CHANNEL.vibdepth-2],cl
; cptr+2 : ESI
call Vibrato
jmp doeff_volbyte_end
endif
doeff_case_vol6:
neg ecx
doeff_case_vol7:
add [esi+FMUSIC_CHANNEL.volume-2],ecx
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME
doeff_volbyte_end:
endif ; VOLUMEBYTE_ON
mov edx,[ebp+doeff_current]
movzx ebx,BYTE PTR [edx+FMUSIC_NOTE.eparam]
mov ecx,ebx
and ebx,0Fh ; grab the effect parameter y
movzx eax,BYTE PTR [edx+FMUSIC_NOTE.effect]
shr cl,4 ; grab the effect parameter x
if ARPEGGIO_ON
else
dec eax
endif
if TREMOR_ON
cmp al,29
else
if MULTIRETRIG_ON
cmp al,27
else
if PANSLIDE_ON
cmp al,25
else
if GLOBALVOLSLIDE_ON
cmp al,17
else
if RETRIG_ON
cmp al,14
else
if NOTECUT_ON
cmp al,14
else
if NOTEDELAY_ON
cmp al,14
else
cmp al,10
endif
endif
endif
endif
endif
endif
endif
if ARPEGGIO_ON
ja doeff_s3_brk
else
jae doeff_s3_brk
endif
call DWORD PTR [eax*4+S3_TBL]
doeff_s3_brk:
; cptr+2 : ESI
call DoFlags
sub esi,-(FMUSIC_CHANNEL_size)
pop eax
add DWORD PTR [ebp+doeff_current],FMUSIC_NOTE_size
cmp esi,eax
jl doeff_for_channels
pop esi
doeff_R:
leave
S3_r:
ret
S3_TBL:
if ARPEGGIO_ON
dd S3_C0
endif
if PORTAUP_ON
dd S3_C1
else
dd S3_r
endif
if PORTADOWN_ON
dd S3_C2
else
dd S3_r
endif
if PORTATO_ON
; cptr+2 : ESI
dd Portamento
else
dd S3_r
endif
if VIBRATO_ON
; cptr+2 : ESI
dd Vibrato
else
dd S3_r
endif
if PORTATOVOLSLIDE_ON
dd S3_C5
else
dd S3_r
endif
if VIBRATOVOLSLIDE_ON
dd S3_C6
else
dd S3_r
endif
if TREMOLO_ON
; cptr+2 : ESI
dd Tremolo
else
dd S3_r
endif
dd S3_r ; skip FMUSIC_XM_SETPANPOSITION
dd S3_r ; skip FMUSIC_XM_SETSAMPLEOFFSET
if VOLUMESLIDE_ON
dd S3_C10
else
dd S3_r
endif
if TREMOR_ON
dd S3_r ; skip FMUSIC_XM_PATTERNJUMP
dd S3_r ; slip FMUSIC_XM_SETVOLUME
dd S3_r ; skip FMUSIC_XM_PATTERNBREAK
dd S3_C14
dd S3_r ; skip FMUSIC_XM_SETSPEED
dd S3_r ; skip FMUSIC_XM_SETGLOBALVOLUME
if GLOBALVOLSLIDE_ON
dd S3_C17
else
dd S3_r
endif
dd S3_r ; unassigned effect ordinal [18]
dd S3_r ; unassigned effect ordinal [19]
dd S3_r ; skip FMUSIC_XM_KEYOFF
dd S3_r ; skip FMUSIC_XM_SETENVELOPEPOS
dd S3_r ; unassigned effect ordinal [22]
dd S3_r ; unassigned effect ordinal [23]
dd S3_r ; unassigned effect ordinal [24]
if PANSLIDE_ON
dd S3_C25
else
dd S3_r
endif
dd S3_r ; unassigned effect ordinal [26]
if MULTIRETRIG_ON
dd S3_C27
else
dd S3_r
endif
dd S3_r ; unassigned effect ordinal [28]
; case FMUSIC_XM_TREMOR
; cptr : ESI
dd Tremor
else
if MULTIRETRIG_ON
dd S3_r
dd S3_r
dd S3_r
dd S3_C14
dd S3_r
dd S3_r
if GLOBALVOLSLIDE_ON
dd S3_C17
else
dd S3_r
endif
dd S3_r
dd S3_r
dd S3_r
dd S3_r
dd S3_r
dd S3_r
dd S3_r
if PANSLIDE_ON
dd S3_C25
else
dd S3_r
endif
dd S3_r
dd S3_C27
else
if PANSLIDE_ON
dd S3_r
dd S3_r
dd S3_r
dd S3_C14
dd S3_r
dd S3_r
if GLOBALVOLSLIDE_ON
dd S3_C17
else
dd S3_r
endif
dd S3_r
dd S3_r
dd S3_r
dd S3_r
dd S3_r
dd S3_r
dd S3_r
dd S3_C25
else
if GLOBALVOLSLIDE_ON
dd S3_r
dd S3_r
dd S3_r
dd S3_C14
dd S3_r
dd S3_r
dd S3_C17
else
if RETRIG_ON
dd S3_r
dd S3_r
dd S3_r
dd S3_C14
else
if NOTECUT_ON
dd S3_r
dd S3_r
dd S3_r
dd S3_C14
else
if NOTEDELAY_ON
dd S3_r
dd S3_r
dd S3_r
dd S3_C14
endif
endif
endif
endif
endif
endif
endif
if VIBRATOVOLSLIDE_ON
S3_C6:
; cptr+2 : ESI
call Vibrato
if VOLUMESLIDE_ON
if PORTATOVOLSLIDE_ON
jmp S3_C10
endif
else
mov cl,[esi+FMUSIC_CHANNEL.volslide-2]
mov eax,ecx
and eax,0Fh
shr ecx,4
jz doeff_volslide_ok
; Slide up takes precedence over down
xchg eax,ecx
neg eax
doeff_volslide_ok:
sub [esi+FMUSIC_CHANNEL.volume-2],eax
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME
ret
endif
endif
if PORTATOVOLSLIDE_ON
S3_C5:
; cptr+2 : ESI
call Portamento
if VOLUMESLIDE_ON
xor ecx,ecx
else
movzx ecx,BYTE PTR [esi+FMUSIC_CHANNEL.volslide-2]
mov eax,ecx
and eax,0Fh
shr ecx,4
jz doeff_volslide_ok
; Slide up takes precedence over down
xchg eax,ecx
neg eax
doeff_volslide_ok:
sub [esi+FMUSIC_CHANNEL.volume-2],eax
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME
ret
endif
endif
if VOLUMESLIDE_ON
S3_C10:
mov cl,[esi+FMUSIC_CHANNEL.volslide-2]
mov eax,ecx
and eax,0Fh
shr ecx,4
jz doeff_volslide_ok
; Slide up takes precedence over down
xchg eax,ecx
neg eax
doeff_volslide_ok:
sub [esi+FMUSIC_CHANNEL.volume-2],eax
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME
ret
endif
if PORTADOWN_ON
S3_C2:
mov al,[esi+FMUSIC_CHANNEL.portaupdown-2]
DoFreqSlide:
mov ecx,[esi+FMUSIC_CHANNEL.freq-2]
lea ecx,[ecx+eax*4]
cmp ecx,1
jge DoFreqSlide_ok
push 1
pop ecx
DoFreqSlide_ok:
mov [esi+FMUSIC_CHANNEL.freq-2],ecx
and DWORD PTR [esi+FMUSIC_CHANNEL.freqdelta-2],0
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_FREQ
ret
endif
if PORTAUP_ON
S3_C1:
mov al,[esi+FMUSIC_CHANNEL.portaupdown-2]
if PORTADOWN_ON
neg eax
jmp DoFreqSlide
else
shl eax,2
mov ecx,[esi+FMUSIC_CHANNEL.freq-2]
sub ecx,eax
cmp ecx,1
jge DoFreqSlide_ok
push 1
pop ecx
DoFreqSlide_ok:
mov [esi+FMUSIC_CHANNEL.freq-2],ecx
and DWORD PTR [esi+FMUSIC_CHANNEL.freqdelta-2],0
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_FREQ
ret
endif
endif
if ARPEGGIO_ON
S3_C0:
cmp BYTE PTR [edx+FMUSIC_NOTE.eparam],ch
jbe doeff_arpeggio_ok
mov eax,[ebp+var_mod]
mov eax,[eax+FMUSIC_MODULE.tick-36]
push 3
cdq
pop edi
idiv edi
dec edx
jz doeff_arpeg_c1
dec edx
jne doeffs_enable_freq
mov ecx,ebx
doeff_arpeg_c1:
mov eax,[ebp+var_mod]
test BYTE PTR [eax+FMUSIC_MODULE.flags-36],1
je doeffs_flagsn1
doeffs_arpeggio_freqd:
shl ecx,6
mov [esi+FMUSIC_CHANNEL.freqdelta-2],ecx
if AMIGAPERIODS_ON
jmp doeffs_enable_freq
endif
doeffs_flagsn1:
if AMIGAPERIODS_ON
movzx eax,BYTE PTR [esi+FMUSIC_CHANNEL.realnote-2]
mov edi,eax
add eax,ecx ; note : EAX
mov ecx,[esp+4] ; [sptr] : ECX
; ESI != 0
call AmigaPeriod
xchg eax,edi ; note : EAX
mov ecx,[esp+4] ; [sptr] : ECX
; ESI != 0
call AmigaPeriod
sub edi,eax
mov [esi+FMUSIC_CHANNEL.freqdelta-2],edi
endif
doeffs_enable_freq:
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_FREQ
doeff_arpeggio_ok:
ret
endif
if MULTIRETRIG_ON
S3_C27:
mov cl,[esi+FMUSIC_CHANNEL.retrigy-2]
test ecx,ecx
jz doeff_multiretrig_ok
mov eax,[ebp+var_mod]
mov eax,[eax+FMUSIC_MODULE.tick-36]
cdq
idiv ecx
test edx,edx
jnz doeff_multiretrig_ok
mov cl,[esi+FMUSIC_CHANNEL.retrigx-2]
and ecx,0Fh
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_TRIGGER
dec ecx
mov eax,[esi+FMUSIC_CHANNEL.volume-2]
js doeff_multiretrig_ok
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME
call DWORD PTR [ecx*4+S4_TBL]
mov [esi+FMUSIC_CHANNEL.volume-2],eax
S4_C2:
dec eax
S4_C1:
dec eax
doeff_multiretrig_ok:
ret
S4_C5:
sub eax,8
S4_C4:
sub eax,4
S4_C3:
sub eax,4
ret
S4_C6:
shl eax,1
push 3
cdq
pop ecx
idiv ecx
ret
S4_C14:
lea eax,[eax+eax*2]
S4_C7:
sar eax,1
ret
S4_C10:
inc eax
S4_C9:
inc eax
ret
S4_C13:
add eax,8
S4_C12:
add eax,4
S4_C11:
add eax,4
ret
S4_C15:
shl eax,1
S4_r:
ret
S4_TBL:
dd S4_C1
dd S4_C2
dd S4_C3
dd S4_C4
dd S4_C5
dd S4_C6
dd S4_C7
dd S4_r
dd S4_C9
dd S4_C10
dd S4_C11
dd S4_C12
dd S4_C13
dd S4_C14
dd S4_C15
endif
if PANSLIDE_ON
S3_C25:
mov cl,[esi+FMUSIC_CHANNEL.panslide-2]
mov eax,ecx
and eax,0Fh
mov edx,[esi+FMUSIC_CHANNEL.pan-2]
shr ecx,4
; Slide right takes precedence over left
jnz doeff_pan_slide_right
sub edx,eax
jns doeff_panslide_ok
mov edx,ecx
jmp doeff_panslide_ok
doeff_pan_slide_right:
add ecx,edx
cdq
dec dl ; edx = 255
cmp ecx,edx
jg doeff_panslide_ok
mov edx,ecx
doeff_panslide_ok:
if SETPANPOSITION_ON
S1_C8:
endif
mov [esi+FMUSIC_CHANNEL.pan-2],edx
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_PAN
ret
endif
if GLOBALVOLSLIDE_ON
S3_C17:
mov ecx,[ebp+var_mod]
mov edx,[ecx+FMUSIC_MODULE.globalvolume-36]
mov al,[ecx+FMUSIC_MODULE.globalvsl-36]
test al,0F0h
; Slide up takes precedence over down
jnz doeff_gvsl_slide_up
and eax,0Fh
sub edx,eax
jns set_global_vol
cdq
xor eax,eax
doeff_gvsl_slide_up:
shr eax,4
add edx,eax
set_global_vol:
if SETGLOBALVOLUME_ON
else
cmp edx,64
jle doeff_setglobalvol
push 64
pop edx
doeff_setglobalvol:
mov [ecx+FMUSIC_MODULE.globalvolume-36],edx
ret
endif
endif
if SETGLOBALVOLUME_ON
S1_C16:
cmp edx,64
mov ecx,[ebp+var_mod]
jle do_setglobalvol
push 64
pop edx
do_setglobalvol:
mov [ecx+FMUSIC_MODULE.globalvolume-36],edx
ret
endif
S3_C14:
if RETRIG_ON
cmp cl,FMUSIC_XM_RETRIG
je doeff_do_retrig
endif
if NOTECUT_ON
sub cl,FMUSIC_XM_NOTECUT
jz doeff_do_notecut
endif
if NOTEDELAY_ON
if NOTECUT_ON
dec cl
else
cmp cl,FMUSIC_XM_NOTEDELAY
endif
jne doeff_special_r
mov ecx,[ebp+var_mod]
xor eax,eax
cmp [ecx+FMUSIC_MODULE.tick-36],ebx
jne doeff_notectrl_z
mov edx,[esp+4]
mov DWORD PTR [esi+FMUSIC_CHANNEL.fadeoutvol-2],65536
movzx edx,BYTE PTR [edx+FSOUND_SAMPLE.defvol]
lea ecx,[eax+9]
mov [esi+FMUSIC_CHANNEL.volume-2],edx
mov edx,[esi+FMUSIC_CHANNEL.envvol-2]
lea edi,[esi+FMUSIC_CHANNEL.envvoltick-2]
cmp ecx,edx
sbb edx,edx
and edx,64
mov [esi+FMUSIC_CHANNEL.envvol-2],edx
; memset(&cptr->envvoltick,0,36)
rep stosd
; Retrigger tremolo and vibrato waveforms
mov cl,[esi+FMUSIC_CHANNEL.wavecontrol-2]
cmp cl,4Fh
jge z2_tremolopos_ok
mov BYTE PTR [esi+FMUSIC_CHANNEL.tremolopos-2],al ; = 0
z2_tremolopos_ok:
test cl,0Ch
jnz z2_vibpos_ok
mov BYTE PTR [esi+FMUSIC_CHANNEL.vibpos-2],al ; = 0
z2_vibpos_ok:
mov eax,[esi+FMUSIC_CHANNEL.period-2]
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOL_OR_FREQ_OR_TR
mov [esi+FMUSIC_CHANNEL.freq-2],eax
if VOLUMEBYTE_ON
mov eax,[ebp+doeff_current]
movzx edx,BYTE PTR [eax+FMUSIC_NOTE.uvolume]
; volume : EDX
; cptr : ESI
jmp VolByte
else
ret
endif
doeff_notectrl_z:
mov BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],al
doeff_special_r:
endif
ret
if NOTECUT_ON
doeff_do_notecut:
mov ecx,[ebp+var_mod]
cmp [ecx+FMUSIC_MODULE.tick-36],ebx
jne doeff_notecut_ok
and DWORD PTR [esi+FMUSIC_CHANNEL.volume-2],0
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME
doeff_notecut_ok:
ret
endif
if RETRIG_ON
doeff_do_retrig:
test ebx,ebx
jz doeff_retrig_ok
mov eax,[ebp+var_mod]
mov eax,[eax+FMUSIC_MODULE.tick-36]
cdq
idiv ebx
test edx,edx
jne doeff_retrig_ok
or BYTE PTR [esi+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOL_OR_FREQ_OR_TR
doeff_retrig_ok:
ret
endif
; DESCRIPTION: Process sample flags
DoFlags:
; cptr+2 - ESI
flags_iptr equ 16
flags_sptr equ 12
mov ebx,esi
push esi
push edi
if INSTRUMENTVIBRATO_ON
; THIS GETS ADDED TO PREVIOUS FREQDELTAS
mov esi,[esp+flags_iptr]
xor eax,eax
movzx edx,BYTE PTR [esi+FMUSIC_INSTRUMENT.VIBtype]
lea edi,[ebx+FMUSIC_CHANNEL.ivibpos-2]
dec edx ; switch(iptr->VIBtype)
js ivib_case_0
mov al,128
jz ivib_case_1
dec edx
jz ivib_case_2
; case 3 / default
mov dl,-128 ; -128 = 384 on a 1byte scope
sub edx,[edi]
trim:
movzx edx,dl
sub eax,edx
sar eax,1 ; delta = (128-((384-cptr->ivibpos)&0xFF))>>1 (case 3)
; delta = (128-((cptr->ivibpos+128)&0xFF))>>1 (case 2)
jmp ivib_end_switch
ivib_case_2:
mov edx,[edi]
sub edx,eax
jmp trim
ivib_case_1:
cmp [edi],eax
sbb edx,edx
and edx,eax
lea eax,[edx-64] ; delta = +/- 64
jmp ivib_end_switch
ivib_case_0:
; delta = 64 sin(2 Pi x/256)
mov ecx,[edi]
mov edx,ecx
and ecx,7Fh
cmp ecx,65
adc eax,-1
xor ecx,eax
and eax,129
add ecx,eax
shr edx,8
movzx eax,BYTE PTR [OFFSET sin64+ecx]
sbb edx,edx
xor eax,edx
sub eax,edx
ivib_end_switch:
movzx edx,BYTE PTR [esi+FMUSIC_INSTRUMENT.iVIBdepth]
imul edx,eax ; delta *= iptr->iVIBdepth
movzx eax,BYTE PTR [esi+FMUSIC_INSTRUMENT.VIBsweep]
test eax,eax
jz sweep_ok
push edi
xchg eax,edi
mov eax,[ebx+FMUSIC_CHANNEL.ivibsweeppos-2]
imul edx
idiv edi
xchg eax,edx ; delta *= cptr->ivibsweeppos/iptr->VIBsweep
xchg eax,edi ; iptr->VIBsweep
pop edi
sweep_ok:
sar edx,6
add [ebx+FMUSIC_CHANNEL.freqdelta-2],edx ; cptr->freqdelta += delta>>6
mov edx,[ebx+FMUSIC_CHANNEL.ivibsweeppos-2]
inc edx
cmp edx,eax
jle sweeppos_ok
xchg eax,edx
sweeppos_ok:
movzx eax,BYTE PTR [esi+FMUSIC_INSTRUMENT.VIBrate]
add eax,[edi] ; cptr->ivibpos += iptr->VIBrate
mov [ebx+FMUSIC_CHANNEL.ivibsweeppos-2],edx
neg ah
or BYTE PTR [ebx+FMUSIC_CHANNEL.notectrl-2],FMUSIC_FREQ
neg ah
sbb ah,0 ; ivibpos - 256
mov [edi],eax
endif ; INSTRUMENTVIBRATO_ON
mov esi,[ebx+FMUSIC_CHANNEL.cptr-2]
test BYTE PTR [ebx+FMUSIC_CHANNEL.notectrl-2],FMUSIC_TRIGGER
jz no_trig
; TRIGGER: allocate a channel
cmp DWORD PTR [esi+FSOUND_CHANNEL.fsptr],0
jz no_swap
; Swap between channels to avoid sounds cutting each other off and causing a click
mov ecx,esi
sub ecx,DWORD PTR [OFFSET _mod+FMUSIC_MODULE.Channels]
shr ecx,7 ; /FSOUND_CHANNEL_size + 1
sbb edi,edi
and edi,-FSOUND_CHANNEL_size*2
lea edi,[esi+edi+FSOUND_CHANNEL_size]
push edi
; Copy the whole channel except it's trailing data
push (FSOUND_CHANNEL_size-20)/4
mov [ebx+FMUSIC_CHANNEL.cptr-2],edi
pop ecx
rep movsd
; This should cause the old channel to ramp out nicely
mov [esi+FSOUND_CHANNEL.actualvolume-FSOUND_CHANNEL.fsptr],ecx
mov [esi+FSOUND_CHANNEL.leftvolume-FSOUND_CHANNEL.fsptr],ecx
mov [esi+FSOUND_CHANNEL.rightvolume-FSOUND_CHANNEL.fsptr],ecx
pop esi
no_swap:
lea edi,[esi+FSOUND_CHANNEL.fsptr]
mov eax,[esp+flags_sptr]
stosd ; fsptr
; START THE SOUND!
xor eax,eax
mov edx,[esi+FSOUND_CHANNEL.fsampleoffset]
stosd ; mixposlo
stosd ; ramp_leftvolume
stosd ; ramp_rightvolume
stosd ; ramp_count, speeddir
mov [esi+FSOUND_CHANNEL.fsampleoffset],eax
mov [esi+FSOUND_CHANNEL.mixpos],edx
no_trig:
mov eax,[ebx+FMUSIC_CHANNEL.volume-2]
xor ecx,ecx
cdq
not edx
and eax,edx
cmp eax,64
jle volume_le64
lea eax,[ecx+64]
volume_le64:
dec cl ; ecx <- 255
mov [ebx+FMUSIC_CHANNEL.volume-2],eax
test BYTE PTR [ebx+FMUSIC_CHANNEL.notectrl-2],FMUSIC_VOLUME
jz no_volume
add eax,[ebx+FMUSIC_CHANNEL.voldelta-2] ; 6 bit (64)
imul DWORD PTR [ebx+FMUSIC_CHANNEL.envvol-2] ; 6 bit (64)
imul DWORD PTR [_mod+FMUSIC_MODULE.globalvolume] ; 6 bit (64)
imul ecx ; eax *= 255
imul DWORD PTR [ebx+FMUSIC_CHANNEL.fadeoutvol-2] ; 16 bit (65536)
; eax:edx /= (2 * 64 * 64 * 64 * 65536)
sar edx,3
mov eax,[esi+FSOUND_CHANNEL.actualpan]
mov [esi+FSOUND_CHANNEL.actualvolume],edx
mov edi,edx
imul edx
idiv ecx
mov [esi+FSOUND_CHANNEL.leftvolume],eax ; leftvolume <- volume*actualpan/255
mov eax,ecx
sub eax,[esi+FSOUND_CHANNEL.actualpan]
imul edi
idiv ecx
mov [esi+FSOUND_CHANNEL.rightvolume],eax
no_volume:
test BYTE PTR [ebx+FMUSIC_CHANNEL.notectrl-2],FMUSIC_PAN
jz no_pan
mov edi,128
mov eax,[ebx+FMUSIC_CHANNEL.pan-2]
sub eax,edi
cdq
xor eax,edx
sub eax,edx
sub edi,eax
mov eax,[ebx+FMUSIC_CHANNEL.envpan-2]
sar edi,5
sub eax,32
imul edi
add eax,[ebx+FMUSIC_CHANNEL.pan-2]
cdq
not edx
and eax,edx ; if(pan < 0) pan = 0
mov edi,[esi] ; actualvolume
cmp eax,ecx
mov edx,ecx
xchg eax,edi
jae pan_ae255
imul edi
idiv ecx
mov edx,edi
pan_ae255:
xchg eax,edx
mov [esi+FSOUND_CHANNEL.actualpan],eax
mov [esi+FSOUND_CHANNEL.leftvolume],edx
not al ; 255 - pan
imul DWORD PTR [esi] ; actualvolume
idiv ecx
mov [esi+FSOUND_CHANNEL.rightvolume],eax
no_pan:
test BYTE PTR [ebx+FMUSIC_CHANNEL.notectrl-2],FMUSIC_FREQ
jz no_freq
mov ecx,[ebx+FMUSIC_CHANNEL.freq-2]
xor edx,edx
add ecx,[ebx+FMUSIC_CHANNEL.freqdelta-2]
lea eax,[edx+40] ; f = 40 Hz
jle freq_bounds_ok
test BYTE PTR [_mod+FMUSIC_MODULE.flags],1
jnz modflags_n1
mov eax,0DA7790h
div ecx
xor edx,edx
jmp freq_bounds_ok
modflags_n1:
mov eax,4608
sub eax,[ebx+FMUSIC_CHANNEL.freq-2]
add eax,[ebx+FMUSIC_CHANNEL.freqdelta-2]
push eax
fild DWORD PTR [esp]
fmul DWORD PTR [f0_0013]
fld st0
frndint
fsub st1,st0
fxch st1
f2xm1
fld1
faddp st1,st0
fscale
fstp st1
fmul DWORD PTR [f8363_0]
fistp DWORD PTR [esp]
pop eax ; freq = 625.271028*exp2((4608-period)/64)
freq_bounds_ok:
mov ebx,FSOUND_MixRate
div ebx
mov [esi+FSOUND_CHANNEL.speedhi],eax
div ebx
mov [esi+FSOUND_CHANNEL.speedlo],eax
no_freq:
pop edi
pop esi
if INSTRUMENTVIBRATO_ON
ret 8
else
ret 4
endif