/programs/develop/libraries/ufmod/Fasm/frmwrk.asm |
---|
0,0 → 1,142 |
; FRMWRK.ASM |
; ---------- |
; A set of common GUI code used in uFMOD examples for KolibriOS. |
; Feel free to reuse it in your own projects if you like it ;) |
; --------------------------------------------------------------- |
; void _cdecl _MessageBox (szCap, lpString, cbString); |
; void _cdecl _MessageBoxCB(szCap, lpString, cbString, cbProc); |
; --------------------------------------------------------------- |
; This is similar to a Win32 MessageBox. The box is centered |
; on screen. It contains a single-line text message and an |
; "OK" button. This function returns when user closes the |
; box (via the X button or via the OK button). An optional |
; callback subroutine may be specified to be called when no |
; events are pending in the event queue. |
; NOTE: Doesn't work if you already have defined a window |
; in the current process! Doesn't modify the event mask. So, |
; make sure keyboard events are enabled before calling this |
; function. This function doesn't check the validity of the |
; supplied parameters! |
; Parameters: |
; szCap - A pointer to the ASCIIz string containing the |
; caption. A trailing zero char IS required. |
; lpString - A pointer to an ASCII string containing a single |
; line message to pop up in the box. No trailing |
; zero char is required. |
; cbString - number of characters in string. |
; cbProc - Address of the callback subroutine. Can be NULL. |
sOK db "OK" |
if FRMWRK_CALLBACK_ON |
_MessageBoxCB: |
else |
_MessageBox: |
end if |
push ebp |
push esi |
push edi |
push ebx |
xor ebp,ebp ; global 0 |
mov esi,[esp+28] ; cbString |
mov edi,[esp+20] ; szCap |
; Get screen metrics. |
lea eax,[ebp+14] |
int 40h |
mov ecx,eax |
movzx eax,ax |
shr ecx,16 ; screen w |
xchg eax,edx ; screen h |
lea ebx,[esi*2+esi] |
lea ebx,[ebx*2+28] ; w = string len * 6 + 28 |
sub ecx,ebx |
shr ecx,1 |
shl ecx,16 |
or ebx,ecx |
lea ecx,[ebp+52h] ; h = 52h |
sub edx,ecx |
shr edx,1 |
shl edx,16 |
or ecx,edx ; y = (screen h - window h) / 2 |
mov edx,ebx ; x = (screen w - window w) / 2 |
_MessageBoxCB_redraw: |
; Start redraw. |
push edx |
lea eax,[ebp+12] |
lea ebx,[ebp+1] |
int 40h |
; Define and draw window. |
xor eax,eax |
mov ebx,edx ; x, w (ECX: y, h) |
mov edx,34C0C0C0h ; style and BG color |
int 40h |
; Define the OK button. |
push esi |
lea eax,[ebp+8] |
sub ebx,28+0Ah |
shr bx,1 |
shl ebx,16 ; x = (window w - button w) / 2 |
mov bx,18+0Ah ; w = 18 + 0Ah |
mov ecx,001C0012h ; y = 1Ch, h = 12h |
lea edx,[ebp+1] ; ID = close |
mov esi,0C0C0C0h ; color |
int 40h |
; Draw the OK label. |
lea eax,[ebp+4] |
add ebx,90000h ; x = button x + 9 |
mov bx,22h ; y = 22h |
xor ecx,ecx ; style, font and color |
mov edx,sOK ; string |
lea esi,[ebp+2] ; length |
int 40h |
pop esi |
; Draw text string. |
lea eax,[ebp+4] |
mov ebx,000A000Ah ; x = 0Ah, y = 0Ah |
xor ecx,ecx ; style, font and color |
mov edx,[esp+28] ; lpString |
int 40h |
; End redraw. |
lea eax,[ebp+12] |
lea ebx,[ebp+2] |
int 40h |
if FRMWRK_CALLBACK_ON |
_MessageBoxCB_eventloop: |
mov edx,[esp+36] ; cbProc |
test edx,edx |
lea eax,[ebp+10] |
jz _MessageBoxCB_peekevent |
; Invoke the callback. |
call edx |
lea eax,[ebp+23] |
lea ebx,[ebp+10] ; wait for at most 0.1 sec |
_MessageBoxCB_peekevent: |
int 40h |
dec eax |
js _MessageBoxCB_eventloop |
else |
lea eax,[ebp+10] |
int 40h |
dec eax |
end if |
pop edx |
jz _MessageBoxCB_redraw |
pop ebx |
pop edi |
pop esi |
pop ebp |
ret |
/programs/develop/libraries/ufmod/Fasm/jmp2pat.asm |
---|
0,0 → 1,239 |
; JMP2PAT.ASM |
; ----------- |
; Sometimes it makes sense merging various XM tracks |
; sharing the same instruments in a single XM file. |
; This example program uses such an XM file actually |
; containing 3 tracks and the _uFMOD_Jump2Pattern |
; function to play all 3 tracks in the same file. |
; A precompiled version (not packed or whatever) is |
; available in bin\ |
use32 |
org 0 |
db 'MENUET01' |
dd 1 |
dd START ; Entry point |
dd uFMOD_IMG_END ; End of code and initialized data |
dd MEMORY_END ; End of uninitialized (BSS) data |
dd STACK_B ; Bottom of the stack |
dd 0 ; Args |
dd 0 ; Reserved |
; uFMOD setup: |
UF_FREQ equ 48000 ; Set sampling rate to 48KHz (22050, 44100, 48000) |
UF_RAMP equ STRONG ; Select STRONG interpolation (NONE, WEAK, STRONG) |
UD_MODE equ UNSAFE ; Select UNSAFE mode (NORMAL, UNSAFE) |
DEBUG equ 0 ; Skip debug-board messages |
NOLINKER equ 1 ; Select "no linker" mode |
; uFMOD constants: |
XM_MEMORY = 1 |
XM_FILE = 2 |
XM_NOLOOP = 8 |
XM_SUSPENDED = 16 |
uFMOD_MIN_VOL = 0 |
uFMOD_MAX_VOL = 25 |
uFMOD_DEFAULT_VOL = 25 |
; BLITZXMK.XM tracked by Kim (aka norki): |
; [00:07] - track #1 |
; [08:10] - track #2 |
; [11:13] - track #3 |
xm file '..\ufmodlib\media\BLITZXMK.XM' |
xm_length = $ - xm |
; Optimization: |
; This header file is suitable for blitzxmk.xm track only! |
; If you change the track, update the optimization header. |
; (Use the standart eff.inc file for a general purpose player app.) |
include '..\ufmodlib\media\blitz.eff.inc' |
; Include the GUI framework. |
FRMWRK_CALLBACK_ON equ 0 ; Disable callback |
include 'frmwrk.asm' |
; UI text messages. |
vals dd 0,8,11 ; Preset pattern indexes |
wnd_btns1 db "1 2 3 Pause " |
wnd_btns2 db "1 2 3 Resume" |
wnd_btns_l = $ - wnd_btns2 |
wnd_cap db "Jump2Pattern",0 |
err_txt db "Error" |
err_txt_l = $ - err_txt |
err_cap db ":-(",0 |
START: |
; Start playback. |
push XM_MEMORY |
push xm_length |
push xm |
call _uFMOD_LoadSong |
; Stack fixing is required here, but in this simple |
; example leaving ESP as it is won't harm. In a real |
; application you should uncomment the following line: |
; add esp,12 |
test eax,eax |
jz error |
xor ebp,ebp ; global 0 |
mov [wnd_btns],wnd_btns1 |
; Switch keyboard mode to SCANCODE. |
lea ebx,[ebp+1] |
lea eax,[ebp+66] |
mov ecx,ebx |
int 40h |
; Get screen metrics. |
lea eax,[ebp+14] |
int 40h |
mov ecx,eax |
movzx eax,ax |
shr ecx,16 ; screen w |
xchg eax,edx ; screen h |
mov ebx,wnd_btns_l*6+42 |
sub ecx,ebx |
shr ecx,1 |
shl ecx,16 |
or ebx,ecx |
lea ecx,[ebp+40h] ; h = 40h |
sub edx,ecx |
shr edx,1 |
shl edx,16 |
or ecx,edx ; y = (screen h - window h) / 2 |
mov edx,ebx ; x = (screen w - window w) / 2 |
redraw: |
; Start redraw. |
push edx |
lea eax,[ebp+12] |
lea ebx,[ebp+1] |
int 40h |
; Define and draw window. |
xor eax,eax |
mov ebx,edx ; x, w (ECX: y, h) |
mov edx,34C0C0C0h ; style and BG color |
mov edi,wnd_cap |
int 40h |
; Define the 1 2 3 Pause/Resume buttons. |
lea eax,[ebp+8] |
mov ebx,0A0012h ; x = 0Ah, w = 12h |
mov ecx,0A0012h ; y = 0Ah, h = 10h |
lea edx,[ebp+10] ; ID = #10 |
mov esi,0C0C0C0h ; color |
int 40h |
mov ebx,280012h ; x = 28h, w = 12h |
inc edx ; ID = #11 |
int 40h |
mov ebx,460012h ; x = 46h, w = 12h |
inc edx ; ID = #12 |
int 40h |
mov ebx,640030h ; x = 64h, w = 30h |
inc edx ; ID = #13 |
int 40h |
; Draw the labels. |
lea eax,[ebp+4] |
mov ebx,120011h ; x = 12h, y = 11h |
xor ecx,ecx ; style, font and color |
mov edx,[wnd_btns] ; string |
lea esi,[ebp+wnd_btns_l] ; length |
int 40h |
; End redraw. |
lea eax,[ebp+12] |
lea ebx,[ebp+2] |
int 40h |
eventloop: |
; Update the PCM buffer. |
call _uFMOD_WaveOut |
lea eax,[ebp+23] |
lea ebx,[ebp+10] ; wait for at most 0.1 sec |
int 40h |
dec eax |
js eventloop ; 0 = idle |
jz redraw ; 1 = redraw |
dec eax ; 2 = keyboard event |
jnz chk_eventbutton |
; Get key scancode. |
lea eax,[ebp+2] |
int 40h |
cmp ah,19h ; P |
je do_PauseResume |
cmp ah,13h ; R |
je do_PauseResume |
chk_kb123: |
movzx eax,ah |
sub eax,2 |
jmp do_Jump2Pat123 |
chk_eventbutton: ; 3 = button event |
lea eax,[ebp+17] |
int 40h |
cmp ah,1 ; Close |
je break_loop |
cmp ah,13 ; Pause/Resume |
jne chk_btn123 |
do_PauseResume: |
cmp BYTE [paused],1 |
mov edx,_uFMOD_Resume |
mov ebx,wnd_btns1 |
je do_Resume |
mov edx,_uFMOD_Pause |
mov ebx,wnd_btns2 |
do_Resume: |
call edx |
xor BYTE [paused],1 |
mov [wnd_btns],ebx |
jmp redraw |
chk_btn123: ; 1 2 3 |
movzx eax,ah |
sub eax,10 |
do_Jump2Pat123: |
cmp eax,3 |
jae eventloop |
push DWORD [vals+eax*4] |
call _uFMOD_Jump2Pattern |
pop eax ; fix stack |
jmp eventloop |
break_loop: |
; Stop playback. |
call _uFMOD_StopSong |
r: ; Exit. |
xor eax,eax |
dec eax |
int 40h |
error: |
push err_txt_l ; cbString |
push err_txt ; lpString |
push err_cap ; szCap |
call _MessageBox |
; add esp,16 |
jmp r |
; Include the whole uFMOD sources here. (Right after |
; your main code to avoid naming conflicts, but still |
; inside your code section.) |
macro PUBLIC symbol {} ; hide all publics |
include '..\ufmodlib\src\fasm.asm' |
wnd_btns dd ? |
paused db ? |
align 4 |
rb 1020 |
STACK_B dd ? ; Stack bottom |
MEMORY_END: ; End of uninitialized (BSS) data |
/programs/develop/libraries/ufmod/Fasm/make.bat |
---|
0,0 → 1,20 |
@echo off |
rem Make the uFMOD examples. |
rem Compiler: FASM |
rem Target OS: KolibriOS |
rem FASM Path: |
SET UF_FASM=\fasm |
if not exist "%UF_FASM%\fasm.exe" goto Err1 |
"%UF_FASM%\fasm" mini.asm mini |
"%UF_FASM%\fasm" jmp2pat.asm jmp2pat |
goto TheEnd |
:Err1 |
echo Couldn't find fasm.exe in %UF_FASM%\ |
:TheEnd |
pause |
@echo on |
cls |
/programs/develop/libraries/ufmod/Fasm/mini.asm |
---|
0,0 → 1,109 |
; MINI.ASM |
; -------- |
; Minimalistic uFMOD usage example. |
; Shows how to play an XM track in memory, |
; including proper error handling. |
; A precompiled version (not packed or whatever) is |
; available in bin\ |
use32 |
org 0 |
db 'MENUET01' |
dd 1 |
dd START ; Entry point |
dd uFMOD_IMG_END ; End of code and initialized data |
dd MEMORY_END ; End of uninitialized (BSS) data |
dd STACK_B ; Bottom of the stack |
dd 0 ; Args |
dd 0 ; Reserved |
; uFMOD setup: |
UF_FREQ equ 48000 ; Set sampling rate to 48KHz (22050, 44100, 48000) |
UF_RAMP equ STRONG ; Select STRONG interpolation (NONE, WEAK, STRONG) |
UD_MODE equ UNSAFE ; Select UNSAFE mode (NORMAL, UNSAFE) |
DEBUG equ 0 ; Skip debug-board messages |
NOLINKER equ 1 ; Select "no linker" mode |
; uFMOD constants: |
XM_MEMORY = 1 |
XM_FILE = 2 |
XM_NOLOOP = 8 |
XM_SUSPENDED = 16 |
uFMOD_MIN_VOL = 0 |
uFMOD_MAX_VOL = 25 |
uFMOD_DEFAULT_VOL = 25 |
; The XM track. |
xm file '..\ufmodlib\media\mini.xm' |
xm_length = $ - xm |
; Optimization: |
; This header file is suitable for mini.xm track only! |
; If you change the track, update the optimization header. |
; (Use the standart eff.inc file for a general purpose player app.) |
include '..\ufmodlib\media\mini.eff.inc' |
; Include the GUI framework. |
FRMWRK_CALLBACK_ON equ 1 ; Enable callback |
include 'frmwrk.asm' |
; UI text messages. |
msg_txt db "uFMOD ruleZ!" |
msg_txt_l = $ - msg_txt |
msg_cap db "FASM",0 |
err_txt db "Error" |
err_txt_l = $ - err_txt |
err_cap db ":-(",0 |
START: |
; Start playback. |
push XM_MEMORY |
push xm_length |
push xm |
call _uFMOD_LoadSong |
; Stack fixing is required here, but in this simple |
; example leaving ESP as it is won't harm. In a real |
; application you should uncomment the following line: |
; add esp,12 |
test eax,eax |
jz error |
; Wait for user input. |
push _uFMOD_WaveOut ; cbProc <- continue fetching data! |
push msg_txt_l ; cbString |
push msg_txt ; lpString |
push msg_cap ; szCap |
call _MessageBoxCB |
; add esp,16 |
; Stop playback. |
call _uFMOD_StopSong |
r: ; Exit. |
xor eax,eax |
dec eax |
int 40h |
error: |
push 0 ; cbProc <- no callback |
push err_txt_l ; cbString |
push err_txt ; lpString |
push err_cap ; szCap |
call _MessageBoxCB |
; add esp,16 |
jmp r |
; Include the whole uFMOD sources here. (Right after |
; your main code to avoid naming conflicts, but still |
; inside your code section.) |
macro PUBLIC symbol {} ; hide all publics |
include '..\ufmodlib\src\fasm.asm' |
align 4 |
rb 1020 |
STACK_B dd ? ; Stack bottom |
MEMORY_END: ; End of uninitialized (BSS) data |
/programs/develop/libraries/ufmod/Fasm |
---|
Property changes: |
Added: tsvn:logminsize |
+5 |
\ No newline at end of property |
/programs/develop/libraries/ufmod/Masm32/make.bat |
---|
0,0 → 1,35 |
@echo off |
rem Set compiler location: |
SET MASM32=\masm32 |
SET UF_FASM=\fasm |
if not exist "%MASM32%\bin\ml.exe" goto Err1 |
if not exist "%UF_FASM%\fasm.exe" goto Err2 |
"%MASM32%\bin\ml" /c /coff mini.asm |
"%MASM32%\bin\link" /DRIVER /SUBSYSTEM:NATIVE /BASE:-0x10000 /ALIGN:0x10000 /MERGE:.data=.text -ignore:4078 mini.obj ufmod.obj |
del mini.obj |
echo virtual at 0 >tmp.asm |
echo file 'mini.exe':3Ch,4 >>tmp.asm |
echo load pehea dword from 0 >>tmp.asm |
echo file 'mini.exe':pehea+0F8h,28h >>tmp.asm |
echo load physofs dword from 4+14h >>tmp.asm |
echo load mem dword from 4+8 >>tmp.asm |
echo file 'mini.exe':physofs+16,4 >>tmp.asm |
echo load sz dword from $-4 >>tmp.asm |
echo end virtual >>tmp.asm |
echo file 'mini.exe':physofs,sz >>tmp.asm |
echo store dword mem at 14h >>tmp.asm |
"%UF_FASM%\fasm" tmp.asm mini |
del mini.exe |
del tmp.asm |
goto TheEnd |
:Err1 |
echo Couldn't find ml.exe in %MASM32%\bin |
goto TheEnd |
:Err2 |
echo Couldn't find fasm.exe in %UF_FASM%\ |
:TheEnd |
pause |
cls |
/programs/develop/libraries/ufmod/Masm32/mini.asm |
---|
0,0 → 1,266 |
; MINI.ASM |
; -------- |
; Shows how to place data and code inside (!!!) the XM track. |
.386 |
.model flat |
include ufmod.inc ; uFMOD API |
.CODE |
PE_BASE db "MENUET01" |
dd 1 |
dd OFFSET _START ; Entry point |
dd OFFSET BSS_START ; End of code and initialized data |
dd OFFSET BSS_END ; End of uninitialized (BSS) data |
dd OFFSET STACK_B ; Bottom of the stack |
dd 0 ; Args |
dd 0 ; Reserved |
err_txt db "Error" |
err_txt_l EQU $ - err_txt |
_START: |
; Start playback. |
push XM_MEMORY |
push xm_length |
push BYTE PTR xm |
; Let's place the stream right inside the code section. |
xm_length EQU 905 |
xm EQU $ - PE_BASE |
xm_unused_000 LABEL BYTE |
; *** The following 60 bytes are not used. So, we'll place |
; *** some code here. |
; (the actual size and location of such gaps may be |
; found out using the Eff utility) |
call uFMOD_LoadSong |
xor ebp,ebp ; global 0 |
; Stack fixing is required here, but in this simple |
; example leaving ESP as it is won't harm. In a real |
; application you should uncomment the following line: |
; add esp,12 |
test eax,eax |
jz error |
; Wait for user input. |
push uFMOD_WaveOut ; cbProc <- continue fetching data! |
push BYTE PTR msg_txt_l ; cbString |
push OFFSET msg_txt ; lpString |
push OFFSET msg_cap ; szCap |
call MessageBoxCB |
; add esp,16 |
; Stop playback. |
call uFMOD_StopSong |
r: ; Exit. |
lea eax,[ebp-1] |
int 40h |
error: |
push ebp ; cbProc <- no callback |
push BYTE PTR err_txt_l ; cbString |
push BYTE PTR (err_txt - PE_BASE) ; lpString |
push OFFSET err_cap ; szCap |
call MessageBoxCB |
; add esp,16 |
jmp r |
org xm_unused_000 + 60 |
db 034h,000h,000h,000h,020h,000h,000h,000h,002h,000h,00Dh,000h,001h,000h,001h,000h |
db 00Ah,000h,091h,000h,000h,001h,002h,003h,004h,005h,006h,007h,000h,001h,002h,003h |
db 004h,005h,006h,007h,008h,009h,00Ah,00Bh,008h,009h,00Ch,00Bh,008h,009h,00Ah,00Bh |
db 008h,009h,00Ch,00Bh,009h,000h,000h,000h,000h,004h,000h,001h,000h,083h,016h,001h |
db 080h,080h,02Eh,001h,000h,00Eh,060h,080h,03Ah,001h,000h,00Eh,062h,081h,061h,083h |
db 035h,001h,009h,000h,000h,000h,000h,004h,000h,001h,000h,083h,016h,001h,080h,080h |
db 02Eh,001h,000h,00Eh,060h,080h,035h,001h,000h,00Eh,062h,081h,061h,083h,038h,001h |
db 009h,000h,000h,000h,000h,004h,000h,001h,000h,083h,016h,001h,080h,080h,02Eh,001h |
db 000h,00Eh,060h,080h,038h,001h,000h,00Eh,062h,080h,083h,033h,001h,009h,000h,000h |
db 000h,000h,006h,000h,001h,000h,083h,016h,001h,080h,080h,02Eh,001h,000h,00Eh,060h |
db 080h,033h,001h,000h,00Eh,061h,081h,061h,083h,035h,001h,083h,00Dh,001h,083h,036h |
db 001h,080h,083h,036h,001h,009h,000h,000h,000h,000h,004h,000h,001h,000h,083h,00Fh |
db 001h,080h,080h,02Eh,001h,000h,00Eh,060h,080h,036h,001h,000h,00Eh,062h,081h,061h |
db 083h,033h,001h,009h,000h,000h,000h,000h,006h,000h,001h,000h,083h,00Fh,001h,080h |
db 080h,02Eh,001h,000h,00Eh,060h,080h,033h,001h,000h,00Eh,061h,081h,061h,083h,02Eh |
db 001h,083h,012h,001h,083h,033h,001h,080h,083h,035h,001h,009h,000h,000h,000h,000h |
db 006h,000h,001h,000h,083h,016h,001h,080h,080h,02Eh,001h,000h,00Eh,060h,080h,035h |
db 001h,000h,00Eh,061h,081h,061h,083h,02Eh,001h,083h,00Dh,001h,083h,031h,001h,080h |
db 083h,02Eh,001h,009h,000h,000h,000h,000h,008h,000h,001h,000h,083h,012h,001h,098h |
db 00Ah,001h,083h,019h,001h,088h,00Ah,083h,01Eh,001h,081h,061h,083h,012h,001h,080h |
db 083h,014h,001h,080h,083h,01Bh,001h,080h,083h,020h,001h,080h,083h,014h,001h,080h |
db 009h,000h,000h,000h,000h,008h,000h,001h,000h,083h,012h,001h,081h,061h,083h,019h |
db 001h,080h,083h,01Eh,001h,080h,083h,012h,001h,080h,083h,019h,001h,083h,031h,001h |
db 083h,01Eh,001h,080h,083h,012h,001h,083h,031h,001h,083h,019h,001h,080h,009h,000h |
db 000h,000h,000h,008h,000h,001h,000h,083h,014h,001h,083h,033h,001h,083h,01Bh,001h |
db 080h,083h,020h,001h,083h,031h,001h,083h,014h,001h,080h,083h,01Bh,001h,083h,030h |
db 001h,083h,020h,001h,080h,083h,014h,001h,083h,031h,001h,083h,01Bh,001h,080h,009h |
db 000h,000h,000h,000h,008h,000h,001h,000h,083h,016h,001h,083h,030h,001h,083h,01Dh |
db 001h,083h,031h,001h,083h,022h,001h,083h,035h,001h,083h,016h,001h,098h,00Ah,001h |
db 083h,01Dh,001h,088h,00Ah,083h,022h,001h,081h,061h,083h,016h,001h,080h,083h,01Dh |
db 001h,080h,009h,000h,000h,000h,000h,008h,000h,001h,000h,083h,016h,001h,080h,083h |
db 01Dh,001h,080h,083h,022h,001h,080h,083h,016h,001h,080h,083h,018h,001h,080h,083h |
db 01Dh,001h,080h,083h,011h,001h,080h,083h,018h,001h,080h,009h,000h,000h,000h,000h |
db 008h,000h,001h,000h,083h,016h,001h,083h,030h,001h,083h,01Dh,001h,083h,031h,001h |
db 083h,019h,001h,083h,02Eh,001h,083h,016h,001h,098h,00Ah,001h,083h,01Dh,001h,088h |
db 00Ah,083h,019h,001h,081h,061h,083h,016h,001h,080h,083h,01Dh,001h,080h,0F1h,000h |
db 000h,000h |
xm_unused_001 LABEL BYTE |
; The following 23 bytes are not used. |
; So, let's place the MessageBox text and caption instead. |
; UI text messages. |
msg_txt db "uFMOD ruleZ!" |
msg_txt_l equ $ - msg_txt |
msg_cap db "MASM32",0 |
err_cap db ":-(",0 |
org xm_unused_001 + 23 |
db 001h,000h,012h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h |
db 000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h |
db 000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h |
db 000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h |
db 000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h |
db 000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h,000h |
db 000h,000h,000h,000h,000h,000h,000h,000h,040h,000h,008h,000h,02Ch,000h,00Eh,000h |
db 008h,000h,018h,000h,016h,000h,020h,000h,008h,000h,02Dh,000h,00Dh,000h,032h,000h |
db 004h,000h,03Ch,000h,007h,000h,044h,000h,004h,000h,05Ah,000h,000h,000h,064h,000h |
db 000h,000h,06Eh,000h,000h,000h,000h,000h,020h,000h,00Ah,000h,028h,000h,01Eh,000h |
db 018h,000h,032h,000h,020h,000h,03Ch,000h,020h,000h,046h,000h,020h,000h,050h,000h |
db 020h,000h,05Ah,000h,020h,000h,064h,000h,020h,000h,06Eh,000h,020h,000h,078h,000h |
db 020h,000h,082h,000h,020h,000h,009h,006h,001h,002h,004h,002h,003h,005h,001h,000h |
db 000h,000h,000h,000h,080h,000h,00Ch,000h,000h,000h,000h,000h,000h,000h,00Ch,000h |
db 000h,000h,040h,000h,001h,080h,0F9h,000h,0BFh,000h,0C3h,000h,00Ah,000h,057h,000h |
db 06Eh,000h,023h,000h |
; ---------------------------------------------------------- |
; void MessageBoxCB(szCap, lpString, cbString, cbProc); |
; ---------------------------------------------------------- |
; This is similar to a Win32 MessageBox. The box is centered |
; on screen. It contains a single-line text message and an |
; "OK" button. This function returns when user closes the |
; box (via the X button or via the OK button). An optional |
; callback subroutine may be specified to be called when no |
; events are pending in the event queue. |
; NOTE: Doesn't work if you already have defined a window |
; in the current process! Doesn't modify the event mask. So, |
; make sure keyboard events are enabled before calling this |
; function. This function doesn't check the validity of the |
; supplied parameters! |
; Parameters: |
; szCap - A pointer to the ASCIIz string containing the |
; caption. A trailing zero char IS required. |
; lpString - A pointer to an ASCII string containing a single |
; line message to pop up in the box. No trailing |
; zero char is required. |
; cbString - number of characters in string. |
; cbProc - Address of the callback subroutine. Can be NULL. |
sOK db "OK" |
MessageBoxCB: |
; EBP = 0 |
mov esi,[esp+12] ; cbString |
mov edi,[esp+4] ; szCap |
; Get screen metrics. |
lea eax,[ebp+14] |
int 40h |
mov ecx,eax |
movzx eax,ax |
shr ecx,16 ; screen w |
xchg eax,edx ; screen h |
lea ebx,[esi*2+esi] |
lea ebx,[ebx*2+28] ; w = string len * 6 + 28 |
sub ecx,ebx |
shr ecx,1 |
shl ecx,16 |
or ebx,ecx |
lea ecx,[ebp+52h] ; h = 52h |
sub edx,ecx |
shr edx,1 |
shl edx,16 |
or ecx,edx ; y = (screen h - window h) / 2 |
mov edx,ebx ; x = (screen w - window w) / 2 |
_MessageBoxCB_redraw: |
; Start redraw. |
push edx |
lea eax,[ebp+12] |
lea ebx,[ebp+1] |
int 40h |
; Define and draw window. |
xor eax,eax |
mov ebx,edx ; x, w (ECX: y, h) |
mov edx,34C0C0C0h ; style and BG color |
int 40h |
; Define the OK button. |
push esi |
lea eax,[ebp+8] |
sub ebx,28+0Ah |
shr bx,1 |
shl ebx,16 ; x = (window w - button w) / 2 |
mov bx,18+0Ah ; w = 18 + 0Ah |
mov ecx,001C0012h ; y = 1Ch, h = 12h |
lea edx,[ebp+1] ; ID = close |
mov esi,0C0C0C0h ; color |
int 40h |
; Draw the OK label. |
lea eax,[ebp+4] |
add ebx,90000h ; x = button x + 9 |
mov bx,22h ; y = 22h |
xor ecx,ecx ; style, font and color |
mov edx,OFFSET sOK ; string |
lea esi,[ebp+2] ; length |
int 40h |
pop esi |
; Draw text string. |
lea eax,[ebp+4] |
mov ebx,000A000Ah ; x = 0Ah, y = 0Ah |
xor ecx,ecx ; style, font and color |
mov edx,[esp+12] ; lpString |
int 40h |
; End redraw. |
lea eax,[ebp+12] |
lea ebx,[ebp+2] |
int 40h |
_MessageBoxCB_eventloop: |
mov edx,[esp+20] ; cbProc |
test edx,edx |
lea eax,[ebp+10] |
jz _MessageBoxCB_peekevent |
; Invoke the callback. |
call edx |
lea eax,[ebp+23] |
lea ebx,[ebp+10] ; wait for at most 0.1 sec |
_MessageBoxCB_peekevent: |
int 40h |
dec eax |
js _MessageBoxCB_eventloop |
pop edx |
jz _MessageBoxCB_redraw |
ret |
.DATA? |
BSS_START LABEL BYTE |
db 1020 dup (?) |
STACK_B dd ? ; Stack bottom |
BSS_END LABEL BYTE |
END _START |
/programs/develop/libraries/ufmod/Masm32/ufmod.inc |
---|
0,0 → 1,241 |
; uFMOD header file |
; Target OS: KolibriOS |
; Compiler: MASM32 |
; HANDLE uFMOD_LoadSong( |
; void *lpXM, |
; void *param, |
; int fdwSong |
; ) |
; --- |
; Description: |
; --- |
; Loads the given XM song and starts playing it as soon as you |
; call uFMOD_WaveOut for the first time. Playback won't begin |
; if XM_SUSPENDED flag is specified. It will stop any currently |
; playing song before loading the new one. |
; --- |
; Parameters: |
; --- |
; lpXM |
; Specifies the song to load. If this parameter is 0, any |
; currently playing song is stopped. In such a case, function |
; does not return a meaningful value. fdwSong parameter |
; determines whether this value is interpreted as a filename |
; or as a pointer to an image of the song in memory. |
; param |
; If XM_MEMORY is specified, this parameter should be the size |
; of the image of the song in memory. |
; If XM_FILE is specified, this parameter is ignored. |
; fdwSong |
; Flags for playing the song. The following values are defined: |
; XM_FILE lpXM points to filename. param is ignored. |
; XM_MEMORY lpXM points to an image of a song in memory. |
; param is the image size. Once, uFMOD_LoadSong |
; returns, it's safe to free/discard the memory |
; buffer. |
; XM_NOLOOP An XM track plays repeatedly by default. Specify |
; this flag to play it only once. |
; XM_SUSPENDED The XM track is loaded in a suspended state, |
; and will not play until the uFMOD_Resume function |
; is called. This is useful for preloading a song |
; or testing an XM track for validity. |
; --- |
; Return Values: |
; --- |
; On success, returns the handle of the Infinity Sound driver. |
; Returns 0 on failure. |
uFMOD_LoadSong PROTO C :DWORD,:DWORD,:DWORD |
; int uFMOD_WaveOut(void) |
; --- |
; Description: |
; --- |
; Updates the internal playback buffer. |
; --- |
; Remarks: |
; --- |
; This function should be called from the same thread |
; uFMOD_LoadSong was previously called. Playback doesn't actually |
; begin when calling uFMOD_LoadSong, but when calling uFMOD_WaveOut |
; after a successful uFMOD_LoadSong call. Afterwards, you should |
; call uFMOD_WaveOut repeatedly at least once every 250 ms to |
; prevent "buffer underruns". |
; uFMOD_WaveOut is a non-blocking function. The accuracy of the |
; InfoAPI functions (uFMOD_GetStats, uFMOD_GetRowOrder and |
; uFMOD_GetTime) depends on the periodicity of this function being |
; invoked. |
; --- |
; Return Values: |
; --- |
; Returns non zero on error. |
uFMOD_WaveOut PROTO C |
; void uFMOD_StopSong(void) |
; --- |
; Description: |
; --- |
; Stops the currently playing song, freeing the associated |
; resources. |
; --- |
; Remarks: |
; --- |
; Does nothing if no song is playing at the time the call is made. |
uFMOD_StopSong PROTO C |
; void uFMOD_Jump2Pattern( |
; unsigned int pat |
; ) |
; --- |
; Description: |
; --- |
; Jumps to the specified pattern index. |
; --- |
; Parameters: |
; --- |
; pat |
; Next zero based pattern index. |
; --- |
; Remarks: |
; --- |
; uFMOD doesn't automatically perform Note Off effects before jumping |
; to the target pattern. In other words, the original pattern will |
; remain in the mixer until it fades out. You can use this feature to |
; your advantage. If you don't like it, just insert leading Note Off |
; commands in all patterns intended to be used as uFMOD_Jump2Pattern |
; targets. |
; if the pattern index lays outside of the bounds of the pattern order |
; table, calling this function jumps to pattern 0, effectively |
; rewinding playback. |
uFMOD_Jump2Pattern PROTO C :DWORD |
; void uFMOD_Pause(void) |
; --- |
; Description: |
; --- |
; Pauses the currently playing song, if any. |
; --- |
; Remarks: |
; --- |
; While paused you can still control the volume (uFMOD_SetVolume) and |
; the pattern order (uFMOD_Jump2Pattern). The RMS volume coefficients |
; (uFMOD_GetStats) will go down to 0 and the progress tracker |
; (uFMOD_GetTime) will "freeze" while the song is paused. |
; uFMOD_Pause doesn't perform the request immediately. Instead, it |
; signals to pause when playback reaches next chunk of data. |
; This way, uFMOD_Pause performs asynchronously and returns very fast. |
; It is not cumulative. So, calling uFMOD_Pause many times in a row |
; has the same effect as calling it once. |
; You shouldn't stop calling uFMOD_WaveOut while the song is paused! |
uFMOD_Pause PROTO C |
; void uFMOD_Resume(void) |
; --- |
; Description: |
; --- |
; Resumes the currently paused song, if any. |
; --- |
; Remarks: |
; --- |
; uFMOD_Resume doesn't perform the request immediately. Instead, it |
; signals to resume when uFMOD_WaveOut is called again. uFMOD_Resume |
; is not cumulative. So, calling it many times in a row has the same |
; effect as calling it once. |
uFMOD_Resume PROTO C |
; unsigned int uFMOD_GetStats(void) |
; --- |
; Description: |
; --- |
; Returns the current RMS volume coefficients in (L)eft and (R)ight |
; channels. |
; low-order word: RMS volume in R channel |
; hi-order word: RMS volume in L channel |
; Range from 0 (silence) to $7FFF (maximum) on each channel. |
; --- |
; Remarks: |
; --- |
; This function is useful for updating a VU meter. It's recommended |
; to rescale the output to log10 (decibels or dB for short), because |
; human ears track volume changes in a dB scale. You may call |
; uFMOD_GetStats() as often as you like, but take in mind that uFMOD |
; updates both channel RMS volumes at the same rate uFMOD_WaveOut |
; function is called. In other words, you should call uFMOD_WaveOut |
; more often to increase the accuracy of uFMOD_GetStats. |
uFMOD_GetStats PROTO C |
; unsigned int uFMOD_GetRowOrder(void) |
; --- |
; Description: |
; --- |
; Returns the currently playing row and order. |
; low-order word: row |
; hi-order word: order |
; --- |
; Remarks: |
; --- |
; This function is useful for synchronization. uFMOD updates both |
; row and order values at the same rate uFMOD_WaveOut function is |
; called. In other words, you should call uFMOD_WaveOut more often |
; to increase the accuracy of uFMOD_GetRowOrder. |
uFMOD_GetRowOrder PROTO C |
; unsigned int uFMOD_GetTime(void) |
; --- |
; Description: |
; --- |
; Returns the time in milliseconds since the song was started. |
; --- |
; Remarks: |
; --- |
; This function is useful for synchronizing purposes. Multimedia |
; applications can use uFMOD_GetTime to synchronize GFX to sound, |
; for example. An XM player can use this function to update a progress |
; meter. |
uFMOD_GetTime PROTO C |
; unsigned char* uFMOD_GetTitle(void) |
; --- |
; Description: |
; --- |
; Returns the current song's title. |
; --- |
; Remarks: |
; --- |
; Not every song has a title, so be prepared to get an empty string. |
uFMOD_GetTitle PROTO C |
; void uFMOD_SetVolume( |
; unsigned int vol |
; ) |
; --- |
; Description: |
; --- |
; Sets the global volume. The volume scale is linear. |
; --- |
; Parameters: |
; --- |
; vol |
; New volume. Range: from uFMOD_MIN_VOL (muting) to uFMOD_MAX_VOL |
; (maximum volume). Any value above uFMOD_MAX_VOL maps to maximum |
; volume. |
; --- |
; Remarks: |
; --- |
; uFMOD internally converts the given values to a logarithmic scale (dB). |
; Maximum volume is set by default. The volume value is preserved across |
; uFMOD_LoadSong calls. You can set the desired volume level before |
; actually starting to play a song. |
; You can use Infinity Sound API to control the L and R channels volumes |
; separately. It also has a wider range than uFMOD_SetVolume, sometimes |
; allowing to amplify the sound volume as well, as opposed to |
; uFMOD_SetVolume only being able to attenuate it. |
uFMOD_SetVolume PROTO C :DWORD |
XM_MEMORY EQU 1 |
XM_FILE EQU 2 |
XM_NOLOOP EQU 8 |
XM_SUSPENDED EQU 16 |
uFMOD_MIN_VOL EQU 0 |
uFMOD_MAX_VOL EQU 25 |
uFMOD_DEFAULT_VOL EQU 25 |
/programs/develop/libraries/ufmod/Masm32/ufmod.obj |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/programs/develop/libraries/ufmod/Masm32 |
---|
Property changes: |
Added: tsvn:logminsize |
+5 |
\ No newline at end of property |
/programs/develop/libraries/ufmod/Nasm/make.bat |
---|
0,0 → 1,18 |
@echo off |
rem Compiler: NASM |
rem Target OS: KolibriOS |
rem NASM Path: |
SET UF_NASM=\nasm |
if not exist "%UF_NASM%\nasmw.exe" goto Err1 |
"%UF_NASM%\nasmw" -fbin -t -O5 -i..\ufmodlib\src\ mini.asm |
goto TheEnd |
:Err1 |
echo Couldn't find nasmw.exe in %UF_NASM%\ |
:TheEnd |
pause |
@echo on |
cls |
/programs/develop/libraries/ufmod/Nasm/mini.asm |
---|
0,0 → 1,225 |
; MINI.ASM |
; -------- |
; Minimalistic uFMOD usage example. |
; Shows how to play an XM track in memory, |
; including proper error handling. |
BITS 32 |
org 0 |
db "MENUET01" |
dd 1 |
dd START ; Entry point |
dd uFMOD_IMG_END ; End of code and initialized data |
dd MEMORY_END ; End of uninitialized (BSS) data |
dd STACK_B ; Bottom of the stack |
dd 0 ; Args |
dd 0 ; Reserved |
; uFMOD setup: |
%define f48000 ; Set sampling rate to 48KHz (22050, 44100, 48000) |
%define STRONG ; Select STRONG interpolation (NONE, WEAK, STRONG) |
%define UNSAFE ; Select UNSAFE mode (NORMAL, UNSAFE) |
%define NODEBUG ; Skip debug-board messages |
%define NOLINKER ; Select "no linker" mode |
; uFMOD constants: |
%define uFMOD_MIN_VOL 0 |
%define uFMOD_MAX_VOL 25 |
%define uFMOD_DEFAULT_VOL 25 |
; The XM track. |
xm incbin "..\ufmodlib\media\mini.xm" |
xm_length equ $ - xm |
; Optimization: |
; This header file is suitable for mini.xm track only! |
; If you change the track, update the optimization header. |
; (Use the standart eff.inc file for a general purpose player app.) |
%include "..\ufmodlib\media\mini.eff.inc" |
; UI text messages. |
msg_txt db "uFMOD ruleZ!" |
msg_txt_l equ $ - msg_txt |
msg_cap db "NASM",0 |
err_txt db "Error" |
err_txt_l equ $ - err_txt |
err_cap db ":-(",0 |
START: |
; Start playback. |
push XM_MEMORY |
push xm_length |
push xm |
call _uFMOD_LoadSong |
; Stack fixing is required here, but in this simple |
; example leaving ESP as it is won't harm. In a real |
; application you should uncomment the following line: |
; add esp,12 |
test eax,eax |
jz error |
; Wait for user input. |
push _uFMOD_WaveOut ; cbProc <- continue fetching data! |
push msg_txt_l ; cbString |
push msg_txt ; lpString |
push msg_cap ; szCap |
call _MessageBoxCB |
; add esp,16 |
; Stop playback. |
call _uFMOD_StopSong |
r: ; Exit. |
xor eax,eax |
dec eax |
int 40h |
error: |
push 0 ; cbProc <- no callback |
push err_txt_l ; cbString |
push err_txt ; lpString |
push err_cap ; szCap |
call _MessageBoxCB |
; add esp,16 |
jmp r |
; --------------------------------------------------------------- |
; void _cdecl _MessageBoxCB(szCap, lpString, cbString, cbProc); |
; --------------------------------------------------------------- |
; This is similar to a Win32 MessageBox. The box is centered |
; on screen. It contains a single-line text message and an |
; "OK" button. This function returns when user closes the |
; box (via the X button or via the OK button). An optional |
; callback subroutine may be specified to be called when no |
; events are pending in the event queue. |
; NOTE: Doesn't work if you already have defined a window |
; in the current process! Doesn't modify the event mask. So, |
; make sure keyboard events are enabled before calling this |
; function. This function doesn't check the validity of the |
; supplied parameters! |
; Parameters: |
; szCap - A pointer to the ASCIIz string containing the |
; caption. A trailing zero char IS required. |
; lpString - A pointer to an ASCII string containing a single |
; line message to pop up in the box. No trailing |
; zero char is required. |
; cbString - number of characters in string. |
; cbProc - Address of the callback subroutine. Can be NULL. |
sOK db "OK" |
_MessageBoxCB: |
push ebp |
push esi |
push edi |
push ebx |
xor ebp,ebp ; global 0 |
mov esi,[esp+28] ; cbString |
mov edi,[esp+20] ; szCap |
; Get screen metrics. |
lea eax,[ebp+14] |
int 40h |
mov ecx,eax |
movzx eax,ax |
shr ecx,16 ; screen w |
xchg eax,edx ; screen h |
lea ebx,[esi*2+esi] |
lea ebx,[ebx*2+28] ; w = string len * 6 + 28 |
sub ecx,ebx |
shr ecx,1 |
shl ecx,16 |
or ebx,ecx |
lea ecx,[ebp+52h] ; h = 52h |
sub edx,ecx |
shr edx,1 |
shl edx,16 |
or ecx,edx ; y = (screen h - window h) / 2 |
mov edx,ebx ; x = (screen w - window w) / 2 |
_MessageBoxCB_redraw: |
; Start redraw. |
push edx |
lea eax,[ebp+12] |
lea ebx,[ebp+1] |
int 40h |
; Define and draw window. |
xor eax,eax |
mov ebx,edx ; x, w (ECX: y, h) |
mov edx,34C0C0C0h ; style and BG color |
int 40h |
; Define the OK button. |
push esi |
lea eax,[ebp+8] |
sub ebx,28+0Ah |
shr bx,1 |
shl ebx,16 ; x = (window w - button w) / 2 |
mov bx,18+0Ah ; w = 18 + 0Ah |
mov ecx,001C0012h ; y = 1Ch, h = 12h |
lea edx,[ebp+1] ; ID = close |
mov esi,0C0C0C0h ; color |
int 40h |
; Draw the OK label. |
lea eax,[ebp+4] |
add ebx,90000h ; x = button x + 9 |
mov bx,22h ; y = 22h |
xor ecx,ecx ; style, font and color |
mov edx,sOK ; string |
lea esi,[ebp+2] ; length |
int 40h |
pop esi |
; Draw text string. |
lea eax,[ebp+4] |
mov ebx,000A000Ah ; x = 0Ah, y = 0Ah |
xor ecx,ecx ; style, font and color |
mov edx,[esp+28] ; lpString |
int 40h |
; End redraw. |
lea eax,[ebp+12] |
lea ebx,[ebp+2] |
int 40h |
_MessageBoxCB_eventloop: |
mov edx,[esp+36] ; cbProc |
test edx,edx |
lea eax,[ebp+10] |
jz _MessageBoxCB_peekevent |
; Invoke the callback. |
call edx |
lea eax,[ebp+23] |
lea ebx,[ebp+10] ; wait for at most 0.1 sec |
_MessageBoxCB_peekevent: |
int 40h |
dec eax |
js _MessageBoxCB_eventloop |
pop edx |
jz _MessageBoxCB_redraw |
pop ebx |
pop edi |
pop esi |
pop ebp |
ret |
; Include the whole uFMOD sources here. (Right after |
; your main code to avoid naming conflicts, but still |
; inside your code section.) |
%include "nasm.asm" |
alignb 4 |
resb 1020 |
STACK_B resd 1 ; Stack bottom |
MEMORY_END: ; End of uninitialized (BSS) data |
/programs/develop/libraries/ufmod/Nasm |
---|
Property changes: |
Added: tsvn:logminsize |
+5 |
\ No newline at end of property |
/programs/develop/libraries/ufmod/core.asm |
---|
0,0 → 1,3374 |
; 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 |
/programs/develop/libraries/ufmod/eff.inc |
---|
0,0 → 1,60 |
; XM-file: full.xm |
; uFMOD optional features: |
INFO_API_ON equ 1 ; enable InfoAPI |
NOLOOP_ON equ 1 ; enable XM_NOLOOP |
PAUSE_RESUME_ON equ 1 ; enable pause/resume and XM_SUSPENDED |
VOL_CONTROL_ON equ 1 ; enable volume control |
JUMP_TO_PAT_ON equ 1 ; enable Jump2Pattern |
XM_FILE_ON equ 1 ; enable file loading |
; Special flags: |
INSTRUMENTVIBRATO_ON equ 1 |
VOLUMEENVELOPE_ON equ 1 |
PANENVELOPE_ON equ 1 |
VOLUMEBYTE_ON equ 1 |
ADPCM_ON equ 1 |
AMIGAPERIODS_ON equ 1 |
; XM effects: |
ARPEGGIO_ON equ 1 |
PORTAUP_ON equ 1 |
PORTADOWN_ON equ 1 |
PORTATO_ON equ 1 |
VIBRATO_ON equ 1 |
PORTATOVOLSLIDE_ON equ 1 |
VIBRATOVOLSLIDE_ON equ 1 |
TREMOLO_ON equ 1 |
SETPANPOSITION_ON equ 1 |
SETSAMPLEOFFSET_ON equ 1 |
VOLUMESLIDE_ON equ 1 |
PATTERNJUMP_ON equ 1 |
SETVOLUME_ON equ 1 |
PATTERNBREAK_ON equ 1 |
SETSPEED_ON equ 1 |
SETGLOBALVOLUME_ON equ 1 |
GLOBALVOLSLIDE_ON equ 1 |
KEYOFF_ON equ 1 |
SETENVELOPEPOS_ON equ 1 |
PANSLIDE_ON equ 1 |
MULTIRETRIG_ON equ 1 |
TREMOR_ON equ 1 |
EXTRAFINEPORTA_ON equ 1 |
FINEPORTAUP_ON equ 1 |
FINEPORTADOWN_ON equ 1 |
SETVIBRATOWAVE_ON equ 1 |
SETFINETUNE_ON equ 1 |
PATTERNLOOP_ON equ 1 |
SETTREMOLOWAVE_ON equ 1 |
SETPANPOSITION16_ON equ 1 |
RETRIG_ON equ 1 |
NOTECUT_ON equ 1 |
NOTEDELAY_ON equ 1 |
PATTERNDELAY_ON equ 1 |
PORTAUP_OR_DOWN_ON equ 1 |
VIBRATO_OR_VOLSLIDE equ 1 |
VIBRATO_OR_TREMOLO equ 1 |
PORTATO_OR_VOLSLIDE equ 1 |
VOLUME_OR_PANENVELOPE equ 1 |
ROWCOMMANDS_ON equ 1 |
FINEVOLUMESLIDE_ON equ 1 |
/programs/develop/libraries/ufmod/fasm.asm |
---|
0,0 → 1,342 |
; FASM.ASM |
; -------- |
; uFMOD public source code release. Provided as-is. |
; *** This stub allows compiling uFMOD sources using FASM. |
; *** CONSTANTS *** |
if UF_FREQ eq 44100 |
FSOUND_MixRate = 44100 |
FREQ_40HZ_p = 1DB8Bh |
FREQ_40HZ_f = 3B7160h |
PCM_format = 3 ; PCM_2_16_44 |
else |
if UF_FREQ eq 22050 |
FSOUND_MixRate = 22050 |
FREQ_40HZ_p = 3B716h |
FREQ_40HZ_f = 76E2C0h |
PCM_format = 9 ; PCM_2_16_22 |
else |
if UF_FREQ eq 48000 |
else |
display 'UF_FREQ not specified (defaulting to 48KHz)',13,10 |
end if |
FSOUND_MixRate = 48000 |
FREQ_40HZ_p = 1B4E8h |
FREQ_40HZ_f = 369D00h |
PCM_format = 1 ; PCM_2_16_48 |
end if |
end if |
if UF_RAMP eq NONE |
RAMP_NONE = 1 |
RAMP_WEAK = 0 |
RAMP_STRONG = 0 |
else |
if UF_RAMP eq WEAK |
RAMP_NONE = 0 |
RAMP_WEAK = 1 |
RAMP_STRONG = 0 |
else |
if UF_RAMP eq STRONG |
else |
display 'UF_RAMP not specified (defaulting to STRONG)',13,10 |
end if |
RAMP_NONE = 0 |
RAMP_WEAK = 0 |
RAMP_STRONG = 1 |
end if |
end if |
UCODE equ 0 |
if UF_MODE eq UNSAFE |
display 'WARNING! Unsafe mod is ON. Library may crash while loading damaged XM tracks!',13,10 |
CHK4VALIDITY = 0 |
AC97SND_ON = 0 |
else |
CHK4VALIDITY = 1 |
if UF_MODE eq AC97SND |
AC97SND_ON = 1 |
else |
AC97SND_ON = 0 |
end if |
end if |
if NOLINKER |
else |
format MS COFF |
section '.text' code readable executable |
end if |
; *** STRUCTS *** |
; Sample type - contains info on sample |
struc FSOUND_SAMPLE{ |
; Don't change order .:. |
._length dd ? ; sample length |
.loopstart dd ? ; loop start |
.looplen dd ? ; loop length |
.defvol db ? ; default volume |
.finetune db ? ; finetune value from -128 to 127 |
.bytes db ? ; type [b 0-1] : 0 - no loop |
; 1 - forward loop |
; 2 - bidirectional loop (aka ping-pong) |
; [b 4] : 0 - 8-bit sample data |
; 1 - 16-bit sample data |
.defpan db ? ; default pan value from 0 to 255 |
.relative db ? ; relative note (signed value) |
.Resved db ? ; reserved, known values: 00h - regular delta packed sample data |
; ADh - ModPlug 4-bit ADPCM packed sample data |
; .:. |
.loopmode db ? |
._align db ? |
.buff db ?,? ; sound data |
} |
virtual at 0 |
FSOUND_SAMPLE FSOUND_SAMPLE |
FSOUND_SAMPLE_size = $-FSOUND_SAMPLE |
end virtual |
; Channel type - contains information on a mixing channel |
struc FSOUND_CHANNEL{ |
.actualvolume dd ? ; driver level current volume |
.actualpan dd ? ; driver level panning value |
.fsampleoffset dd ? ; sample offset (sample starts playing from here) |
.leftvolume dd ? ; mixing information. adjusted volume for left channel (panning involved) |
.rightvolume dd ? ; mixing information. adjusted volume for right channel (panning involved) |
.mixpos dd ? ; mixing information. high part of 32:32 fractional position in sample |
.speedlo dd ? ; mixing information. playback rate - low part fractional |
.speedhi dd ? ; mixing information. playback rate - high part fractional |
.ramp_lefttarget dw ? |
.ramp_righttarget dw ? |
.ramp_leftspeed dd ? |
.ramp_rightspeed dd ? |
; Don't change order .:. |
.fsptr dd ? ; pointer to FSOUND_SAMPLE currently playing sample |
.mixposlo dd ? ; mixing information. low part of 32:32 fractional position in sample |
.ramp_leftvolume dd ? |
.ramp_rightvolume dd ? |
.ramp_count dw ? |
.speeddir db ?,? ; mixing information. playback direction - forwards or backwards |
; .:. |
} |
virtual at 0 |
FSOUND_CHANNEL FSOUND_CHANNEL |
FSOUND_CHANNEL_size = $-FSOUND_CHANNEL |
end virtual |
; Single note type - contains info on 1 note in a pattern |
struc FMUSIC_NOTE{ |
.unote db ? ; note to play at (0-97) 97=keyoff |
.number db ? ; sample being played (0-128) |
.uvolume db ? ; volume column value (0-64) 255=no volume |
.effect db ? ; effect number (0-1Ah) |
.eparam db ? ; effect parameter (0-255) |
} |
virtual at 0 |
FMUSIC_NOTE FMUSIC_NOTE |
FMUSIC_NOTE_size = $-FMUSIC_NOTE |
end virtual |
; Pattern data type |
struc FMUSIC_PATTERN{ |
.rows dw ? |
.patternsize dw ? |
.data dd ? ; pointer to FMUSIC_NOTE |
} |
virtual at 0 |
FMUSIC_PATTERN FMUSIC_PATTERN |
FMUSIC_PATTERN_size = $-FMUSIC_PATTERN |
end virtual |
; Multi sample extended instrument |
struc FMUSIC_INSTRUMENT{ |
.sample rd 16 ; 16 pointers to FSOUND_SAMPLE per instrument |
; Don't change order .:. |
.keymap rb 96 ; sample keymap assignments |
.VOLPoints rw 24 ; volume envelope points |
.PANPoints rw 24 ; panning envelope points |
.VOLnumpoints db ? ; number of volume envelope points |
.PANnumpoints db ? ; number of panning envelope points |
.VOLsustain db ? ; volume sustain point |
.VOLLoopStart db ? ; volume envelope loop start |
.VOLLoopEnd db ? ; volume envelope loop end |
.PANsustain db ? ; panning sustain point |
.PANLoopStart db ? ; panning envelope loop start |
.PANLoopEnd db ? ; panning envelope loop end |
.VOLtype db ? ; type of envelope,bit 0:On 1:Sustain 2:Loop |
.PANtype db ? ; type of envelope,bit 0:On 1:Sustain 2:Loop |
.VIBtype db ? ; instrument vibrato type |
.VIBsweep db ? ; time it takes for vibrato to fully kick in |
.iVIBdepth db ? ; depth of vibrato |
.VIBrate db ? ; rate of vibrato |
.VOLfade dw ? ; fade out value |
; .:. |
} |
virtual at 0 |
FMUSIC_INSTRUMENT FMUSIC_INSTRUMENT |
FMUSIC_INSTRUMENT_size = $-FMUSIC_INSTRUMENT |
end virtual |
; Channel type - contains information on a mod channel |
struc FMUSIC_CHANNEL{ |
.note db ? ; last note set in channel |
.samp db ? ; last sample set in channel |
.notectrl db ? ; flags for DoFlags proc |
.inst db ? ; last instrument set in channel |
.cptr dd ? ; pointer to FSOUND_CHANNEL system mixing channel |
.freq dd ? ; current mod frequency period for this channel |
.volume dd ? ; current mod volume for this channel |
.voldelta dd ? ; delta for volume commands... tremolo/tremor, etc |
.freqdelta dd ? ; delta for frequency commands... vibrato/arpeggio, etc |
.pan dd ? ; current mod pan for this channel |
; Don't change order .:. |
.envvoltick dd ? ; tick counter for envelope position |
.envvolpos dd ? ; envelope position |
.envvoldelta dd ? ; delta step between points |
.envpantick dd ? ; tick counter for envelope position |
.envpanpos dd ? ; envelope position |
.envpandelta dd ? ; delta step between points |
.ivibsweeppos dd ? ; instrument vibrato sweep position |
.ivibpos dd ? ; instrument vibrato position |
.keyoff db ?,? ; flag whether keyoff has been hit or not |
.envvolstopped db ? ; flag to say whether envelope has finished or not |
.envpanstopped db ? ; flag to say whether envelope has finished or not |
; .:. |
.envvolfrac dd ? ; fractional interpolated envelope volume |
.envvol dd ? ; final interpolated envelope volume |
.fadeoutvol dd ? ; volume fade out |
.envpanfrac dd ? ; fractional interpolated envelope pan |
.envpan dd ? ; final interpolated envelope pan |
.period dd ? ; last period set in channel |
.sampleoffset dd ? ; sample offset for this channel in SAMPLES |
.portatarget dd ? ; note to porta to |
.patloopno db ?,?,?,? ; pattern loop variables for effect E6x |
.patlooprow dd ? |
.realnote db ? ; last realnote set in channel |
.recenteffect db ? ; previous row's effect... used to correct tremolo volume |
.portaupdown db ? ; last porta up/down value |
db ? ; unused |
.xtraportadown db ? ; last porta down value |
.xtraportaup db ? ; last porta up value |
.volslide db ? ; last volume slide value |
.panslide db ? ; pan slide parameter |
.retrigx db ? ; last retrig volume slide used |
.retrigy db ? ; last retrig tick count used |
.portaspeed db ? ; porta speed |
.vibpos db ? ; vibrato position |
.vibspeed db ? ; vibrato speed |
.vibdepth db ? ; vibrato depth |
.tremolopos db ? ; tremolo position |
.tremolospeed db ? ; tremolo speed |
.tremolodepth db ? ; tremolo depth |
.tremorpos db ? ; tremor position |
.tremoron db ? ; remembered parameters for tremor |
.tremoroff db ? ; remembered parameters for tremor |
.wavecontrol db ? ; waveform type for vibrato and tremolo (4bits each) |
.finevslup db ? ; parameter for fine volume slide down |
.fineportaup db ? ; parameter for fine porta slide up |
.fineportadown db ? ; parameter for fine porta slide down |
} |
virtual at 0 |
FMUSIC_CHANNEL FMUSIC_CHANNEL |
FMUSIC_CHANNEL_size = $-FMUSIC_CHANNEL |
end virtual |
; Song type - contains info on song |
struc FMUSIC_MODULE{ |
; Don't change order .:. |
.pattern dd ? ; pointer to FMUSIC_PATTERN array for this song |
.instrument dd ? ; pointer to FMUSIC_INSTRUMENT array for this song |
.mixer_samplesleft dd ? |
.globalvolume dd ? ; global mod volume |
.tick dd ? ; current mod tick |
.speed dd ? ; speed of song in ticks per row |
.order dd ? ; current song order position |
.row dd ? ; current row in pattern |
.patterndelay dd ? ; pattern delay counter |
.nextorder dd ? ; current song order position |
.nextrow dd ? ; current row in pattern |
.unused1 dd ? |
.numchannels dd ? ; number of channels |
.Channels dd ? ; channel pool |
.uFMOD_Ch dd ? ; channel array for this song |
.mixer_samplespertick dd ? |
.numorders dw ? ; number of orders (song length) |
.restart dw ? ; restart position |
.numchannels_xm db ? |
.globalvsl db ? ; global mod volume |
.numpatternsmem dw ? ; number of allocated patterns |
.numinsts dw ? ; number of instruments |
.flags dw ? ; flags such as linear frequency, format specific quirks, etc |
.defaultspeed dw ? |
.defaultbpm dw ? |
.orderlist rb 256 ; pattern playing order list |
; .:. |
} |
virtual at 0 |
FMUSIC_MODULE FMUSIC_MODULE |
FMUSIC_MODULE_size = $-FMUSIC_MODULE |
end virtual |
OFFSET equ |
PTR equ |
endif equ end if |
include 'ufmod.asm' |
include 'core.asm' |
if NOLINKER |
uFMOD_IMG_END: ; End of uFMOD's code. BSS follows. |
align 16 |
else |
section '.bss' readable writeable align 16 |
end if |
; Don't change order! |
_mod rb FMUSIC_MODULE_size ; currently playing track |
mmt rd 3 |
ufmod_heap dd ? |
dd ? ; unused |
if AC97SND_ON |
extrn hSound |
dd ? |
else |
hSound dd ? |
endif |
hBuff dd ? |
SW_Exit dd ? |
; mix buffer memory block (align 16!) |
MixBuf rb FSOUND_BlockSize*8 |
ufmod_noloop db ? |
ufmod_pause_ db ? |
mix_endflag rb 2 |
mmf rd 4 |
ufmod_vol dd ? ; global volume scale |
; * LPCALLBACKS * |
uFMOD_fopen dd ? |
uFMOD_fread dd ? |
file_struct rd 7 |
cache_offset dd ? |
if INFO_API_ON |
time_ms dd ? |
L_vol dw ? ; L channel RMS volume |
R_vol dw ? ; R channel RMS volume |
s_row dw ? |
s_order dw ? |
szTtl rb 24 |
end if |
DummySamp rb FSOUND_SAMPLE_size |
/programs/develop/libraries/ufmod/makeobj.bat |
---|
0,0 → 1,68 |
@echo off |
rem Make the uFMOD libraries in COFF object format |
rem Target OS: KolibriOS |
rem *** CONFIG START |
rem *** Check the Readme docs for a complete reference |
rem *** on configuring the following options |
rem Pathes: |
SET UF_MASM=\masm32\bin |
SET UF_NASM=\nasm |
SET UF_FASM=\fasm |
rem Select compiler: MASM, NASM or FASM |
SET UF_ASM=FASM |
rem Select mixing rate: 22050, 44100 or 48000 (22.05 KHz, 44.1 KHz or 48 KHz) |
SET UF_FREQ=48000 |
rem Set volume ramping mode (interpolation): NONE, WEAK or STRONG |
SET UF_RAMP=STRONG |
rem Set build mode: NORMAL, UNSAFE or AC97SND |
SET UF_MODE=NORMAL |
rem *** CONFIG END |
if %UF_ASM%==MASM goto MASM |
if %UF_ASM%==NASM goto NASM |
if %UF_ASM%==FASM goto FASM |
echo %UF_ASM% not supported |
goto TheEnd |
:MASM |
if not exist "%UF_MASM%\ml.exe" goto Err1 |
"%UF_MASM%\ml" /c /coff /nologo /Df%UF_FREQ% /D%UF_RAMP% /D%UF_MODE% /Fo ufmod.obj src\masm.asm |
goto TheEnd |
:NASM |
if not exist "%UF_NASM%\nasmw.exe" goto Err2 |
"%UF_NASM%\nasmw" -O4 -t -fwin32 -dNODEBUG -df%UF_FREQ% -d%UF_RAMP% -d%UF_MODE% -isrc\ -oufmod.obj src\nasm.asm |
goto TheEnd |
:FASM |
if not exist "%UF_FASM%\fasm.exe" goto Err3 |
echo UF_FREQ equ %UF_FREQ% >tmp.asm |
echo UF_RAMP equ %UF_RAMP% >>tmp.asm |
echo UF_MODE equ %UF_MODE% >>tmp.asm |
echo DEBUG equ 0 >>tmp.asm |
echo NOLINKER equ 0 >>tmp.asm |
echo include 'src\eff.inc' >>tmp.asm |
echo include 'src\fasm.asm' >>tmp.asm |
"%UF_FASM%\fasm" tmp.asm ufmod.obj |
del tmp.asm |
goto TheEnd |
:Err1 |
echo Couldn't find ml.exe in %UF_MASM%\ |
goto TheEnd |
:Err2 |
echo Couldn't find nasmw.exe in %UF_NASM%\ |
goto TheEnd |
:Err3 |
echo Couldn't find fasm.exe in %UF_FASM%\ |
:TheEnd |
pause |
@echo on |
cls |
/programs/develop/libraries/ufmod/masm.asm |
---|
0,0 → 1,270 |
; MASM.ASM |
; -------- |
; uFMOD public source code release. Provided as-is. |
; *** This stub allows compiling uFMOD sources using MASM32. |
.386 |
.model flat |
ifdef f44100 |
FSOUND_MixRate = 44100 |
FREQ_40HZ_p = 1DB8Bh |
FREQ_40HZ_f = 3B7160h |
PCM_format = 3 |
else |
ifdef f22050 |
FSOUND_MixRate = 22050 |
FREQ_40HZ_p = 3B716h |
FREQ_40HZ_f = 76E2C0h |
PCM_format = 9 |
else |
ifndef f48000 |
echo UF_FREQ not specified (defaulting to 48KHz) |
endif |
FSOUND_MixRate = 48000 |
FREQ_40HZ_p = 1B4E8h |
FREQ_40HZ_f = 369D00h |
PCM_format = 1 |
endif |
endif |
RAMP_NONE = 0 |
RAMP_WEAK = 0 |
RAMP_STRONG = 0 |
ifdef NONE |
RAMP_NONE = 1 |
else |
ifdef WEAK |
RAMP_WEAK = 1 |
else |
ifndef STRONG |
echo UF_RAMP not specified (defaulting to STRONG) |
endif |
RAMP_STRONG = 1 |
endif |
endif |
UCODE = 0 |
DEBUG = 0 |
CHK4VALIDITY = 1 |
ifdef UNSAFE |
echo WARNING! Unsafe mod is ON. Library may crash while loading damaged XM tracks! |
CHK4VALIDITY = 0 |
endif |
AC97SND_ON = 0 |
ifdef AC97SND |
AC97SND_ON = 1 |
endif |
include eff.inc |
FSOUND_SAMPLE STRUC |
_length dd ? |
loopstart dd ? |
looplen dd ? |
defvol db ? |
finetune db ? |
bytes db ? |
defpan db ? |
relative db ? |
Resved db ? |
loopmode db ? |
_align db ? |
buff db ?,? |
FSOUND_SAMPLE ENDS |
FSOUND_CHANNEL STRUC |
actualvolume dd ? |
actualpan dd ? |
fsampleoffset dd ? |
leftvolume dd ? |
rightvolume dd ? |
mixpos dd ? |
speedlo dd ? |
speedhi dd ? |
ramp_lefttarget dw ? |
ramp_righttarget dw ? |
ramp_leftspeed dd ? |
ramp_rightspeed dd ? |
fsptr dd ? |
mixposlo dd ? |
ramp_leftvolume dd ? |
ramp_rightvolume dd ? |
ramp_count dw ? |
speeddir db ?,? |
FSOUND_CHANNEL ENDS |
FMUSIC_NOTE STRUC |
unote db ? |
number db ? |
uvolume db ? |
effect db ? |
eparam db ? |
FMUSIC_NOTE ENDS |
FMUSIC_PATTERN STRUC |
rows dw ? |
patternsize dw ? |
data dd ? |
FMUSIC_PATTERN ENDS |
FMUSIC_INSTRUMENT STRUC |
sample dd 16 dup (?) |
keymap db 96 dup (?) |
VOLPoints dw 24 dup (?) |
PANPoints dw 24 dup (?) |
VOLnumpoints db ? |
PANnumpoints db ? |
VOLsustain db ? |
VOLLoopStart db ? |
VOLLoopEnd db ? |
PANsustain db ? |
PANLoopStart db ? |
PANLoopEnd db ? |
VOLtype db ? |
PANtype db ? |
VIBtype db ? |
VIBsweep db ? |
iVIBdepth db ? |
VIBrate db ? |
VOLfade dw ? |
FMUSIC_INSTRUMENT ENDS |
FMUSIC_CHANNEL STRUC |
note db ? |
samp db ? |
notectrl db ? |
inst db ? |
cptr dd ? |
freq dd ? |
volume dd ? |
voldelta dd ? |
freqdelta dd ? |
pan dd ? |
envvoltick dd ? |
envvolpos dd ? |
envvoldelta dd ? |
envpantick dd ? |
envpanpos dd ? |
envpandelta dd ? |
ivibsweeppos dd ? |
ivibpos dd ? |
keyoff db ?,? |
envvolstopped db ? |
envpanstopped db ? |
envvolfrac dd ? |
envvol dd ? |
fadeoutvol dd ? |
envpanfrac dd ? |
envpan dd ? |
period dd ? |
sampleoffset dd ? |
portatarget dd ? |
patloopno db ?,?,?,? |
patlooprow dd ? |
realnote db ? |
recenteffect db ? |
portaupdown db ? |
db ? |
xtraportadown db ? |
xtraportaup db ? |
volslide db ? |
panslide db ? |
retrigx db ? |
retrigy db ? |
portaspeed db ? |
vibpos db ? |
vibspeed db ? |
vibdepth db ? |
tremolopos db ? |
tremolospeed db ? |
tremolodepth db ? |
tremorpos db ? |
tremoron db ? |
tremoroff db ? |
wavecontrol db ? |
finevslup db ? |
fineportaup db ? |
fineportadown db ? |
FMUSIC_CHANNEL ENDS |
FMUSIC_MODULE STRUC |
pattern dd ? |
instrument dd ? |
mixer_samplesleft dd ? |
globalvolume dd ? |
tick dd ? |
speed dd ? |
order dd ? |
row dd ? |
patterndelay dd ? |
nextorder dd ? |
nextrow dd ? |
unused1 dd ? |
numchannels dd ? |
Channels dd ? |
uFMOD_Ch dd ? |
mixer_samplespertick dd ? |
numorders dw ? |
restart dw ? |
numchannels_xm db ? |
globalvsl db ? |
numpatternsmem dw ? |
numinsts dw ? |
flags dw ? |
defaultspeed dw ? |
defaultbpm dw ? |
orderlist db 256 dup (?) |
FMUSIC_MODULE ENDS |
FMUSIC_MODULE_size = SIZE FMUSIC_MODULE |
FSOUND_CHANNEL_size = SIZE FSOUND_CHANNEL |
FMUSIC_CHANNEL_size = SIZE FMUSIC_CHANNEL |
FMUSIC_INSTRUMENT_size = SIZE FMUSIC_INSTRUMENT |
FMUSIC_PATTERN_size = SIZE FMUSIC_PATTERN |
FMUSIC_NOTE_size = SIZE FMUSIC_NOTE |
; FPU register stack |
st0 TEXTEQU <st(0)> |
st1 TEXTEQU <st(1)> |
.CODE |
include ufmod.asm |
include core.asm |
.DATA? |
_mod = $ |
FMUSIC_MODULE<> |
mmt dd ?,?,? |
ufmod_heap dd ?,? |
if AC97SND_ON |
EXTERN hSound:DWORD |
dd ? |
else |
hSound dd ? |
endif |
hBuff dd ? |
SW_Exit dd ? |
MixBuf db FSOUND_BlockSize*8 dup (?) |
ufmod_noloop db ? |
ufmod_pause_ db ? |
mix_endflag db ?,? |
mmf dd ?,?,?,? |
ufmod_vol dd ? |
uFMOD_fopen dd ? |
uFMOD_fread dd ? |
file_struct dd 7 dup (?) |
cache_offset dd ? |
if INFO_API_ON |
time_ms dd ? |
L_vol dw ? |
R_vol dw ? |
s_row dw ? |
s_order dw ? |
szTtl db 24 dup (?) |
endif |
DummySamp FSOUND_SAMPLE<> |
end |
/programs/develop/libraries/ufmod/media/BLITZXMK.XM |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/programs/develop/libraries/ufmod/media/blitz.eff.inc |
---|
0,0 → 1,60 |
; XM-file: BLITZXMK.XM |
; uFMOD optional features: |
INFO_API_ON equ 0 ; disable InfoAPI |
NOLOOP_ON equ 0 ; disable XM_NOLOOP |
PAUSE_RESUME_ON equ 1 ; enable pause/resume and XM_SUSPENDED |
VOL_CONTROL_ON equ 0 ; disable volume control |
JUMP_TO_PAT_ON equ 1 ; enable Jump2Pattern |
XM_FILE_ON equ 0 ; disable file loading |
; Special flags: |
INSTRUMENTVIBRATO_ON equ 1 |
VOLUMEENVELOPE_ON equ 1 |
PANENVELOPE_ON equ 0 |
VOLUMEBYTE_ON equ 1 |
ADPCM_ON equ 0 |
AMIGAPERIODS_ON equ 0 |
; XM effects: |
ARPEGGIO_ON equ 0 |
PORTAUP_ON equ 0 |
PORTADOWN_ON equ 0 |
PORTATO_ON equ 1 |
VIBRATO_ON equ 1 |
PORTATOVOLSLIDE_ON equ 0 |
VIBRATOVOLSLIDE_ON equ 0 |
TREMOLO_ON equ 0 |
SETPANPOSITION_ON equ 0 |
SETSAMPLEOFFSET_ON equ 0 |
VOLUMESLIDE_ON equ 0 |
PATTERNJUMP_ON equ 1 |
SETVOLUME_ON equ 0 |
PATTERNBREAK_ON equ 0 |
SETSPEED_ON equ 1 |
SETGLOBALVOLUME_ON equ 0 |
GLOBALVOLSLIDE_ON equ 0 |
KEYOFF_ON equ 0 |
SETENVELOPEPOS_ON equ 0 |
PANSLIDE_ON equ 0 |
MULTIRETRIG_ON equ 0 |
TREMOR_ON equ 0 |
EXTRAFINEPORTA_ON equ 0 |
FINEPORTAUP_ON equ 0 |
FINEPORTADOWN_ON equ 0 |
SETVIBRATOWAVE_ON equ 0 |
SETFINETUNE_ON equ 0 |
PATTERNLOOP_ON equ 0 |
SETTREMOLOWAVE_ON equ 0 |
SETPANPOSITION16_ON equ 0 |
RETRIG_ON equ 0 |
NOTECUT_ON equ 1 |
NOTEDELAY_ON equ 1 |
PATTERNDELAY_ON equ 0 |
PORTAUP_OR_DOWN_ON equ 0 |
VIBRATO_OR_VOLSLIDE equ 1 |
VIBRATO_OR_TREMOLO equ 1 |
PORTATO_OR_VOLSLIDE equ 1 |
VOLUME_OR_PANENVELOPE equ 1 |
ROWCOMMANDS_ON equ 1 |
FINEVOLUMESLIDE_ON equ 0 |
/programs/develop/libraries/ufmod/media/mini.eff.inc |
---|
0,0 → 1,60 |
; XM-file: mini.xm |
; uFMOD optional features: |
INFO_API_ON equ 0 ; disable InfoAPI |
NOLOOP_ON equ 0 ; disable XM_NOLOOP |
PAUSE_RESUME_ON equ 0 ; disable pause/resume and XM_SUSPENDED |
VOL_CONTROL_ON equ 0 ; disable volume control |
JUMP_TO_PAT_ON equ 0 ; disable Jump2Pattern |
XM_FILE_ON equ 0 ; disable file loading |
; Special flags: |
INSTRUMENTVIBRATO_ON equ 0 |
VOLUMEENVELOPE_ON equ 1 |
PANENVELOPE_ON equ 0 |
VOLUMEBYTE_ON equ 0 |
ADPCM_ON equ 0 |
AMIGAPERIODS_ON equ 0 |
; XM effects: |
ARPEGGIO_ON equ 0 |
PORTAUP_ON equ 0 |
PORTADOWN_ON equ 0 |
PORTATO_ON equ 0 |
VIBRATO_ON equ 0 |
PORTATOVOLSLIDE_ON equ 0 |
VIBRATOVOLSLIDE_ON equ 0 |
TREMOLO_ON equ 0 |
SETPANPOSITION_ON equ 0 |
SETSAMPLEOFFSET_ON equ 0 |
VOLUMESLIDE_ON equ 1 |
PATTERNJUMP_ON equ 0 |
SETVOLUME_ON equ 0 |
PATTERNBREAK_ON equ 0 |
SETSPEED_ON equ 0 |
SETGLOBALVOLUME_ON equ 0 |
GLOBALVOLSLIDE_ON equ 0 |
KEYOFF_ON equ 0 |
SETENVELOPEPOS_ON equ 0 |
PANSLIDE_ON equ 0 |
MULTIRETRIG_ON equ 0 |
TREMOR_ON equ 0 |
EXTRAFINEPORTA_ON equ 0 |
FINEPORTAUP_ON equ 0 |
FINEPORTADOWN_ON equ 0 |
SETVIBRATOWAVE_ON equ 0 |
SETFINETUNE_ON equ 0 |
PATTERNLOOP_ON equ 1 |
SETTREMOLOWAVE_ON equ 0 |
SETPANPOSITION16_ON equ 0 |
RETRIG_ON equ 0 |
NOTECUT_ON equ 0 |
NOTEDELAY_ON equ 0 |
PATTERNDELAY_ON equ 0 |
PORTAUP_OR_DOWN_ON equ 0 |
VIBRATO_OR_VOLSLIDE equ 0 |
VIBRATO_OR_TREMOLO equ 0 |
PORTATO_OR_VOLSLIDE equ 0 |
VOLUME_OR_PANENVELOPE equ 1 |
ROWCOMMANDS_ON equ 1 |
FINEVOLUMESLIDE_ON equ 0 |
/programs/develop/libraries/ufmod/media/mini.xm |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/programs/develop/libraries/ufmod/media |
---|
Property changes: |
Added: tsvn:logminsize |
+5 |
\ No newline at end of property |
/programs/develop/libraries/ufmod/nasm.asm |
---|
0,0 → 1,278 |
; NASM.ASM |
; -------- |
; uFMOD public source code release. Provided as-is. |
; *** This stub allows compiling uFMOD sources using NASM. |
; Everything documented in fasm stub! |
; %error directive in NASM causes multiple prompts to appear due to |
; multiple passes :( So, we'd better avoid using %error. |
ifdef f44100 |
FSOUND_MixRate equ 44100 |
FREQ_40HZ_p equ 1DB8Bh |
FREQ_40HZ_f equ 3B7160h |
PCM_format equ 3 |
else |
ifdef f22050 |
FSOUND_MixRate equ 22050 |
FREQ_40HZ_p equ 3B716h |
FREQ_40HZ_f equ 76E2C0h |
PCM_format equ 9 |
else |
FSOUND_MixRate equ 48000 |
FREQ_40HZ_p equ 1B4E8h |
FREQ_40HZ_f equ 369D00h |
PCM_format equ 1 |
endif |
endif |
ifdef NONE |
RAMP_NONE equ 1 |
RAMP_WEAK equ 0 |
RAMP_STRONG equ 0 |
else |
ifdef WEAK |
RAMP_NONE equ 0 |
RAMP_WEAK equ 1 |
RAMP_STRONG equ 0 |
else |
RAMP_NONE equ 0 |
RAMP_WEAK equ 0 |
RAMP_STRONG equ 1 |
endif |
endif |
UCODE equ 0 |
ifdef NODEBUG |
DEBUG equ 0 |
else |
DEBUG equ 1 |
endif |
ifdef UNSAFE |
CHK4VALIDITY equ 0 |
AC97SND_ON equ 0 |
else |
CHK4VALIDITY equ 1 |
ifdef AC97SND |
AC97SND_ON equ 1 |
else |
AC97SND_ON equ 0 |
endif |
endif |
ifndef NOLINKER |
%include "eff.inc" |
[segment .text align=4] |
endif |
STRUC FSOUND_SAMPLE |
FSOUND_SAMPLE._length resd 1 |
FSOUND_SAMPLE.loopstart resd 1 |
FSOUND_SAMPLE.looplen resd 1 |
FSOUND_SAMPLE.defvol resb 1 |
FSOUND_SAMPLE.finetune resb 1 |
FSOUND_SAMPLE.bytes resb 1 |
FSOUND_SAMPLE.defpan resb 1 |
FSOUND_SAMPLE.relative resb 1 |
FSOUND_SAMPLE.Resved resb 1 |
FSOUND_SAMPLE.loopmode resb 1 |
FSOUND_SAMPLE._align resb 1 |
FSOUND_SAMPLE.buff resb 2 |
ENDSTRUC |
STRUC FSOUND_CHANNEL |
FSOUND_CHANNEL.actualvolume resd 1 |
FSOUND_CHANNEL.actualpan resd 1 |
FSOUND_CHANNEL.fsampleoffset resd 1 |
FSOUND_CHANNEL.leftvolume resd 1 |
FSOUND_CHANNEL.rightvolume resd 1 |
FSOUND_CHANNEL.mixpos resd 1 |
FSOUND_CHANNEL.speedlo resd 1 |
FSOUND_CHANNEL.speedhi resd 1 |
FSOUND_CHANNEL.ramp_lefttarget resw 1 |
FSOUND_CHANNEL.ramp_righttarget resw 1 |
FSOUND_CHANNEL.ramp_leftspeed resd 1 |
FSOUND_CHANNEL.ramp_rightspeed resd 1 |
FSOUND_CHANNEL.fsptr resd 1 |
FSOUND_CHANNEL.mixposlo resd 1 |
FSOUND_CHANNEL.ramp_leftvolume resd 1 |
FSOUND_CHANNEL.ramp_rightvolume resd 1 |
FSOUND_CHANNEL.ramp_count resw 1 |
FSOUND_CHANNEL.speeddir resb 2 |
ENDSTRUC |
STRUC FMUSIC_NOTE |
FMUSIC_NOTE.unote resb 1 |
FMUSIC_NOTE.number resb 1 |
FMUSIC_NOTE.uvolume resb 1 |
FMUSIC_NOTE.effect resb 1 |
FMUSIC_NOTE.eparam resb 1 |
ENDSTRUC |
STRUC FMUSIC_PATTERN |
FMUSIC_PATTERN.rows resw 1 |
FMUSIC_PATTERN.patternsize resw 1 |
FMUSIC_PATTERN.data resd 1 |
ENDSTRUC |
STRUC FMUSIC_INSTRUMENT |
FMUSIC_INSTRUMENT.sample resd 16 |
FMUSIC_INSTRUMENT.keymap resb 96 |
FMUSIC_INSTRUMENT.VOLPoints resw 24 |
FMUSIC_INSTRUMENT.PANPoints resw 24 |
FMUSIC_INSTRUMENT.VOLnumpoints resb 1 |
FMUSIC_INSTRUMENT.PANnumpoints resb 1 |
FMUSIC_INSTRUMENT.VOLsustain resb 1 |
FMUSIC_INSTRUMENT.VOLLoopStart resb 1 |
FMUSIC_INSTRUMENT.VOLLoopEnd resb 1 |
FMUSIC_INSTRUMENT.PANsustain resb 1 |
FMUSIC_INSTRUMENT.PANLoopStart resb 1 |
FMUSIC_INSTRUMENT.PANLoopEnd resb 1 |
FMUSIC_INSTRUMENT.VOLtype resb 1 |
FMUSIC_INSTRUMENT.PANtype resb 1 |
FMUSIC_INSTRUMENT.VIBtype resb 1 |
FMUSIC_INSTRUMENT.VIBsweep resb 1 |
FMUSIC_INSTRUMENT.iVIBdepth resb 1 |
FMUSIC_INSTRUMENT.VIBrate resb 1 |
FMUSIC_INSTRUMENT.VOLfade resw 1 |
ENDSTRUC |
STRUC FMUSIC_CHANNEL |
FMUSIC_CHANNEL.note resb 1 |
FMUSIC_CHANNEL.samp resb 1 |
FMUSIC_CHANNEL.notectrl resb 1 |
FMUSIC_CHANNEL.inst resb 1 |
FMUSIC_CHANNEL.cptr resd 1 |
FMUSIC_CHANNEL.freq resd 1 |
FMUSIC_CHANNEL.volume resd 1 |
FMUSIC_CHANNEL.voldelta resd 1 |
FMUSIC_CHANNEL.freqdelta resd 1 |
FMUSIC_CHANNEL.pan resd 1 |
FMUSIC_CHANNEL.envvoltick resd 1 |
FMUSIC_CHANNEL.envvolpos resd 1 |
FMUSIC_CHANNEL.envvoldelta resd 1 |
FMUSIC_CHANNEL.envpantick resd 1 |
FMUSIC_CHANNEL.envpanpos resd 1 |
FMUSIC_CHANNEL.envpandelta resd 1 |
FMUSIC_CHANNEL.ivibsweeppos resd 1 |
FMUSIC_CHANNEL.ivibpos resd 1 |
FMUSIC_CHANNEL.keyoff resb 2 |
FMUSIC_CHANNEL.envvolstopped resb 1 |
FMUSIC_CHANNEL.envpanstopped resb 1 |
FMUSIC_CHANNEL.envvolfrac resd 1 |
FMUSIC_CHANNEL.envvol resd 1 |
FMUSIC_CHANNEL.fadeoutvol resd 1 |
FMUSIC_CHANNEL.envpanfrac resd 1 |
FMUSIC_CHANNEL.envpan resd 1 |
FMUSIC_CHANNEL.period resd 1 |
FMUSIC_CHANNEL.sampleoffset resd 1 |
FMUSIC_CHANNEL.portatarget resd 1 |
FMUSIC_CHANNEL.patloopno resb 4 |
FMUSIC_CHANNEL.patlooprow resd 1 |
FMUSIC_CHANNEL.realnote resb 1 |
FMUSIC_CHANNEL.recenteffect resb 1 |
FMUSIC_CHANNEL.portaupdown resb 2 |
FMUSIC_CHANNEL.xtraportadown resb 1 |
FMUSIC_CHANNEL.xtraportaup resb 1 |
FMUSIC_CHANNEL.volslide resb 1 |
FMUSIC_CHANNEL.panslide resb 1 |
FMUSIC_CHANNEL.retrigx resb 1 |
FMUSIC_CHANNEL.retrigy resb 1 |
FMUSIC_CHANNEL.portaspeed resb 1 |
FMUSIC_CHANNEL.vibpos resb 1 |
FMUSIC_CHANNEL.vibspeed resb 1 |
FMUSIC_CHANNEL.vibdepth resb 1 |
FMUSIC_CHANNEL.tremolopos resb 1 |
FMUSIC_CHANNEL.tremolospeed resb 1 |
FMUSIC_CHANNEL.tremolodepth resb 1 |
FMUSIC_CHANNEL.tremorpos resb 1 |
FMUSIC_CHANNEL.tremoron resb 1 |
FMUSIC_CHANNEL.tremoroff resb 1 |
FMUSIC_CHANNEL.wavecontrol resb 1 |
FMUSIC_CHANNEL.finevslup resb 1 |
FMUSIC_CHANNEL.fineportaup resb 1 |
FMUSIC_CHANNEL.fineportadown resb 1 |
ENDSTRUC |
STRUC FMUSIC_MODULE |
FMUSIC_MODULE.pattern resd 1 |
FMUSIC_MODULE.instrument resd 1 |
FMUSIC_MODULE.mixer_samplesleft resd 1 |
FMUSIC_MODULE.globalvolume resd 1 |
FMUSIC_MODULE.tick resd 1 |
FMUSIC_MODULE.speed resd 1 |
FMUSIC_MODULE.order resd 1 |
FMUSIC_MODULE.row resd 1 |
FMUSIC_MODULE.patterndelay resd 1 |
FMUSIC_MODULE.nextorder resd 1 |
FMUSIC_MODULE.nextrow resd 1 |
FMUSIC_MODULE.unused1 resd 1 |
FMUSIC_MODULE.numchannels resd 1 |
FMUSIC_MODULE.Channels resd 1 |
FMUSIC_MODULE.uFMOD_Ch resd 1 |
FMUSIC_MODULE.mixer_samplespertick resd 1 |
FMUSIC_MODULE.numorders resw 1 |
FMUSIC_MODULE.restart resw 1 |
FMUSIC_MODULE.numchannels_xm resb 1 |
FMUSIC_MODULE.globalvsl resb 1 |
FMUSIC_MODULE.numpatternsmem resw 1 |
FMUSIC_MODULE.numinsts resw 1 |
FMUSIC_MODULE.flags resw 1 |
FMUSIC_MODULE.defaultspeed resw 1 |
FMUSIC_MODULE.defaultbpm resw 1 |
FMUSIC_MODULE.orderlist resb 256 |
ENDSTRUC |
%macro PUBLIC 1 |
ifndef NOLINKER |
GLOBAL %1 |
endif |
%endmacro |
%define OFFSET |
%define PTR |
include "ufmod.asm" |
include "core.asm" |
ifdef NOLINKER |
uFMOD_IMG_END: ; End of uFMOD's code. BSS follows. |
align 16 |
[segment .bss] |
else |
[segment .bss align=16] |
endif |
_mod resb FMUSIC_MODULE_size |
mmt resd 3 |
ufmod_heap resd 2 |
if AC97SND_ON |
extern hSound |
resd 1 |
else |
hSound resd 1 |
endif |
hBuff resd 1 |
SW_Exit resd 1 |
MixBuf resb FSOUND_BlockSize*8 |
ufmod_noloop resb 1 |
ufmod_pause_ resb 1 |
mix_endflag resb 2 |
mmf resd 4 |
ufmod_vol resd 1 |
uFMOD_fopen resd 1 |
uFMOD_fread resd 1 |
file_struct resd 7 |
cache_offset resd 1 |
if INFO_API_ON |
time_ms resd 1 |
L_vol resw 1 |
R_vol resw 1 |
s_row resw 1 |
s_order resw 1 |
szTtl resb 24 |
endif |
DummySamp resb FSOUND_SAMPLE_size |
/programs/develop/libraries/ufmod/readme_en.htm |
---|
0,0 → 1,34 |
<html><head><meta http-equiv=Content-Type content="text/html; charset=windows-1251"><title>uFMOD</title></head><body style='margin:0'><table border=0 cellpadding=0 cellspacing=0 width=100%><tr bgcolor=#E7E7E7 align=center><td height=20 style='color:#708090;font-size:9pt;font-family:Arial,Aerial'>[ English | <a href='es.htm'>Español</a> | <a href='ru.htm'>Pyccκuú</a> ]<tr bgcolor=#708090><td height=1></table><center><h2 style='font-size:14pt;font-family:Arial,Aerial'>μFMOD v1.25 for KolibriOS</h2></center><div style='font-size:10pt;font-family:Arial,Aerial;text-align:justify;margin:8'><p>uFMOD is an XM player library written in assembly language. It's perfect for size- and speed-critical applications, click free, highly reliable, easy to use, open source, multiplatform. File and direct memory playback supported. It is able to play even damaged and non-standard XM tracks. Usage examples available for the following compilers: FASM, MASM32 and NASM.<p>KolibriOS port should run correctly on any PC meeting the following requirements:<ol><li>KolibriOS SVN revision 574 or later. You can download the latest official distro and the SVN binaries from <a href='http://www.kolibrios.org/?&lang=en'>www.kolibrios.org</a>.<li>A sound card supported by the <a href='http://infinity-sound.narod.ru/'>Infinity Sound audio library</a>. It is the default KolibriOS sound driver. Currently it supports many AC'97 compatible sound cards.</ol>If your machine meets the above requirements but uFMOD doesn't run properly, let us know (check the <a href='#ci'>contact information</a> near the bottom of this page).<ul><li><a href='#1'>Getting started</a><li><a href='#2'>Tools</a><ul><li><a href='#21'>XMStrip</a><li><a href='#22'>Eff</a></ul><li><a href='#3'>Compiling the library</a><li><a href='#4'>Examples</a><li><a href='#5'>Reducing the executable file size</a><li><a href='#6'>FAQ</a><li><a href='#7'>Thanks</a></ul><p> <br><a name='1'><b>Getting started</b></a><p>KolibriOS is an operating system written is assembly language. That's why it is so small and extremely fast. It is very powerful as well, as you've probably found out already. That's also uFMOD's spirit ;)<p>Most of the tasks described below can be accomplished directly in Kolibri. However, since many novice Kolibri coders prefer compiling their programs in Windows and then moving them to Kolibri for testing, we'll use crosscompilation here for the sake of universality.<p> <br><a name='2'><b>Tools</b></a><p>There are 2 freeware tools currently available to use along with uFMOD: XMStrip and Eff. None of them has been ported to KolibriOS yet. So, you should pick one of the other platform-specific distros (Win32, Linux or Unix/BSD) and use XMStrip and Eff crossplatformly. No matter which platform-specific version you choose, both utilities have dual interface: terminal and GUI. GUI is rather self-explanatory. Next, we'll explain the terminal interface.<p><table border=0 cellpadding=0 cellspacing=0 bgcolor=#708090 style='font-size:9pt;font-family:Arial,Aerial'><tr><td colspan=3 height=1><tr height=18><td style='color:#E7E7E7'><b> SVN </b><td bgcolor=#E7E7E7> <a href='http://ufmod.svn.sourceforge.net/viewvc/ufmod'>Complete source code available</a> <td width=1><tr><td colspan=3 height=1></table><p><a name='21'><b><i>XMStrip</i></b></a> expects an XM filename on input, repacks the file contents to make it smaller, without losing sound quality. What it does exactly is removing overhead data (dummy instruments, patterns and junk metadata), stripping reserved and currently unused bytes, repacking pattern data. Running <code>xmstrip /h</code> produces the following output:<p><center><table border=0 cellpadding=8><tr bgcolor=#000000><td><pre><font color=#FFFFFF> USAGE: xmstrip [options] file [output] |
file - input file name. |
output - optional output file name. |
options: |
/c - clean only (don't strip) |
When [output] is not specified, XMSTRIP |
attempts to overwrite the input. If file |
name contains spaces, enclose it in "".</font></table></center><p>Keep in mind, that other XM players whould probably reject a 'stripped' XM file. The <b>/c</b> option is useful for 'recovering' such a stripped file or just cleaning a regular file intended to be played with any other XM player.<p><a name='22'><b><i>Eff</i></b></a> is useful for advanced users, willing to squeeze every single byte out of their applications. The general idea is to extract only those features you do mean to use in your application, recompile the uFMOD library from source and obtain the smallest possible footprint. Running <code>eff /h</code> requests the following prompt:<p><center><table border=0 cellpadding=8><tr bgcolor=#000000><td><pre><font color=#FFFFFF> USAGE: eff [options] file |
file - input file name |
options: |
/Dm - generate a masm32/tasm dump |
/Dd - generate a Pascal (Delphi) dump |
/Dc - generate a C/C++ dump |
/Ds - generate an RCDATA resource dump |
/Di - disable infoAPI: |
uFMOD_GetStats, uFMOD_GetRowOrder, |
uFMOD_GetTitle and uFMOD_GetTime |
/Dp - disable uFMOD_Pause, uFMOD_Resume |
and XM_SUSPENDED |
/Dv - disable volume control |
/Dj - disable Jump2Pattern |
/Df - disable loading XM from file |
/Dl - disable XM_NOLOOP |
/M - mark & clear unused chunks of |
+<p>There are currently 2 examples available: mini and jmp2pat. Precompiled executables are located in bin/. None of the executables are packed/compressed.<ul><li><b>mini</b> is the simplest example showing how to play an XM track from memory with proper error handling.<li><b>jmp2pat</b> is a bit more complex example showing how to use the Jump2Pattern feature and pause/resume. It uses a composite XM tracked by Kim (aka norki). For more information on composite XM files and the Jump2Pattern feature, refer to the following section.</ul><p> <br><a name='5'><b>Reducing the executable file size</b></a><p>Use <a href='#22'>Eff</a> to optimize the library and make it smaller.<p>When embedding the XM track directly into the executable or attaching it as a raw binary resource, it's sometimes worth it trying to optimize the XM itself. Modplug Player features ADPCM compression, which makes the XM somewhat smaller, but it's a lossy compression! Use <a href='#22'>XMStrip</a> for lossless (in terms of sound quality) size optimization.<p>If you're sure all XM tracks your application is going to use are valid (not damaged or otherwise modified), rebuild the library in UNSAFE mode.<p>Packers, such as mtappack by diamond, make executables smaller. Anyway, to make things fair, the sample executables are not compressed at all!<p>Let's talk some more about optimizing the XM file size:<p>An advanced XM file size optimization method involves merging various XM tracks in a single composite file. Since you can share the instruments in a composite file, the resulting file size could be a lot smaller than the sum of the separate file sizes before merging. Even without sharing the instruments it will be smaller because of the XM file header being declared only once. Let's see an example with 3 XM files:<pre> |
+<b>File 1 :</b> XM1_HEADER P11 P12 P13 I11 I12 |
+<b>File 2 :</b> XM2_HEADER P21 P22 P23 P24 I21 I22 I23 I24 |
+<b>File 3 :</b> XM3_HEADER P31 I31 |
+</pre><i><b>Legend:</b> XMn_HEADER is the header of the n-th XM file. Pni is the i-th pattern of the n-th XM file. Ini is the i-th instrument of the n-th XM file.</i><p>First, let's merge them in a single file without sharing the instruments:<pre> |
+<b>File 4 :</b> XM4_HEADER P11 P12 P13 P21 P22 P23 P24 P31 I11 I12 I21 I22 I23 I24 I31 |
+</pre>Now, let's say I12 is very similar or even equal to I23 and I24 is the same as I31. So, we can modify P2n to make them use I12 instead of I23 and P31 to use I24, so that we can remove I23 and I31:<pre> |
+<b>File 4 :</b> XM4_HEADER P11 P12 P13 P21 P22 P23 P24 P31 I11 I12 I21 I22 I24 |
+</pre>You'll have to modify the looping and pattern jumping commands and the references to instruments in "files" 2 and 3. Obviously, you can merge just 2 files or more than 3. XM file format limits the amount of patterns and instruments in a single file. That's the general idea. You'd have to learn how to use a tracker in order to perform this kind of optimization. Once you've got all your files merged, you can issue a single uFMOD_PlaySong function call and trigger all the "files" with uFMOD_Jump2Pattern. For example, uFMOD_Jump2Pattern(3) will start playing the 2nd "file", uFMOD_Jump2Pattern(7) will launch the 3rd and uFMOD_Jump2Pattern(0) will reset to the first "file". The exact indexes depend on your pattern layout. The <b>jmp2pat</b> example uses this feature.<p>Using Jump2Pattern has another advantage: switching is done much faster (practically in no time), as opposed to stopping and reloading a track. So, you can use this feature when quickly switching the background music is required.<p> <br><a name='6'><b>FAQ</b></a><p><span style='color:#008080'><b>Q:</b> Is uFMOD free for any type of use? Even commercial?</span><br><b>A:</b> Yes, currently it is.<p><span style='color:#008080'><b>Q:</b> Where can I get XM files from?</span><br><b>A:</b> Try visiting <a href='http://modarchive.org/'>The Mod Archive</a>. They have a huge archive of free tracker music in XM, IT, S3M and MOD format. You can use <a href='http://www.modplug.com/'>Open Modplug Tracker</a> to convert IT, S3M and MOD tracks to XM format without apparent degradation. There are many talented composers out there in the web sharing their music at no cost. Just don't forget the copyright!<p><span style='color:#008080'><b>Q:</b> Is uFMOD related in some way to Firelight Technologies® FMOD and miniFMOD sound libraries?</span><br><b>A:</b> Not any more. Up until 2004 uFMOD was based on the latest miniFMOD public source code release. Since then, library sources had been completely rewritten, introducing many new features. So, uFMOD is in no way representative of FMOD and miniFMOD sources.<p><span style='color:#008080'><b>Q:</b> Some XM player libraries claim to add only N kilobytes to the executable file. How many Kb does uFMOD add exactly to the executable's size?</span><br><b>A:</b> It is impossible to tell an exact value, because it depends on library features used (especially, when using the Eff utility), test program code layout, XM file size (when embedding the XM into the executable file). It also depends on the linker options. For example, bin/mini is 4.768 bytes without compression.<p><span style='color:#008080'><b>Q:</b> Where can I get the official XM file format specification from?</span><br><b>A:</b> No official and up to date specification exists. However, you can take a look at <a href='http://sourceforge.net/project/showfiles.php?group_id=158498&package_id=234625'>"The Unofficial XM File Format Specification: FastTracker II, ADPCM and Stripped Module Subformats"</a>. This document covers most aspects of the original XM file format and all the non-standard extensions currently supported by uFMOD. ModePlug's public source code (it's C++) also serves as reference material on module file formats.<p> <br><a name='7'><b>Thanks go out to</b></a><p>antarman, Barracuda, bogrus, chris_b, cresta, dododo, flaith, Four-F, GL#0M, norki, q_q, SofT MANiAC, S_T_A_S_, voodooattack and yoxola for reporting bugs, requesting interesting features, submitting usage examples and otherwise helping us improve uFMOD.<p><a href='http://wasm.ru'>[WASM.RU]</a> and <a href='http://sf.net'>SourceForge.net</a> for support and hosting.<p> <br><b>Copyright</b><p>uFMOD sources, binaries and utility programs © 2005 - 2007 Asterix and Quantum.<br>All rights reserved.<p>Sample tunes:<ul><li>Minimal III © 2006 - 2007 SofT MANiAC (CoolPHat).<li>BlitzXMK.XM from Jump2Pat example © 2007 Kim (aka norki).</ul></div><table border=0 cellpadding=0 cellspacing=0 width=100%><tr bgcolor=#708090><td height=1><tr bgcolor=#E7E7E7><td height=52 style='color:#708090;font-size:10pt;font-family:Arial,Aerial' align=center>Found a bug? Got a question or a suggestion?<br>Starting to develop a cool application using uFMOD? Please, let us know: <a href='mailto:ufmod@users.sf.net' name='ci'>ufmod@users.sf.net</a></table></body></html> |
\ No newline at end of file |
/programs/develop/libraries/ufmod/readme_es.htm |
---|
0,0 → 1,36 |
<html lang=es><head><meta http-equiv=Content-Type content="text/html; charset=windows-1251"><title>uFMOD</title></head><body style='margin:0'><table border=0 cellpadding=0 cellspacing=0 width=100%><tr bgcolor=#E7E7E7 align=center><td height=20 style='color:#708090;font-size:9pt;font-family:Arial,Aerial'>[ <a href='en.htm'>English</a> | Español | <a href='ru.htm'>Pyccκuú</a> ]<tr bgcolor=#708090><td height=1></table><center><h2 style='font-size:14pt;font-family:Arial,Aerial'>μFMOD v1.25 para KolibriOS</h2></center><div style='font-size:10pt;font-family:Arial,Aerial;text-align:justify;margin:8'><p>uFMOD es una librería para reproducir música en formato XM, desarrollada completamente en lenguaje ensamblador. Es perfecta para aplicaciones de tamaño y tiempo crítico, libre de defectos audibles, altamente confiable, fácil de usar, de código fuente abierto y multiplataforma. Permite reproducir ficheros y arreglos estáticos en memoria. Es capaz de reproducir inclusive ficheros corruptos y/o modificados. Ejemplos de uso disponibles para los siguientes compiladores: FASM, MASM32 y NASM.<p>La versión para KolibriOS debe funcionar en cualquier PC, siempre y cuando se cumplan los siguientes requisitos:<ol><li>KolibriOS revisión SVN 574 ó posterior. Puede descargar el último distributivo oficial y las actualizaciones SVN de <a href='http://www.kolibrios.org/?&lang=en'>www.kolibrios.org</a>.<li>Una tarjeta de sonido soportada por la librería <a href='http://infinity-sound.narod.ru/'>Infinity Sound</a>. Este controlador de audio viene preinstalado en KolibriOS. Actualmente soporta muchas tarjetas de sonido compatibles con AC'97.</ol>Si su máquina cumple con dichos requisitos pero uFMOD no funciona correctamente, por favor, repórtenos este hecho. (Ver <a href='#ci'>información de contacto</a> en la parte inferior de esta página.)<p><ul><li><a href='#1'>Antes de comenzar</a><li><a href='#2'>Herramientas</a><ul><li><a href='#21'>XMStrip</a><li><a href='#22'>Eff</a></ul><li><a href='#3'>Compilando la librería</a><li><a href='#4'>Ejemplos</a><li><a href='#5'>Cómo lograr un ejecutable más compacto</a><li><a href='#6'>Preguntas frecuentes</a><li><a href='#7'>Agradecimientos</a></ul><p> <br><a name='1'><b>Antes de comenzar</b></a><p>KolibriOS es un sistema operativo desarrollado en lenguaje ensamblador. Por eso es tan compacto y rápido. Además, es bastante versátil, como probablemente ya se habrá podido dar cuenta. Ese también es el espíritu de uFMOD ;)<p>La mayor parte de los pasos descritos a continuación se puede llevar a cabo diréctamente en Kolibri. Sin embargo, como muchos programadores principiantes en Kolibri prefieren compilar sus programas en Windows y luego transferirlos a Kolibri para hacer pruebas, vamos a usar compilación cruzada en esta guía en aras de generalizar la metodología.<p> <br><a name='2'><b>Herramientas</b></a><p>Hay 2 herramientas gratuitas para usar con uFMOD: XMStrip y Eff. Ninguna de las dos ha sido portada a KolibriOS aún. Por lo tanto, se recomienda descargar alguno de los otros distributivos uFMOD (Win32, Linux o Unix/BSD) y usar Eff y XMStrip desde otra plataforma. Sin importar la plataforma elegida, ambas herramientas poseen interfaz de usuario dual: consola y gráfica (GUI). El modo GUI es bastante intuitivo. Vamos a exponer el modo de consola.<p><table border=0 cellpadding=0 cellspacing=0 bgcolor=#708090 style='font-size:9pt;font-family:Arial,Aerial'><tr><td colspan=3 height=1><tr height=18><td style='color:#E7E7E7'><b> SVN </b><td bgcolor=#E7E7E7> <a href='http://ufmod.svn.sourceforge.net/viewvc/ufmod'>Código fuente completo disponible</a> <td width=1><tr><td colspan=3 height=1></table><p><a name='21'><b><i>XMStrip</i></b></a> recibe un fichero XM como entrada, modifica su contenido para minimizar el tamaño, sin que esto afecte la calidad del sonido. Concretamente, XMStrip elimina los datos no utilizados (instrumentos y patrones redundantes, comentarios, etc.) y agrupa los patrones de notas para optimizar el tiempo de lectura y procesamiento del XM. Al ingresar <code>xmstrip /h</code> obtenemos la siguiente respuesta:<p><center><table border=0 cellpadding=8><tr bgcolor=#000000><td><pre><font color=#FFFFFF> USAGE: xmstrip [options] file [output] |
file - input file name. |
output - optional output file name. |
options: |
/c - clean only (don't strip) |
When [output] is not specified, XMSTRIP |
attempts to overwrite the input. If file |
name contains spaces, enclose it in "".</font></table></center><p>Si no especifica el nombre del fichero de salida, XMStrip intentará sobreescribir el fichero de entrada. Si el nombre del fichero contiene espacios, enciérrelo entre comillas dobles ("").<p>Tenga presente, que otros reproductores de XM, probablemente, rechacen los ficheros producidos por XMStrip. Especifique <b>/c</b> para 'recuperar' un fichero así o símplemente para procesar un fichero normal que desea poder usar en otros reproductores de XM.<p><a name='22'><b><i>Eff</i></b></a> es útil para los usuarios avanzados, que desean ahorrar hasta el último byte en sus aplicaciones. La idea es extraer sólo aquellas opciones que realmente se van a usar en la aplicación, recompilar la librería uFMOD y obtener el menor tamaño posible. Comencemos abriendo una sesión de terminal y escribiendo <code>eff /h</code> para obtener el siguiente resúmen:<p><center><table border=0 cellpadding=8><tr bgcolor=#000000><td><pre><font color=#FFFFFF> USAGE: eff [options] file |
file - input file name |
options: |
/Dm - generate a masm32/tasm dump |
/Dd - generate a Pascal (Delphi) dump |
/Dc - generate a C/C++ dump |
/Ds - generate an RCDATA resource dump |
/Di - disable infoAPI: |
uFMOD_GetStats, uFMOD_GetRowOrder, |
uFMOD_GetTitle and uFMOD_GetTime |
/Dp - disable uFMOD_Pause, uFMOD_Resume |
and XM_SUSPENDED |
/Dv - disable volume control |
/Dj - disable Jump2Pattern |
/Df - disable loading XM from file |
/Dl - disable XM_NOLOOP |
/M - mark & clear unused chunks of |
+ Opciones adicionales:<ul><li><b>/Dm</b> genera un volcado hexadecimal a partir del fichero XM dado, para ser usado en MASM32 o TASM. La sintaxis es compatible con FASM y NASM. Sin embargo, tanto FASM como NASM permiten incluir el contenido de un fichero binario directamente. Es necesario especificar esta opción para poder usar <b>/M</b> (ver mas adelante).<li><b>/Dd</b> y <b>/Dc</b> generan volcados para Pascal (Delphi, Kylix, FreePascal) y C/C++ respectivamente.<li><b>/Ds</b> produce un volcado en formato RCDATA, usado en scripts de recursos. No tiene utilidad en KolibriOS.<li>Especifique <b>/Di</b> para deshabilitar todas las funciones informativas: uFMOD_GetStats, uFMOD_GetRowOrder, uFMOD_GetTitle y uFMOD_GetTime. Eliminarlas reduce el tamaño de la librería y mejora un poco el rendimiento.<li><b>/Dp</b> elimina las funciones uFMOD_Pause y uFMOD_Resume y hace que uFMOD ignore la bandera XM_SUSPENDED. Si no necesita pausar/reanudar, agregue esta opción a la linea de comandos para ahorrar otros tantos bytes.<li>uFMOD_SetVolume no sólo hace la librería más grande, sino que también consume tiempo adicional de CPU. Utilice <b>/Dv</b> para deshabilitar esta función y recuperar algunos bytes y ciclos de reloj ;)<li><b>/Dj</b> deshabilita la función Jump2Pattern. Esta es una función avanzada, no usada en la mayoria de las aplicaciones. Consulte la sección <a href='#5'>"Cómo lograr un ejecutable más compacto"</a> para mayor información sobre el uso de Jump2Pattern.<li>¿No va a reproducir ficheros - sólo arreglos estáticos? Entonces, querrá aprovechar la opción <b>/Df</b> para minimizar el tamaño de la librería.<li><b>/Dl</b> (L minúscula) hace que la librería ignore la bandera XM_NOLOOP (esto también reduce el tamaño y mejora la eficiencia).<li>Por último, hay una opción de optimización realmente extrema, disponible sólo para los programadores en lenguaje ensamblador. En cada fichero XM hay secuencias de bytes que se encuentran reservadas para versiones futuras del formato XM o contienen metadatos (comentarios, publicidad, etc.) <b>/M</b> delimita y resalta estos 'huecos' en el volcado y los habilita para ser usados con mayor utilidad. Por ejemplo, puede almacenar datos y hasta código ejecutable en dichos 'huecos'. El ejemplo src/Masm32/ utiliza esta opción.</ul>Si no se presenta error alguno, Eff debe generar un fichero EFF.INC y un volcado hexadecimal, si éste fue solicitado. Algunos ejemplos (todos son correctos):<p><b>eff /Dmpvjfl /M ejemplo.xm<br>eff /M /Dm /Dp /Dv /Dj /Df /Dl ejemplo.xm<br>eff -M -Dmpvjfl ejemplo.xm</b><p>Cualquiera de estas sentencias produce un volcado en lenguaje ensamblador con todos los 'huecos' delimitados y rellenos con ceros por defecto. El fichero de cabecera EFF.INC recopila los efectos XM que realmente se utilizan en el fichero XM dado, más algunas banderas adicionales para deshabilitar las funciones de pausar/reanudar, control de volumen, Jump2Pattern, soporte para ficheros y XM_NOLOOP. Copie EFF.INC en src/ufmodlib/src/ y recompile la librería. Consulte la siguiente sección para mayor información sobre cómo recompilar uFMOD. Acaba de compilar su propia versión ultraoptimizada de uFMOD, pero recuerde que ésta contiene un subconjunto de efectos XM. Entonces, ¡sólo servirá para reproducir correctamente el fichero XM especificado como parámetro! |
+</ul>Una vez terminada la modificación del código fuente, si desea recompilar ufmod.obj, abra el fichero de procesamiento por lotes src/ufmodlib/makeobj.bat en un editor de texto plano. Todo lo contenido entre las siguientes líneas:<pre>rem *** CONFIG START</pre>y<pre>rem *** CONFIG END</pre>es configurable. Verifique los valores en la sección <code>Pathes</code>. Una de las opciones dice:<pre>SET UF_NASM=\nasm</pre>Si Ud. tiene instalado NASM, asegúrese de que el camino allí especificado apunte exactamente a la ubicación de nasmw.exe. Supongamos que NASM se encuentra instalado en <code>D:\TOOLS\NASM</code>. Entonces, vamos a modificar el camino de la siguiente forma:<pre>SET UF_NASM=D:\TOOLS\NASM</pre>No todos los caminos deben ser configurados correctamente para recompilar la librería. Por ejemplo, si Ud. prefiere usar FASM como el ensamblador por defecto, no es necesario configurar el camino de NASM. Asegúrese de que todos los caminos necesarios para recompilar la librería sean correctos. Luego, configure las opciones disponibles, de acuerdo con la siguiente tabla:<p><table border=0 cellpadding=4 cellspacing=2 style='font-size:10pt;font-family:Arial,Aerial'><tr bgcolor=#708090 style='color:#E7E7E7;font-weight:bold'><td>Opción<td>Descripción<td width=200>Valores disponibles<tr valign=top><td>UF_RAMP<td>Esta opción controla el acoplador de volúmen (interpolación). Esto sirve para suprimir cierto tipo de defecto de sonido conocido como clic, común en música sintetizada. Sin embargo, la interpolación en algunos casos puede generar distorsión. STRONG (fuerte) es el valor por defecto, recomendado para la mayoría de las aplicaciones. En este modo, el acoplador detecta variaciones de volúmen y las suaviza mediante interpolación lineal de 128 etapas. En modo WEAK (débil) hay sólo 16 etapas. WEAK es menos efectivo que STRONG, pero la probabilidad de distorsión también es menor. NONE deshabilita el acoplador. Si no hay interpolación, no puede haber distorsión, pero los clics quedarían al descubierto, a menos que el contenido del XM se encuentre perfectamente balanceado.<td>NONE, WEAK, STRONG<tr bgcolor=#E7E7E7 valign=top><td>UF_FREQ<td>Frecuencia de muestreo (en Hz). 48KHz es el valor recomendado para la mayoría de las aplicaciones.<td>22050, 44100, 48000<tr valign=top><td>UF_ASM<td>Ensamblador. La librería uFMOD se puede compilar con diferentes ensambladores. Escoja su favorito :)<td>MASM, NASM, FASM<tr bgcolor=#E7E7E7 valign=top><td>UF_MODE<td>NORMAL es el valor por defecto. No tiene nada de especial. UNSAFE deshabilida la comprobación de validez del formato XM a la hora de cargar el fichero. Si Ud. está seguro de que todos los ficheros XM están correctos (puede verificarlos con Eff o con XMStrip), puede recompilar uFMOD en modo UNSAFE para reducir el tamaño de la librería y el tiempo de carga. Tenga en cuenta que ¡Un XM corrupto podría ocasionar un fallo en modo UNSAFE! El modo AC97SND hace que ufmod.obj contenga una versión especial de la librería uFMOD. Esta versión se usa en el reproductor de MP3 de Serge que viene preinstalado en KolibriOS. También puede servir en otras aplicaciones orientadas al uso de codecs. Para mayor información puede consultar el fichero ufmod-codec.h.<td>NORMAL, UNSAFE, AC97SND</table><p>Ejecute el fichero de procesamiento por lotes para generar la librería. ¡Eso es todo!<p> <br><a name='4'><b>Ejemplos</b></a><p>Hay 2 ejemplos disponibles actualmente: mini y jmp2pat. Los ejecutables precompilados se encuentran en bin/. Estos ejecutables no estan empaquetados ni comprimidos.<ul><li><b>mini</b> es el ejemplos más simple. Presenta cómo reproducir una pista XM en memoria, con manejo adecuado de errores.<li><b>jmp2pat</b> es un ejemplo de uso de la función Jump2Pattern. Utiliza un XM compuesto de varias pistas, proporcionado por Kim (también conocido como norki). Consulte la sección siguiente para mayor información sobre pistas compuestas y la función Jump2Pattern.</ul><p> <br><a name='5'><b>Cómo lograr un ejecutable más compacto</b></a><p>Utilice <a href='#22'>Eff</a> para optimizar la librería uFMOD y hacerla mas pequeña.<p>Si desea embeber la pista XM directamente en el ejecutable, puede intentar primero optimizar el fichero XM. Modplug Player permite comprimir un fichero XM usando ADPCM, ¡pero es un tipo de compresión con pérdidas! Utilice <a href='#21'>XMStrip</a> para optimización sin pérdidas (en términos de calidad del sonido.)<p>Si tiene plena certeza de que todos los XM que va a reproducir la aplicación son válidos (ninguno puede estar corrupto o modificado), recompile la librería en modo UNSAFE.<p>Empaquetadores, como mtappack desarrollado por diamond, logran reducir el tamaño del ejecutable. Sin embargo, para mayor objetividad, los ejecutables de ejemplo ¡no estan comprimidos!<p>Ahora veamos otra técnica interesante para minimizar el tamaño de los ficheros XM:<p>Es posible unir varias pistas XM en un solo fichero compuesto. Ya que es posible compartir los instrumentos entre las pistas en el fichero compuesto, el tamaño resultante de este fichero puede ser mucho menor que la suma de los tamaños de los ficheros por separado. Aún sin compartir los instrumentos el tamaño debe ser menor, puesto que sólo se usa un único ejemplar de cabecera XM. Veamos un ejemplo con 3 ficheros XM:<pre> |
+<b>Fichero 1 :</b> CABECERA_XM1 P11 P12 P13 I11 I12 |
+<b>Fichero 2 :</b> CABECERA_XM2 P21 P22 P23 P24 I21 I22 I23 I24 |
+<b>Fichero 3 :</b> CABECERA_XM3 P31 I31 |
+</pre><i><b>Leyenda:</b> CABECERA_XMn es la cabecera del n-ésimo fichero. Pni es el i-ésimo patrón del n-ésimo fichero. Ini es el i-ésimo instrumento del n-ésimo fichero.</i><p>Primero, vamos a unir los 3 ficheros en uno solo sin compartir los instrumentos:<pre> |
+<b>Fichero 4 :</b> CABECERA_XM4 P11 P12 P13 P21 P22 P23 P24 P31 I11 I12 I21 I22 I23 I24 I31 |
+</pre>Supongamos que I12 es muy similar o identico a I23 y que I24 es igual que I31. Podemos modificar P2n para hacer que utilicen I12 en vez de I23 y enlazar P31 con I24. Entonces, podremos eliminar I23 e I31:<pre> |
+<b>Fichero 4 :</b> CABECERA_XM4 P11 P12 P13 P21 P22 P23 P24 P31 I11 I12 I21 I22 I24 |
+</pre>Al final tendrá que modificar los comandos de ciclos y saltos de patrones y las referencias a instrumentos en los "ficheros" 2 y 3. Obviamente, también es posible unir apenas 2 o más de 3 ficheros, aunque el formato XM establece límites para el número máximo de patrones e instrumentos en un fichero. Esa es, en general, la idea. Es necesario saber usar un tracker para realizar todas estas operaciones sobre un fichero XM. Una vez unidas todas las pistas en un fichero compuesto, podrá iniciar la reproducción con un único llamado a uFMOD_PlaySong y "activar" las pistas por separado con llamados a uFMOD_Jump2Pattern. Por ejemplo, uFMOD_Jump2Pattern(3) pasaria a reproducir la segunda pista, uFMOD_Jump2Pattern(7) saltaria a la tercera y uFMOD_Jump2Pattern(0) regresaria a la primera. Los indices exactos en cada caso dependen de los patrones asignados con el tracker. El ejemplo <b>jmp2pat</b> emplea esta clase de optimización.<p>El uso de Jump2Pattern tiene otra ventaja: la conmutación de pistas se realiza mucho más rápido (casi de inmediato) que el proceso habitual de parar la pista actual y cargar una pista nueva. Por lo tanto, puede usar esta técnica cuando necesite conmutar las pistas de audio de la manera más rápida posible.<p> <br><a name='6'><b>Preguntas frecuentes</b></a><p><span style='color:#008080'><b>P:</b> ¿Es uFMOD gratis para cualquier tipo de uso, incluido el comercial?</span><br><b>R:</b> Si, actualmente así es.<p><span style='color:#008080'><b>P:</b> ¿En donde puedo conseguir música en formato XM?</span><br><b>R:</b> En <a href='http://modarchive.org/'>The Mod Archive</a> hay un enorme archivo de música gratis en formatos XM, IT, S3M y MOD. Puede usar el <a href='http://www.modplug.com/'>Open Modplug Tracker</a> para convertir ficheros IT, S3M y MOD a formato XM sin perder la calidad. Hay muchos compositores talentosos en la red dispuestos a compartir su música de manera gratuita. ¡Pero no olvide el copyright!<p><span style='color:#008080'><b>P:</b> ¿Existe alguna relación entre el proyecto uFMOD y las librerías FMOD y/o miniFMOD de Firelight Technologies®?</span><br><b>R:</b> Ya no. Hasta el año 2004 uFMOD se basó en el código fuente abierto de la librería miniFMOD. Desde ese entonces, el código fuente de uFMOD fue completamente reescrito, optimizado y depurado. También fueron agregadas muchas funciones nuevas. Por lo tanto, la versión actual de uFMOD no tiene relación alguna con FMOD o miniFMOD.<p><span style='color:#008080'><b>P:</b> Algunas librerías aseguran incrementar el tamaño del ejecutable en N kilobytes. ¿En cuanto se incrementa el tamaño de un ejecutable con uFMOD?</span><br><b>R:</b> No es posible establecer un valor exacto, ya que el tamaño depende de muchos factores, a saber: funciones usadas (en especial, si se utiliza la herramienta EFF), código de la aplicación principal, tamaño del fichero XM (cuando el XM es embebido en el ejecutable). También depende de las opciones del linker. El ejemplo bin/mini ocupa únicamente 4.768 bytes sin compresión.<p><span style='color:#008080'><b>P:</b> ¿En dónde puedo conseguir la especificación oficial del formato XM?</span><br><b>R:</b> No existe especificación oficial actualizada. En cambio, puede estudiar el documento <a href='http://sourceforge.net/project/showfiles.php?group_id=158498&package_id=234625'>"The Unofficial XM File Format Specification: FastTracker II, ADPCM and Stripped Module Subformats"</a> (sólo en inglés). Este documento describe la mayoría de los aspectos relevantes del formato XM original, al igual que todas las extensiones extraoficiales actualmente soportadas por uFMOD. Los códigos fuente de ModPlug (en C++) sirven de referencia sobre formatos derivados del MOD, XM, IT, S3M y muchos otros.<p> <br><a name='7'><b>Agradecemos a</b></a><p>antarman, Barracuda, bogrus, chris_b, cresta, dododo, flaith, Four-F, GL#0M, norki, q_q, SofT MANiAC, S_T_A_S_, voodooattack y yoxola por reportar errores, sugerir nuevas ideas, aportar ejemplos de uso y de otras formas ayudarnos a mejorar uFMOD.<p><a href='http://wasm.ru'>[WASM.RU]</a> y <a href='http://sf.net'>SourceForge.net</a> por el soporte y hosting.<p> <br><b>Copyright</b><p>Los códigos fuente y ficheros binarios de uFMOD © 2005 - 2007 Asterix y Quantum.<br>Todos los derechos reservados.<p>Pistas de ejemplo:<ul><li>Minimal III © 2006 - 2007 SofT MANiAC (CoolPHat).<li>BlitzXMK.XM del ejemplo Jump2Pat © 2007 Kim (también conocido como norki).</ul></div><table border=0 cellpadding=0 cellspacing=0 width=100%><tr bgcolor=#708090><td height=1><tr bgcolor=#E7E7E7><td height=52 style='color:#708090;font-size:10pt;font-family:Arial,Aerial' align=center>¿Desea reportar un error? ¿Tiene preguntas o sugerencias?<br> ¿Está desarrollando un gran proyecto usando uFMOD? Por favor, mantenganos al tanto: <a href='mailto:ufmod@users.sf.net' name='ci'>ufmod@users.sf.net</a></table></body></html> |
\ No newline at end of file |
/programs/develop/libraries/ufmod/readme_ru.htm |
---|
0,0 → 1,34 |
<html lang=ru><head><meta http-equiv=Content-Type content="text/html; charset=windows-1251"><title>uFMOD</title></head><body style='margin:0'><table border=0 cellpadding=0 cellspacing=0 width=100%><tr bgcolor=#E7E7E7 align=center><td height=20 style='color:#708090;font-size:9pt;font-family:Arial,Aerial'>[ <a href='en.htm'>English</a> | <a href='es.htm'>Español</a> | Pyccκuú ]<tr bgcolor=#708090><td height=1></table><center><h2 style='font-size:14pt;font-family:Arial,Aerial'>μFMOD v1.25 äëÿ KolibriOS</h2></center><div style='font-size:10pt;font-family:Arial,Aerial;text-align:justify;margin:8'><p>uFMOD - ýòî êîìïàêòíàÿ, øóñòðàÿ, íàä¸æíàÿ, ìóëüòèïëàòôîðìåííàÿ áèáëèîòåêà äëÿ êà÷åñòâåííîãî âîñïðîèçâåäåíèÿ àóäèî â ôîðìàòå XM, ðàçðàáîòàííàÿ ïîëíîñòüþ íà àññåìáëåðå. XM ìîæåò õðàíèòüñÿ â îòäåëüíîì ôàéëå èëè ïðåäâàðèòåëüíî çàãðóæåí â ïàìÿòü. Ïîääåðæèâàþòñÿ òàêæå áèòûå è íå ñîâñåì ñòàíäàðòíûå ôàéëû. Áèáëèîòåêà ðàñïðîñòðàíÿåòñÿ ñ îòêðûòûì èñõîäíûì êîäîì è ïðèìåðàìè äëÿ ñëåäóþùèõ êîìïèëÿòîðîâ: FASM, MASM32 è NASM.<p>Âåðñèÿ äëÿ KolibriOS äîëæíà èñïðàâíî ðàáîòàòü íà ëþáûõ êîíôèãóðàöèÿõ, óäîâëåòâîðÿþùèõ ñëåäóþùèì òðåáîâàíèÿì:<ol><li>Ìèíèìàëüíàÿ ðåâèçèÿ SVN ÿäðà è äðàéâåðîâ KolibriOS: 574. Ïîñëåäíèå âåðñèè äèñòðèáóòèâîâ è îáíîâëåíèÿ SVN ìîæíî ñêà÷àòü ñ îôèöèàëüíîãî ñàéòà: <a href='http://www.kolibrios.org/'>www.kolibrios.org</a>.<li>Çâóêîâàÿ êàðòî÷êà, ïîääåðæèâàåìàÿ àóäèî-áèáëèîòåêîé <a href='http://infinity-sound.narod.ru/'>Infinity Sound</a> - ýòî âñòðîåííûé çâóêîâîé äðàéâåð KolibriOS. Íà äàííûé ìîìåíò äðàéâåð ïîääåðæèâàåò ìíîãèå âñòðîåííûå êîäåêè ñîâìåñòèìûå ñî ñòàíäàðòîì AC'97.</ol>Âàøà êîíôèãóðàöèÿ óäîâëåòâîðÿåò âûøåïåðå÷èñëåííûì òðåáîâàíèÿì, íî uFMOD íà íåé îòêàçûâàåòñÿ ðàáîòàòü? - Ïîæàëóéñòà, ñîîáùèòå íàì îá ýòîì (<a href='#ci'>êîíòàêòíûå äàííûå</a> ïðèâîäÿòñÿ â íèçó äàííîé ñòðàíèöû).<p><ul><li><a href='#1'>Ïðåæäå ÷åì íà÷àòü</a><li><a href='#2'>Óòèëèòû</a><ul><li><a href='#21'>XMStrip</a><li><a href='#22'>Eff</a></ul><li><a href='#3'>Êîìïèëÿöèÿ áèáëèîòåêè</a><li><a href='#4'>Ïðèìåðû</a><li><a href='#5'>Äîïîëíèòåëüíîå óìåíüøåíèå ðàçìåðà</a><li><a href='#6'>×àÂî</a><li><a href='#7'>Áëàãîäàðíîñòè</a></ul><p> <br><a name='1'><b>Ïðåæäå ÷åì íà÷àòü</b></a><p>KolibriOS - ýòî îïåðàöèîííàÿ ñèñòåìà, íàïèñàííàÿ íà àññåìáëåðå. Ïîýòîìó ó íå¸ òàêîé ìàëåíüêèé ðàçìåð è òàêàÿ âûñîêàÿ ïðîèçâîäèòåëüíîñòü, íî òîëüêî íå â óùåðá âîçìîæíîñòÿì ýòîé ïîëíîöåííîé îïåðàöèîíêè, êàê Âû, âîçìîæíî, óæå óáåäèëèñü. Àíàëîãè÷íàÿ èäåîëîãèÿ ïîääåðæèâàåòñÿ è â ïðîåêòå uFMOD ;)<p>Îñíîâíóþ ÷àñòü äàííîãî ðóêîâîäñòâà ìîæíî óñïåøíî âûïîëíèòü ïðÿìî â ñàìîé ñèñòåìå Kolibri. Òåì íå ìåíåå, òàê êàê ìíîãèå íîâè÷êè â ïðîãðàììèðîâàíèè Kolibri ïðåäïî÷èòàþò êîìïèëèðîâàòü ñâîè ïðîåêòû â Windows è ïîòîì ïåðåíîñèòü èõ â Kolibri äëÿ òåñòèðîâàíèÿ, â äàííîì ðóêîâîäñòâå ìû ïðèìåíèì êðîññêîìïèëÿöèþ.<p> <br><a name='2'><b>Óòèëèòû</b></a><p>Åñòü ïàðà áåñïëàòíûõ óòèëèò äëÿ èñïîëüçîâàíèÿ ñîâìåñòíî ñ uFMOD: XMStrip è Eff. Ïîêà ÷òî íè îäíà èç íèõ íå ïîðòèðîâàíà â Kolibri. Ïîýòîìó ìîæåòå ñêà÷àòü ëþáîé èç äðóãèõ äèñòðèáóòèâîâ uFMOD (äëÿ Win32, Linux èëè Unix/BSD) è èñïîëüçîâàòü óòèëèòû êðîññïëàòôîðìåííî. Íåçàâèñèìî îò âûáðàííîãî äèñòðèáóòèâà, îáå óòèëèòû ñîâìåùàþò â ñåáå êîíñîëüíûé è ãðàôè÷åñêèé (GUI) èíòåðôåéñû. Ðåæèì GUI èíòóèòèâíî ïîíÿòåí. Äàâàéòå ðàññìîòðèì êîíñîëüíûé èíòåðôåéñ.<p><table border=0 cellpadding=0 cellspacing=0 bgcolor=#708090 style='font-size:9pt;font-family:Arial,Aerial'><tr><td colspan=3 height=1><tr height=18><td style='color:#E7E7E7'><b> SVN </b><td bgcolor=#E7E7E7> <a href='http://ufmod.svn.sourceforge.net/viewvc/ufmod'>Èñõîäíèêè äîñòóïíû ÷åðåç SVN</a> <td width=1><tr><td colspan=3 height=1></table><p><a name='21'><b><i>XMStrip</i></b></a> îáðàáàòûâàåò çàäàííûé XM ôàéë ñ öåëüþ óìåíüøåíèÿ ðàçìåðà, áåç ïîòåðè êà÷åñòâà çâó÷àíèÿ.  ïðîöåññå îáðàáîòêè, XMStrip óäàëÿåò íåèñïîëüçóþùèåñÿ èíñòðóìåíòû è ïàðòèòóðû, âûðåçàåò êîììåíòàðèè è ïåðåïàêîâûâàåò âíóòðåííèå ñòðóêòóðû ôàéëà äëÿ óìåíüøåíèÿ ðàçìåðà è ïîâûøåíèÿ ñêîðîñòè çàãðóçêè. Äëÿ íà÷àëà, îòêðîåì êîíñîëü è ââåä¸ì <code>xmstrip /h</code>, ÷òîáû ïîëó÷èòü ñëåäóþùåå ñîîáùåíèå:<p><center><table border=0 cellpadding=8><tr bgcolor=#000000><td><pre><font color=#FFFFFF> USAGE: xmstrip [options] file [output] |
file - input file name. |
output - optional output file name. |
options: |
/c - clean only (don't strip) |
When [output] is not specified, XMSTRIP |
attempts to overwrite the input. If file |
name contains spaces, enclose it in "".</font></td></tr></table></center><p>Åñëè èìÿ ñîõðàíÿåìîãî ôàéëà íå óêàçàíî, XMStrip ïåðåçàïèøåò çàäàííûé ôàéë. Åñëè èìÿ ôàéëà ñîäåðæèò ïðîáåëû, åãî íåîáõîäèìî çàêëþ÷èòü â êàâû÷êè ("").<p>Èìåéòå â âèäó, ÷òî äðóãèå ïðîèãðûâàòåëè XM ôàéëîâ, âîçìîæíî, îòêàæóòñÿ âîñïðîèçâîäèòü ôàéë, îáðàáîòàííûé XMStrip. Îïöèÿ <b>/c</b> ïðåäóñìîòðåíà äëÿ âîññòàíîâëåíèÿ òàêèõ ôàéëîâ èëè îáðàáîòêè îáû÷íûõ XM ôàéëîâ, êîòîðûå ïëàíèðóåòñÿ ïðîèãðûâàòü íå òîëüêî â uFMOD.<p><a name='22'><b><i>Eff</i></b></a> ïðåäíàçíà÷àåòñÿ äëÿ îïûòíûõ êîäåðîâ, æåëàþùèõ ñýêîíîìèòü êàæäûé áàéò â ñâîèõ ïðèëîæåíèÿõ. Äëÿ ýòîãî íóæíî âûäåëèòü òîëüêî òå ôóíêöèè uFMOD, êîòîðûå äåéñòâèòåëüíî áóäóò èñïîëüçîâàíû â öåëåâîì ïðèëîæåíèè, ïåðåêîìïèëèðîâàòü áèáëèîòåêó è ïîëó÷èòü íàèìåíüøèé âîçìîæíûé ðàçìåð. Âîò, ÷òî âûäà¸ò <code>eff /h</code> :<p><center><table border=0 cellpadding=8><tr bgcolor=#000000><td><pre><font color=#FFFFFF> USAGE: eff [options] file |
file - input file name |
options: |
/Dm - generate a masm32/tasm dump |
/Dd - generate a Pascal (Delphi) dump |
/Dc - generate a C/C++ dump |
/Ds - generate an RCDATA resource dump |
/Di - disable infoAPI: |
uFMOD_GetStats, uFMOD_GetRowOrder, |
uFMOD_GetTitle and uFMOD_GetTime |
/Dp - disable uFMOD_Pause, uFMOD_Resume |
and XM_SUSPENDED |
/Dv - disable volume control |
/Dj - disable Jump2Pattern |
/Df - disable loading XM from file |
/Dl - disable XM_NOLOOP |
/M - mark & clear unused chunks of |
+<li><span style='color:#800080'><b>eff.inc</b></span> - ýòîò çàãîëîâî÷íûé ôàéë ñîçäà¸òñÿ óòèëèòîé <a href='#22'>Eff</a>. Íå ðåêîìåíäóåòñÿ ðåäàêòèðîâàòü äàííûé ôàéë âðó÷íóþ! Íàñòîÿùèå êîäåðû íå îáðàùàþò âíèìàíèÿ íà ïîäîáíûå ïðåäóïðåæäåíèÿ, íî âñ¸ æå... :)<li><span style='color:#800080'><b>ufmod.inc</b></span> ñîäåðæèò ïîäðîáíîå îïèñàíèå API uFMOD äëÿ èñïîëüçîâàíèÿ â ïðîåêòàõ íà ASM/C/C++.<li><span style='color:#800080'><b>ufmod-codec.h</b></span> ñîäåðæèò îïèñàíèå àëüòåðíàòèâíîãî API uFMOD, êîòîðîå ïðåäîñòàâëÿåòñÿ áèáëèîòåêîé â ðåæèìå AC97SND - ýòîò ðåæèì ïðåäíàçíà÷åí äëÿ èñïîëüçîâàíèÿ â ïëååðàõ àóäèî-ôàéëîâ, âðîäå AC'97 MP3 Player Serge'ÿ.<li> <span style='color:#008080'><b>core.asm</b></span> íàõîäèòñÿ áîëüøàÿ ÷àñòü èñõîäíîãî êîäà uFMOD. Ýòîò ñàìûé ôàéë ïðèñóòñòâóåò âî âñåõ äèñòðèáóòèâàõ áèáëèîòåêè: KolibriOS, Unix/BSD, Linux è Win32. Çàãðóçêà XM-ôàéëà, ñìåøèâàíèå êàíàëîâ, íàëîæåíèå ýôôåêòîâ è ìíîãèå äðóãèå îáùèå äëÿ âñåõ äèñòðèáóòèâîâ àëãîðèòìû ðåàëèçîâàíû â äàííîì ôàéëå.<li><span style='color:#008080'><b>ufmod.asm</b></span> ñîäåðæèò ïëàòôîðìîçàâèñèìûå ïðîöåäóðû: ôàéëîâûé Â/Â, îáùåíèå ñî çâóêîâûì äðàéâåðîì è ò.ä. Ïîýòîìó, ñîäåðæèìîå äàííîãî ôàéëà ðàçëè÷àåòñÿ â äèñòðèáóòèâàõ äëÿ ðàçíûõ ÎÑåé.<li><span style='color:#008080'><b>fasm.asm</b></span> õðàíèò îïðåäåëåíèÿ êîíñòàíò, ñòðóêòóð è ò.ä. ïîä ñèíòàêñèñ Flat Assembler (FASM). Ýòîò ôàéë ïîçâîëÿåò ñîáèðàòü áèáëèîòåêó ñ ïîìîùüþ FASM.<li><span style='color:#008080'><b>masm.asm</b></span> õðàíèò îïðåäåëåíèÿ êîíñòàíò, ñòðóêòóð è ò.ä. ïîä ñèíòàêñèñ MASM32. Ýòîò ôàéë ïîçâîëÿåò ñîáèðàòü áèáëèîòåêó ñ ïîìîùüþ MASM32.<li><span style='color:#008080'><b>nasm.asm</b></span> õðàíèò îïðåäåëåíèÿ êîíñòàíò, ñòðóêòóð è ò.ä. ïîä ñèíòàêñèñ Netwide Assembler (NASM). Ýòîò ôàéë ïîçâîëÿåò ñîáèðàòü áèáëèîòåêó ñ ïîìîùüþ NASM.</ul>Ñëåäóþùèì ïîñëå âíåñåíèÿ èçìåíåíèé â èñõîäíèêè øàãîì ÿâëÿåòñÿ êîìïèëÿöèÿ. ×òîáû ïåðåñîáðàòü ufmod.obj, ñíà÷àëà îòêðîéòå â òåêñòîâîì ðåäàêòîðå áàòíèê src/ufmodlib/makeobj.bat. Âñ¸, ÷òî íàõîäèòñÿ ìåæäó ñëåäóþùèõ ñòðîê:<pre>rem *** CONFIG START</pre>è<pre>rem *** CONFIG END</pre>ïîäëåæèò íàñòðîéêå. Îáðàòèòå âíèìàíèå íà ñåêöèþ <code>Pathes</code>. Òàì åñòü òàêàÿ îïöèÿ:<pre>SET UF_NASM=\nasm</pre>Åñëè ó Âàñ óñòàíîâëåí NASM, óäîñòîâåðüòåñü, ÷òî ïóòü â äàííîé îïöèè óêàçûâàåò òî÷íî òóäà, ãäå íàõîäèòñÿ nasmw.exe. Äîïóñòèì, NASM óñòàíîâëåí â <code>D:\TOOLS\NASM</code>.  òàêîì ñëó÷àå, íåîáõîäèìî ñêîððåêòèðîâàòü îïöèþ ñëåäóþùèì îáðàçîì:<pre>SET UF_NASM=D:\TOOLS\NASM</pre>Íå âñå ïóòè íåîáõîäèìû äëÿ óñïåøíîé êîìïèëÿöèè. Íàïðèìåð, åñëè Âû íàìåðåíû èñïîëüçîâàòü FASM, íå íóæíî íàñòðàèâàòü UF_NASM. Ïðîâåðüòå ïðàâèëüíîñòü âñåõ ïóòåé, íåîáõîäèìûõ äëÿ êîìïèëÿöèè. Òåïåðü íàñòðîéòå ïàðàìåòðû êîíôèãóðàöèè, ñîãëàñíî ñëåäóþùåé òàáëèöå:<p><table border=0 cellpadding=4 cellspacing=2 style='font-size:10pt;font-family:Arial,Aerial'><tr bgcolor=#708090 style='color:#E7E7E7;font-weight:bold'><td>Îïöèÿ<td>Îïèñàíèå<td width=200>Çíà÷åíèÿ<tr valign=top><td>UF_RAMP<td>Äàííàÿ îïöèÿ ïîçâîëÿåò íàñòðîèòü ìåõàíèçì èíòåðïîëÿöèè, êîòîðûé ïðåäíàçíà÷åí äëÿ ïîãàøåíèÿ ùåë÷êîâ - ðåçêèå ïåðåïàäû àìïëèòóäû ñèãíàëà, õàðàêòåðíûå äëÿ òðåêåðñêîé ìóçûêè. Ñ äðóãîé ñòîðîíû, èíòåðïîëÿöèÿ âíîñèò èñêàæåíèå â âûñîêî÷àñòîòíûå ñïåêòðàëüíûå ñîñòàâëÿþùèå ñèãíàëà, ÷òî èíîãäà áûâàåò çàìåòíî. STRONG - ýòî çíà÷åíèå ïî óìîë÷àíèþ, ðåêîìåíäóåìîå äëÿ áîëüøèíñòâà ïðèëîæåíèé.  äàííîì ðåæèìå ìèêñåð ñãëàæèâàåò ðåçêèå ïåðåïàäû àìïëèòóäû, ïðèìåíÿÿ ëèíåéíóþ 128-ñòóïåí÷àòóþ èíòåðïîëÿöèþ. WEAK íàêëàäûâàåò ëèøü 16 ñòóïåíåé - ýòîò ðåæèì ìåíåå ýôôåêòèâåí, ÷åì STRONG, íî çàòî âåðîÿòíîñòü äåãðàäàöèè ñèãíàëà â ýòîì ðåæèìå íèæå. NONE âîîáùå îòêëþ÷àåò èíòåðïîëÿöèþ. Áåç ñãëàæèâàíèÿ íå áóäåò è äåãðàäàöèè, íî áîëüøèíñòâî êîìïîçèöèé áåç ñãëàæèâàíèÿ áóäåò çâó÷àòü çàìåòíî õóæå èç-çà íàëîæåíèÿ ùåë÷êîâ. Îñîáûì îáðàçîì ñáàëàíñèðîâàííûå êîìïîçèöèè áåç ñãëàæèâàíèÿ ìîãóò çâó÷àòü ëó÷øå.<td>NONE, WEAK, STRONG<tr bgcolor=#E7E7E7 valign=top><td>UF_FREQ<td>×àñòîòà äèñêðåòèçàöèè (â Ãö). 48ÊÃö ÿâëÿåòñÿ çíà÷åíèåì, ðåêîìåíäóåìûì äëÿ áîëüøèíñòâà ïðèëîæåíèé.<td>22050, 44100, 48000<tr valign=top><td>UF_ASM<td>Àññåìáëåð. Äà, uFMOD ìîæíî ñîáèðàòü ðàçíûìè àññåìáëåðàìè - âûáèðàéòå òîò, êîòîðûé áîëüøå íðàâèòñÿ :)<td>MASM, NASM, FASM<tr bgcolor=#E7E7E7 valign=top><td>UF_MODE<td>NORMAL - ýòî çíà÷åíèå ïî óìîë÷àíèþ. Íè÷åãî îñîáåííîãî. UNSAFE îòêëþ÷àåò ïðîâåðêó ïðàâèëüíîñòè ôîðìàòà XM ïåðåä çàãðóçêîé êîìïîçèöèè. Åñëè Âû óâåðåíû, ÷òî âñå êîìïîçèöèè, êîòîðûå áóäóò ïðîèãðûâàòüñÿ â âàøåì ïðèëîæåíèè, êîððåêòíû (ïðàâèëüíîñòü ôîðìàòà XM-ôàéëà ìîæíî ïðîâåðèòü â Eff èëè XMStrip), ìîæåòå ïåðåñîáðàòü áèáëèîòåêó â ðåæèìå UNSAFE, ÷òîáû âûéãðàòü â ðàçìåðå è ñêîðîñòè çàãðóçêè. Èìåéòå â âèäó, ÷òî çàãðóçêà íåïðàâèëüíîãî XM-ôàéëà â ðåæèìå UNSAFE ìîæåò ïðèâåñòè ê êðàõó!  ðåæèìå AC97SND áèáëèîòåêà ïðåäñòàâëÿåò ñîáîé êîäåê äëÿ ïðîèãðûâàòåëÿ AC'97 MP3 Player Serge'ÿ. Äàííûé ðåæèì ìîæåò áûòü ïîëåçåí è äëÿ äðóãèõ ïðîåêòîâ ñõîäíîé íàïðàâëåííîñòè. Îïèñàíèå API äàííîãî ðåæèìà ìîæíî íàéòè â ufmod-codec.h.<td>NORMAL, UNSAFE, AC97SND</table><p>Çàïóñòèòå áàòíèê, ÷òîáû ñîáðàòü áèáëèîòåêó. Âîò è âñ¸!<p> <br><a name='4'><b>Ïðèìåðû</b></a><p> äàííûé äèñòðèáóòèâ âîøëè 2 ïðèìåðà: mini è jmp2pat. Îòêîìïèëèðîâàííûå ýêçåøíèêè íàõîäÿòñÿ â bin/. Çàìåòüòå, ÷òî ýêçåøíèêè ïðåäñòàâëåíû áåç ñæàòèÿ.<ul><li><b>mini</b> - ýòî ïðîñòåéøèé ïðèìåð ôîíîâîãî ïðîèãðûâàíèÿ ìóçûêè èç ïàìÿòè.<li><b>jmp2pat</b> - ýòî ïðèìåð èñïîëüçîâàíèÿ ôóíêöèè Jump2Pattern.  äàííîì ïðèìåðå ïðîèãðûâàåòñÿ êîìïîçèòíûé XM, ëþáåçíî ïðåäîñòàâëåííûé òîâàðèùåì Kim (îí æå norki). Îïèñàíèå òåõíèêè ñîçäàíèÿ è èñïîëüçîâàíèÿ ïîäîáíûõ êîìïîçèöèé ìîæíî íàéòè â ñëåäóþùåì ðàçäåëå.</ul><p> <br><a name='5'><b>Äîïîëíèòåëüíîå óìåíüøåíèå ðàçìåðà</b></a><p>Óòèëèòà <a href='#22'>Eff</a> ïðåäíàçíà÷åíà äëÿ îïòèìèçàöèè è óìåíüøåíèÿ ðàçìåðà áèáëèîòåêè uFMOD.<p>Åñëè Âû ñîáèðàåòåñü âêëþ÷èòü XM ñòàòè÷åñêè â ýêçåøíèê, ìîæåòå ïîïðîáîâàòü îïòèìèçèðîâàòü ñíà÷àëà ñàì XM. Modplug Player óìååò ñæèìàòü XM-êîìïîçèöèè ïî ñõåìå APDCM, íî ó÷òèòå, ÷òî ýòîò òèï ñæàòèÿ ïàãóáíî âëèÿåò íà êà÷åñòâî çâó÷àíèÿ! Óòèëèòà <a href='#21'>XMStrip</a> ïåðåïàêîâûâàåò XM ôàéë áåç ïîòåðè êà÷åñòâà.<p>Åñëè Âû óâåðåíû â êîððåêòíîñòè ôîðìàòà âñåõ êîìïîçèöèé, êîòîðûå áóäóò èñïîëüçîâàíû â ïðèëîæåíèè, ìîæåòå ïåðåñîáðàòü áèáëèîòåêó â ðåæèìå UNSAFE.<p>Óïàêîâùèêè, âðîäå mtappack diamond'à, óìåþò óæèìàòü ýêçåøíèêè. Òåì íå ìåíåå, äëÿ íàãëÿäíîñòè, âñå ïðèìåðû ïðåäîñòàâëåíû áåç ñæàòèÿ!<p>Åñòü åù¸ îäèí õèòðûé ñïîñîá îïòèìèçàöèè ðàçìåðà XM-ôàéëîâ, êîòîðûé çàêëþ÷àåòñÿ â ñîâìåùåíèè ñðàçó íåñêîëüêèõ êîìïîçèöèé â îäíîì ôàéëå. Ïðè ýòîì ìîæíî óäàëÿòü ëèøíèå ýêçåìïëÿðû ïîâòîðÿþùèõñÿ èíñòðóìåíòîâ, åñëè òàêîâûå èìåþòñÿ, ÷òî î÷åíü çàìåòíî ñêàçûâàåòñÿ íà ðàçìåðå êîíå÷íîãî ôàéëà. Äàæå áåç îïòèìèçàöèè èíñòðóìåíòîâ ðàçìåð êîìïîçèòíîãî ôàéëà äîëæåí ïîëó÷èòüñÿ ìåíüøå ñóììû ðàçìåðîâ îòäåëüíûõ ôàéëîâ, òàê êàê çàãîëîâêè âñåõ ôàéëîâ çàìåíÿþòñÿ îäíèì îáùèì. Äàâàéòå ðàññìîòðèì ïðèìåð ñ òðåìÿ ôàéëàìè:<pre> |
+<b>Ôàéë 1 :</b> XM1_HEADER P11 P12 P13 I11 I12 |
+<b>Ôàéë 2 :</b> XM2_HEADER P21 P22 P23 P24 I21 I22 I23 I24 |
+<b>Ôàéë 3 :</b> XM3_HEADER P31 I31 |
+</pre><i><b>Ïîÿñíåíèå:</b> XMn_HEADER - ýòî çàãîëîâîê n-íîãî ôàéëà. Pnm - ýòî m-íàÿ ïàðòèòóðà n-íîãî ôàéëà. Inm - ýòî m-íûé èíñòðóìåíò n-íîãî ôàéëà.</i><p>Äëÿ íà÷àëà, ñîâìåñòèì âñå 3 êîìïîçèöèè áåç îïòèìèçàöèè èíñòðóìåíòîâ:<pre> |
+<b>Ôàéë 4 :</b> XM4_HEADER P11 P12 P13 P21 P22 P23 P24 P31 I11 I12 I21 I22 I23 I24 I31 |
+</pre>Ïðåäñòàâüòå, ÷òî I12 î÷åíü ïîõîæ èëè èäåíòè÷åí I23; I24 è I31 òîæå ïðàêòè÷åñêè îäèíàêîâû. Ìû ìîæåì çàñòàâèòü ïàðòèòóðû P2n èñïîëüçîâàòü I12 âìåñòî I23, à P31 ïåðåêëþ÷èòü íà I24. Òîãäà ìû ñìîæåì óäàëèòü I23 è I31:<pre> |
+<b>Ôàéë 4 :</b> XM4_HEADER P11 P12 P13 P21 P22 P23 P24 P31 I11 I12 I21 I22 I24 |
+</pre>Íåîáõîäèìî ñêîððåêòèðîâàòü êîìàíäû çàöèêëèâàíèÿ è ññûëêè íà ïàðòèòóðû â êîìïîçèöèÿõ 2 è 3 ïîñëå ñîâìåùåíèÿ. Êîíå÷íî, ìîæíî ñîâìåùàòü è áîëüøåå êîëè÷åñòâî êîìïîçèöèé, íî ôîðìàò XM èìååò îãðàíè÷åíèÿ íà ìàêñèìàëüíîå êîëè÷åñòâî ïàðòèòóð è èíñòðóìåíòîâ â ôàéëå. Âñå îïåðàöèè íàä XM-ôàéëàìè íàäëåæèò ïðîâîäèòü â ñïåöèàëüíîì ÏÎ - òðåêåðå. Äëÿ ïðîèãðûâàíèÿ êîìïîçèòíîãî ôàéëà äîñòàòî÷íî îäíîãî âûçîâà ôóíêöèè uFMOD_PlaySong. Äàëåå íóæíî èñïîëüçîâàòü ôóíêöèþ uFMOD_Jump2Pattern äëÿ ïðîèãðûâàíèÿ îòäåëüíûõ êîìïîçèöèé èç îáùåãî ôàéëà â ïðîèçâîëüíîé ïîñëåäîâàòåëüíîñòè. Íàïðèìåð, uFMOD_Jump2Pattern(3) ïåðåêëþ÷èòñÿ íà âòîðóþ êîìïîçèöèþ, uFMOD_Jump2Pattern(7) íà÷í¸ò ïðîèãðûâàòü òðåòüþ, à uFMOD_Jump2Pattern(0) âåðí¸òñÿ îáðàòíî ê ïåðâîé. Òî÷íûå çíà÷åíèÿ èíäåêñîâ ñòàðòîâûõ ïàðòèòóð êàæäîé êîìïîçèöèè ïîñëå ñîâìåùåíèÿ ëåãêî âû÷èñëèòü â óìå, íî ìîæíî è â òðåêåðå ïîäñìîòðåòü :) Ïðèìåð <b>jmp2pat</b> èñïîëüçóåò äàííûé ñïîñîá îïòèìèçàöèè.<p> èñïîëüçîâàíèè Jump2Pattern åñòü åù¸ îäèí ïëþñ - ïåðåêëþ÷åíèå ïðîèñõîäèò ãîðàçäî áûñòðåå (ïðàêòè÷åñêè ìîìåíòàëüíî) ÷åì ïðè îñòàíîâêå òåêóùåé êîìïîçèöèè è ïîñëåäóþùåé çàãðóçêå íîâîé. Ìîæåòå áðàòü íà âîîðóæåíèå ýòó ôèøêó äëÿ ðåàëèçàöèè ðåøåíèé, òðåáóþùèõ ìàêñèìàëüíî áûñòðîãî ïåðåêëþ÷åíèÿ ìóçûêàëüíîãî ôîíà.<p> <br><a name='6'><b>×àÂî</b></a><p><span style='color:#008080'><b>Â:</b> Áèáëèîòåêà uFMOD äåéñòâèòåëüíî áåñïëàòíà äëÿ ëþáîãî èñïîëüçîâàíèÿ, âêëþ÷àÿ êîììåð÷åñêîå?</span><br><b>Î:</b> Äà, òåêóùàÿ âåðñèÿ àáñîëþòíî áåñïëàòíà äëÿ èñïîëüçîâàíèÿ â ëþáûõ öåëÿõ.<p><span style='color:#008080'><b>Â:</b> Ãäå áû äîñòàòü êîìïîçèöèè â ôîðìàòå XM?</span><br><b>Î:</b> <a href='http://modarchive.org/'>The Mod Archive</a> ñîäåðæèò âíóøèòåëüíûõ ðàçìåðîâ àðõèâ ñ áåñïëàòíûìè òðåêåðñêèìè êîìïîçèöèÿìè â ôîðìàòå XM, IT, S3M è MOD. <a href='http://www.modplug.com/'>Open Modplug Tracker</a> óìååò êîíâåðòèðîâàòü IT, S3M è MOD â XM áåç ïîòåðè êà÷åñòâà.  ñåòè ìíîãî òàëàíòëèâûõ êîìïîçèòîðîâ, êîòîðûå áåñïëàòíî âûêëàäûâàþò ñâîè ðàáîòû. Íå çàáûâàéòå óêàçûâàòü ñîîòâåòñòâóþùèå ïîìåòêè îá àâòîðñòâå!<p><span style='color:#008080'><b>Â:</b> Ñóùåñòâóåò ëè êàêàÿ-ëèáî ñâÿçü ìåæäó ïðîåêòîì uFMOD è ðàçðàáîòêàìè Firelight Technologies®: FMOD è miniFMOD?</span><br><b>Î:</b> Íà äàííûé ìîìåíò íèêàêîé ñâÿçè óæå íåò. Äî 2004ãî ãîäà âêëþ÷èòåëüíî ïðîåêò uFMOD îñíîâûâàëñÿ íà èñõîäíûõ êîäàõ áèáëèîòåêè miniFMOD. Ñ òåõ ïîð, êîä uFMOD áûë ïîëíîñòüþ ïåðåïèñàí, îñíàù¸í íîâûìè ôóíêöèÿìè, îïòèìèçèðîâàí è îòëàæåí. Òàêèì îáðàçîì, uFMOD áîëåå íå ñâÿçàí íè ñ FMOD, íè ñ miniFMOD.<p><span style='color:#008080'><b>Â:</b> Íåêîòîðûå ðàçðàáîò÷èêè óòâåðæäàþò, ÷òî èõ áèáëèîòåêè óâåëè÷èâàþò ýêçåøíèêè íà N-íîå êîëè÷åñòâî êèëîáàéò. Íà ñêîëüêî êèëîáàéò óâåëè÷èâàåòñÿ ðàçìåð ýêçåøíèêà ïðè èñïîëüçîâàíèè uFMOD?</span><br><b>Î:</b> Òî÷íîãî îòâåòà íà ýòîò âîïðîñ íåò, òàê êàê ýòîò ðàçìåð çàâèñèò îò ìíîãèõ ôàêòîðîâ: èñïîëüçóåìûå õàðàêòåðèñòèêè áèáëèîòåêè (îñîáåííî ïðè èñïîëüçîâàíèè óòèëèòû Eff), îñíîâíîé êîä ïðîãðàììû, ðàçìåð XM-ôàéëà (åñëè XM âêëþ÷àåòñÿ â îáðàç ýêçåøíèêà). Ðàçìåð òàêæå çàâèñèò îò îïöèé ëèíêåðà. Ïðèìåð bin/mini çàíèìàåò 4768 áàéò áåç ñæàòèÿ.<p><span style='color:#008080'><b>Â:</b> Ãäå ìîæíî ðàçäîáûòü îôèöèàëüíîå îïèñàíèå ôîðìàòà XM?</span><br><b>Î:</b> Ïîëíîãî îôèöèàëüíîãî îïèñàíèÿ ñîâðåìåííîãî ôîðìàòà XM íåò. Ïîçâîëüòå ïðåäëîæèòü âçàìåí ýòîò äîêóìåíò: <a href='http://sourceforge.net/project/showfiles.php?group_id=158498&package_id=234625'>"The Unofficial XM File Format Specification: FastTracker II, ADPCM and Stripped Module Subformats"</a> (òîëüêî íà àíãë.).  äàííîì äîêóìåíòå îïèñàíû ìíîãèå òîíêîñòè ðàáîòû ñ ôîðìàòîì XM, âêëþ÷àÿ âñå íåñòàíäàðòíûå ðàñøèðåíèÿ, êîòîðûå íà äàííûé ìîìåíò ïîääåðæèâàåò uFMOD. Ê òîìó æå, èç èñõîäíèêîâ ModPlug (íà C++) ìîæíî ïî÷åðïíóòü ìàññó ïîëåçíîé èíôîðìàöèè ïî òðåêåðñêèì ôîðìàòàì ôàéëîâ.<p> <br><a name='7'><b>Áëàãîäàðíîñòè</b></a><p>antarman, Barracuda, bogrus, chris_b, cresta, dododo, flaith, Four-F, GL#0M, norki, q_q, SofT MANiAC, S_T_A_S_, voodooattack è yoxola çà ïîìîùü â óñòðàíåíèè îøèáîê, ïðåäëîæåíèÿ ïî óëó÷øåíèþ áèáëèîòåêè, ïðèìåðû èñïîëüçîâàíèÿ ïîä ðàçíûå êîìïèëÿòîðû è âñ¸ îñòàëüíîå, òàê èëè èíà÷å ïîìîãàþùåå íàì â ðàçâèòèè ïðîåêòà.<p><a href='http://wasm.ru'>[WASM.RU]</a> è <a href='http://sf.net'>SourceForge.net</a> çà ïîääåðæêó è õîñòèíã.<p> <br><b>Àâòîð©òâî</b><p>Èñõîäíûå êîäû uFMOD è ñîïðîâîæäàþùèå óòèëèòàðíûå ïðèëîæåíèÿ © 2005 - 2007 Asterix è Quantum.<br>Âñå ïðàâà çàùèùåíû.<p>Êîìïîçèöèè:<ul><li>Minimal III © 2006 - 2007 SofT MANiAC (CoolPHat).<li>BlitzXMK.XM èç ïðèìåðà Jump2Pat © 2007 Kim (îí æå - norki).</ul></div><table border=0 cellpadding=0 cellspacing=0 width=100%><tr bgcolor=#708090><td height=1><tr bgcolor=#E7E7E7><td height=52 style='color:#708090;font-size:10pt;font-family:Arial,Aerial' align=center>Íàøëè îøèáêó? Æåëàåòå çàäàòü âîïðîñ ðàçðàáîò÷èêàì èëè âûñêàçàòü ïðåäëîæåíèå ïî óëó÷øåíèþ áèáëèîòåêè?<br>Ðàçðàáàòûâàåòå èíòåðåñíûé ïðîåêò ñ èñïîëüçîâàíèåì uFMOD? Âàì ñþäà: <a href='mailto:ufmod@users.sf.net' name='ci'>ufmod@users.sf.net</a></table></body></html> |
\ No newline at end of file |
/programs/develop/libraries/ufmod/ufmod-codec.h |
---|
0,0 → 1,89 |
/* |
uFMOD API reference (AC97SND mode) |
========================================================= |
NOTE: ufmod.obj should be rebuilt setting UF_MODE=AC97SND |
in order to make it usable in AC97SND player. |
The Infinity Sound driver handle should be available as |
a public symbol named hSound. It is so when using Serge's |
sound.lib. |
*/ |
#ifdef __cplusplus |
extern "C" { |
#endif |
/* HANDLE uFMOD_LoadSong(char *lpXM); |
--- |
Description: |
--- |
Loads the given XM song and starts playing it as soon as you |
call uFMOD_WaveOut for the first time. It will stop any |
currently playing song before loading the new one. Heap should |
be initialized before calling this function! |
--- |
Parameters: |
--- |
lpXM |
Specifies the filename of the song to load. |
--- |
Return Values: |
--- |
On success, returns a non zero value. Returns 0 on failure. |
*/ |
int __cdecl uFMOD_LoadSong(char*); |
/* int uFMOD_WaveOut(SNDBUF hBuff) |
--- |
Description: |
--- |
Updates the internal playback buffer. |
--- |
Parameters: |
--- |
hBuff |
The Infinity Sound buffer to update. |
--- |
Remarks: |
--- |
Playback doesn't actually begin when calling uFMOD_LoadSong, |
but when calling uFMOD_WaveOut after a successful uFMOD_LoadSong |
call. Afterwards, you should call uFMOD_WaveOut repeatedly at |
least once every 250 ms to prevent "buffer underruns". |
uFMOD_WaveOut is a non-blocking function. |
--- |
Return Values: |
--- |
Returns non zero on error. |
*/ |
int __cdecl uFMOD_WaveOut(unsigned int); |
/* void uFMOD_StopSong(void) |
--- |
Description: |
--- |
Stops the currently playing song, freeing the associated |
resources. |
--- |
Remarks: |
--- |
Does nothing if no song is playing at the time the call is made. |
*/ |
void __cdecl uFMOD_StopSong(); |
/* unsigned char* _uFMOD_GetTitle(void) |
--- |
Description: |
--- |
Returns the current song's title. |
--- |
Remarks: |
--- |
Not every song has a title, so be prepared to get an empty string. |
*/ |
unsigned char* __cdecl uFMOD_GetTitle(); |
#ifdef __cplusplus |
} |
#endif |
/programs/develop/libraries/ufmod/ufmod.asm |
---|
0,0 → 1,1104 |
; UFMOD.ASM |
; --------- |
; uFMOD public source code release. Provided as-is. |
SOUND_VERSION equ 100h ; required Infinity sound driver version |
FSOUND_Block equ 10 |
FSOUND_BlockSize equ 1024 ; 1 << FSOUND_Block |
if DEBUG |
; Debug messages: |
sDBGMSG1 db "uFMOD: XM track loaded",13,10,0 |
sDBGMSG2 db "uFMOD: Infinity driver loaded",13,10,0 |
sDBGMSG3 db "uFMOD: Buffer created",13,10,0 |
sDBGMSG4 db "uFMOD: Sound buffer destroyed",13,10,0 |
sDBGMSG5 db "uFMOD: Infinity version: ",0 |
; DEBUG board: print a string. |
DBG_print_s: |
; EDX = msg (trailing 0 is required!) |
pushad |
DBG_print_s_loop: |
mov eax,63 |
mov ebx,1 |
mov cl,[edx] |
test cl,cl |
jz DBG_print_s_R |
int 40h |
inc edx |
jmp DBG_print_s_loop |
DBG_print_s_R: |
popad |
ret |
; DEBUG board: print the hex value in EAX. |
DBG_print_x: |
; EAX = val |
pushad |
mov esi,eax |
mov edx,OFFSET MixBuf |
mov ecx,7 |
mov DWORD PTR [edx+8],0A0Dh |
print_eax_loop: |
mov eax,esi |
and al,0Fh |
cmp al,10 |
sbb al,69h |
das |
mov [edx+ecx],al |
shr esi,4 |
dec ecx |
jns print_eax_loop |
call DBG_print_s |
popad |
ret |
endif ; DEBUG |
if RAMP_STRONG |
volumerampsteps equ 128 |
volumeramps_pow equ 7 |
endif |
if RAMP_WEAK |
volumerampsteps equ 16 |
volumeramps_pow equ 4 |
endif |
if RAMP_NONE |
volumerampsteps equ 64 |
volumeramps_pow equ 6 |
endif |
XM_MEMORY equ 1 |
XM_FILE equ 2 |
XM_NOLOOP equ 8 |
XM_SUSPENDED equ 16 |
FMUSIC_ENVELOPE_SUSTAIN equ 2 |
FMUSIC_ENVELOPE_LOOP equ 4 |
FMUSIC_FREQ equ 1 |
FMUSIC_VOLUME equ 2 |
FMUSIC_PAN equ 4 |
FMUSIC_TRIGGER equ 8 |
FMUSIC_VOLUME_OR_FREQ equ 3 |
FMUSIC_VOLUME_OR_PAN equ 6 |
FMUSIC_VOL_OR_FREQ_OR_TR equ 11 |
FMUSIC_FREQ_OR_TRIGGER equ 9 |
NOT_FMUSIC_TRIGGER equ 0F7h |
NOT_FMUSIC_TRIGGER_OR_FRQ equ 0F6h |
; FMUSIC_XMCOMMANDS enum: |
FMUSIC_XM_PORTAUP equ 1 |
FMUSIC_XM_PORTADOWN equ 2 |
FMUSIC_XM_PORTATO equ 3 |
FMUSIC_XM_VIBRATO equ 4 |
FMUSIC_XM_PORTATOVOLSLIDE equ 5 |
FMUSIC_XM_VIBRATOVOLSLIDE equ 6 |
FMUSIC_XM_TREMOLO equ 7 |
FMUSIC_XM_SETPANPOSITION equ 8 |
FMUSIC_XM_SETSAMPLEOFFSET equ 9 |
FMUSIC_XM_VOLUMESLIDE equ 10 |
FMUSIC_XM_PATTERNJUMP equ 11 |
FMUSIC_XM_SETVOLUME equ 12 |
FMUSIC_XM_PATTERNBREAK equ 13 |
FMUSIC_XM_SPECIAL equ 14 |
FMUSIC_XM_SETSPEED equ 15 |
FMUSIC_XM_SETGLOBALVOLUME equ 16 |
FMUSIC_XM_GLOBALVOLSLIDE equ 17 |
FMUSIC_XM_KEYOFF equ 20 |
FMUSIC_XM_PANSLIDE equ 25 |
FMUSIC_XM_MULTIRETRIG equ 27 |
FMUSIC_XM_TREMOR equ 29 |
FMUSIC_XM_EXTRAFINEPORTA equ 33 |
; FMUSIC_XMCOMMANDSSPECIAL enum: |
FMUSIC_XM_FINEPORTAUP equ 1 |
FMUSIC_XM_FINEPORTADOWN equ 2 |
FMUSIC_XM_SETGLISSANDO equ 3 |
FMUSIC_XM_SETVIBRATOWAVE equ 4 |
FMUSIC_XM_SETFINETUNE equ 5 |
FMUSIC_XM_PATTERNLOOP equ 6 |
FMUSIC_XM_SETTREMOLOWAVE equ 7 |
FMUSIC_XM_SETPANPOSITION16 equ 8 |
FMUSIC_XM_RETRIG equ 9 |
FMUSIC_XM_NOTECUT equ 12 |
FMUSIC_XM_NOTEDELAY equ 13 |
FMUSIC_XM_PATTERNDELAY equ 14 |
if AC97SND_ON |
file_read: |
; buf in EAX |
; size in EDX |
push ebx |
push esi |
push edi |
push ebp |
xchg eax,edi |
file_read_begin: |
test edx,edx |
jg file_read_chk_cache |
file_read_done: |
pop ebp |
pop edi |
pop esi |
pop ebx |
ret |
; *** CHECK IN THE CACHE |
file_read_chk_cache: |
mov ebp,OFFSET file_struct |
mov esi,[ebp-24] |
sub esi,[ebp+28] ; cache_offset |
js file_read_cache_done |
mov ecx,8192 |
sub ecx,esi |
jle file_read_cache_done |
add esi,OFFSET MixBuf |
sub edx,ecx |
jns file_read_do_cache |
add ecx,edx |
file_read_do_cache: |
add [ebp-24],ecx |
rep movsb |
test edx,edx |
jle file_read_done ; data read from the cache (no need to access the FS) |
file_read_cache_done: |
; *** FS BATCH READ OPERATION |
mov eax,[ebp-24] |
mov ecx,edx |
add ecx,eax |
and ecx,0FFFFE000h |
sub ecx,eax |
jle file_read_fs_done ; Too few data requested for a FS batch operation |
sub edx,ecx |
mov [ebp+4],eax ; file offset |
mov [ebp+12],ecx ; NumberOfBytesToRead |
mov [ebp+16],edi ; lpBuffer |
mov ebx,ebp |
add edi,ecx |
push 70 |
add [ebp-24],ecx |
pop eax |
int 40h |
file_read_fs_done: |
; *** UPDATE THE CACHE |
mov ecx,[ebp-24] |
and ecx,0FFFFE000h |
mov [ebp+4],ecx ; file offset |
mov [ebp+28],ecx ; cache_offset |
mov DWORD PTR [ebp+12],8192 ; NumberOfBytesToRead |
mov DWORD PTR [ebp+16],OFFSET MixBuf ; lpBuffer |
mov ebx,ebp |
push 70 |
pop eax |
int 40h |
jmp file_read_begin |
if INFO_API_ON |
PUBLIC _uFMOD_GetTitle |
_uFMOD_GetTitle: |
mov eax,OFFSET szTtl |
ret |
endif |
else |
uFMOD_mem dd mem_open, mem_read |
if XM_FILE_ON |
uFMOD_fs dd file_open, file_read |
endif |
szInfinity db "INFINITY",0 |
if JUMP_TO_PAT_ON |
; Jump to the given pattern |
PUBLIC _uFMOD_Jump2Pattern |
_uFMOD_Jump2Pattern: |
mov eax,[esp+4] |
mov ecx,OFFSET _mod+36 |
movzx eax,ax |
and DWORD PTR [ecx+FMUSIC_MODULE.nextrow-36],0 |
cmp ax,[ecx+FMUSIC_MODULE.numorders-36] |
sbb edx,edx |
and eax,edx |
mov [ecx+FMUSIC_MODULE.nextorder-36],eax |
ret |
endif |
if VOL_CONTROL_ON |
; Set global volume [0: silence, 25: max. volume] |
vol_scale dw 1 ; -45 dB |
dw 130 ; -24 |
dw 164 ; -23 |
dw 207 ; -22 |
dw 260 ; -21 |
dw 328 ; -20 |
dw 413 ; -19 |
dw 519 ; -18 |
dw 654 ; -17 |
dw 823 ; -16 |
dw 1036 ; -15 |
dw 1305 ; -14 |
dw 1642 ; -13 |
dw 2068 ; -12 |
dw 2603 ; -11 |
dw 3277 ; -10 |
dw 4125 ; -9 |
dw 5193 ; -8 |
dw 6538 ; -7 |
dw 8231 ; -6 |
dw 10362 ; -5 |
dw 13045 ; -4 |
dw 16423 ; -3 |
dw 20675 ; -2 |
dw 26029 ; -1 |
dw 32768 ; 0 dB |
PUBLIC _uFMOD_SetVolume |
_uFMOD_SetVolume: |
mov eax,[esp+4] |
cmp eax,25 |
jna get_vol_scale |
push 25 |
pop eax |
get_vol_scale: |
mov ax,[vol_scale+eax*2] |
mov [ufmod_vol],eax |
ret |
endif |
if PAUSE_RESUME_ON |
; Pause the currently playing song. |
PUBLIC _uFMOD_Pause |
_uFMOD_Pause: |
mov al,1 |
jmp $+4 |
; Resume the currently paused song. |
PUBLIC _uFMOD_Resume |
_uFMOD_Resume: |
xor eax,eax |
mov BYTE PTR [ufmod_pause_],al |
ret |
endif |
if INFO_API_ON |
; Return currently playing signal stats: |
; lo word : RMS volume in R channel |
; hi word : RMS volume in L channel |
PUBLIC _uFMOD_GetStats |
_uFMOD_GetStats: |
push 4 |
jmp _uFMOD_InfoApi |
; Return currently playing row and order: |
; lo word : row |
; hi word : order |
PUBLIC _uFMOD_GetRowOrder |
_uFMOD_GetRowOrder: |
push 8 |
jmp _uFMOD_InfoApi |
; Return the time in milliseconds since the song was started. |
PUBLIC _uFMOD_GetTime |
_uFMOD_GetTime: |
push 0 |
_uFMOD_InfoApi: |
pop edx |
mov eax,[time_ms+edx] |
ret |
endif |
; *********************** |
; * XM_MEMORY CALLBACKS * |
; *********************** |
mem_read: |
; buf in EAX |
; size in EDX |
push edi |
push esi |
xchg eax,edi ; buf |
mov esi,OFFSET mmf |
lodsd |
mov ecx,edx |
add edx,[esi] |
cmp edx,eax |
jl copy |
sub eax,[esi] |
xchg eax,ecx |
copy: |
test ecx,ecx |
jle mem_read_R |
lodsd |
add eax,[esi] |
mov [esi-4],edx |
mem_do_copy: |
mov dl,[eax] |
mov [edi],dl |
inc eax |
inc edi |
dec ecx |
jnz mem_do_copy |
mem_read_R: |
pop esi |
pop edi |
if INFO_API_ON |
PUBLIC _uFMOD_GetTitle |
_uFMOD_GetTitle: |
mov eax,OFFSET szTtl |
endif |
mem_open: |
ret |
; ********************* |
; * XM_FILE CALLBACKS * |
; ********************* |
if XM_FILE_ON |
file_open: |
; pszName in ESI |
; Prepare the FILE struct for subsecuent I/O: |
lea eax,[ebp+8] ; file_struct |
xor edx,edx |
mov [eax],edx ; +0 subfunction: 0 = read |
mov [eax+8],edx ; +8 Reserved |
; +12 NumberOfBytesToRead |
; +16 lpBuffer |
push -1 |
push 1 |
mov [eax+20],dl ; +20 db 0 |
mov [eax+21],esi ; +21 lpFileName |
pop DWORD PTR [eax+28] ; cache_offset |
pop DWORD PTR [eax-28] ; [mmf] = maximum size |
ret |
file_read: |
; buf in EAX |
; size in EDX |
push ebx |
push esi |
push edi |
push ebp |
xchg eax,edi |
file_read_begin: |
test edx,edx |
jg file_read_chk_cache |
file_read_done: |
pop ebp |
pop edi |
pop esi |
pop ebx |
ret |
; *** CHECK IN THE CACHE |
file_read_chk_cache: |
mov ebp,OFFSET file_struct |
mov esi,[ebp-24] |
sub esi,[ebp+28] ; cache_offset |
js file_read_cache_done |
mov ecx,8192 |
sub ecx,esi |
jle file_read_cache_done |
add esi,OFFSET MixBuf |
sub edx,ecx |
jns file_read_do_cache |
add ecx,edx |
file_read_do_cache: |
add [ebp-24],ecx |
rep movsb |
test edx,edx |
jle file_read_done ; data read from the cache (no need to access the FS) |
file_read_cache_done: |
; *** FS BATCH READ OPERATION |
mov eax,[ebp-24] |
mov ecx,edx |
add ecx,eax |
and ecx,0FFFFE000h |
sub ecx,eax |
jle file_read_fs_done ; Too few data requested for a FS batch operation |
sub edx,ecx |
mov [ebp+4],eax ; file offset |
mov [ebp+12],ecx ; NumberOfBytesToRead |
mov [ebp+16],edi ; lpBuffer |
mov ebx,ebp |
add edi,ecx |
push 70 |
add [ebp-24],ecx |
pop eax |
int 40h |
file_read_fs_done: |
; *** UPDATE THE CACHE |
mov ecx,[ebp-24] |
and ecx,0FFFFE000h |
mov [ebp+4],ecx ; file offset |
mov [ebp+28],ecx ; cache_offset |
mov DWORD PTR [ebp+12],8192 ; NumberOfBytesToRead |
mov DWORD PTR [ebp+16],OFFSET MixBuf ; lpBuffer |
mov ebx,ebp |
push 70 |
pop eax |
int 40h |
jmp file_read_begin |
endif |
endif ; AC97SND_ON = 0 |
uFMOD_lseek: |
; pos in EAX |
; org in ECX |
; !org in Z |
mov edx,OFFSET mmf+4 |
jz mem_ok |
add eax,[edx] |
mem_ok: |
test eax,eax |
js mem_seek_R |
cmp eax,[edx-4] |
ja mem_seek_R |
mov [edx],eax |
mem_seek_R: |
ret |
; Dynamic memory allocation |
alloc: |
; EAX: how many bytes to allocate |
add eax,3 |
and eax,-4 |
jle alloc_error2 |
mov ecx,OFFSET ufmod_heap |
alloc_lookup: |
cmp DWORD PTR [ecx],0 |
je do_alloc |
mov ecx,[ecx] |
cmp [ecx+4],eax |
jl alloc_lookup |
sub [ecx+4],eax |
mov eax,[ecx+4] |
lea eax,[eax+ecx+8] |
ret |
do_alloc: |
add eax,8 |
push ebx |
push edi |
mov ebx,eax |
add ebx,8191 |
neg eax |
and ebx,-8192 |
push ecx |
add eax,ebx |
xchg eax,edi |
push 12 |
push 68 |
mov ecx,ebx |
pop eax |
pop ebx |
int 40h |
; Test for error condition |
test eax,eax |
pop ebx |
mov edx,edi ; free space |
jz alloc_error1 |
mov [ebx],eax |
mov edi,eax |
lea eax,[eax+edx+8] |
mov [edi+4],edx |
pop edi |
pop ebx |
ret |
alloc_error1: |
pop edi |
pop ebx |
alloc_error2: |
xor eax,eax |
pop edx ; EIP |
pop ebx |
leave |
_alloc_R: |
ret |
; Starts playing a song. |
PUBLIC _uFMOD_LoadSong |
_uFMOD_LoadSong: |
; *** FREE PREVIOUS TRACK, IF ANY |
call _uFMOD_StopSong |
if AC97SND_ON |
mov ecx,[esp+4] |
push ebx |
push esi |
push edi |
push ebp |
mov ebp,OFFSET uFMOD_fopen |
; Prepare the FILE struct for subsecuent I/O: |
lea eax,[ebp+8] ; file_struct |
xor edx,edx |
mov [eax],edx ; +0 subfunction: 0 = read |
mov [eax+8],edx ; +8 Reserved |
; +12 NumberOfBytesToRead |
; +16 lpBuffer |
mov [eax+20],dl ; +20 db 0 |
mov [eax+21],ecx ; +21 lpFileName |
push -1 |
push 1 |
mov DWORD PTR [ebp+4],OFFSET file_read ; uFMOD_fread |
pop DWORD PTR [eax+28] ; cache_offset |
mov [eax-24],edx |
pop DWORD PTR [eax-28] ; [mmf] = maximum size |
else |
mov eax,[esp+8] ; param |
mov ecx,[esp+12] ; fdwSong |
mov edx,[esp+4] ; lpXM |
test edx,edx |
jz _alloc_R |
; *** SET I/O CALLBACKS |
push ebx |
push esi |
push edi |
push ebp |
mov ebp,OFFSET uFMOD_fopen |
mov [ebp-20],eax ; mmf |
xor eax,eax |
mov [ebp-16],eax ; mmf+4 |
test cl,XM_MEMORY |
mov esi,OFFSET uFMOD_mem |
if XM_FILE_ON |
jnz set_callbacks |
test cl,XM_FILE |
lea esi,[esi+(uFMOD_fs-uFMOD_mem)] |
endif |
jz goto_StopSong |
set_callbacks: |
if NOLOOP_ON |
test cl,XM_NOLOOP |
setnz [ebp-24] ; ufmod_noloop |
endif |
if PAUSE_RESUME_ON |
and cl,XM_SUSPENDED |
mov [ebp-23],cl ; ufmod_pause_ |
endif |
mov edi,ebp ; uFMOD_fopen |
movsd |
movsd |
mov esi,edx ; uFMOD_fopen:lpXM <= ESI |
if VOL_CONTROL_ON |
cmp [ebp-4],eax ; ufmod_vol |
jne play_vol_ok |
mov WORD PTR [ebp-4],32768 |
play_vol_ok: |
endif |
xor edi,edi |
; *** INIT THE INFINITY DRIVER |
lea eax,[edi+68] |
lea ebx,[edi+16] |
mov ecx,OFFSET szInfinity |
int 40h |
test eax,eax |
mov [hSound],eax |
jz goto_StopSong |
if DEBUG |
mov edx,OFFSET sDBGMSG2 |
call DBG_print_s |
endif |
; *** CHECK THE DRIVER VERSION |
push edi ; ver = 0 |
push esp ; &ver |
mov edx,esp |
push 4 ; .out_size |
push edx ; .output = &&ver |
push edi ; .inp_size |
push edi ; .input |
push edi ; .code = SRV_GETVERSION |
push eax ; .handle = [hSound] |
lea ebx,[edi+17] |
lea eax,[edi+68] |
mov ecx,esp |
int 40h |
add esp,28 |
pop eax ; ver |
if DEBUG |
mov edx,OFFSET sDBGMSG5 |
call DBG_print_s |
call DBG_print_x |
endif |
shr eax,16 |
cmp eax,SOUND_VERSION |
ja _uFMOD_StopSong+4 ; obsolete program version (Hint: try adjusting SOUND_VERSION!) |
; *** ALLOCATE A HEAP OBJECT |
lea eax,[edi+68] |
lea ebx,[edi+11] |
int 40h |
test eax,eax |
jz goto_StopSong |
; *** LOAD THE TRACK |
mov [ebp-12],esi ; mmf+8 <= pMem |
if XM_FILE_ON |
call DWORD PTR [ebp] ; uFMOD_fopen |
endif |
endif ; AC97SND_ON = 0 |
call LoadXM |
test eax,eax |
goto_StopSong: |
jz _uFMOD_StopSong+4 |
if DEBUG |
mov edx,OFFSET sDBGMSG1 |
call DBG_print_s |
endif |
if AC97SND_ON |
else |
xor edi,edi |
; *** CREATE THE PCM BUFFER |
push edi ; size (default is 64Kb) |
push PCM_format ; format: 16-bit / stereo / sampling rate |
mov edx,esp |
push OFFSET hBuff |
mov eax,esp |
push 4 ; .out_size |
push eax ; .output = &&hBuff |
push 8 ; .inp_size |
push edx ; .input |
push 1 ; .code = SND_CREATE_BUFF |
push DWORD PTR [hSound] ; .handle |
lea eax,[edi+68] |
lea ebx,[edi+17] |
mov ecx,esp |
int 40h |
pop esi ; <- hSound |
add esp,32 |
test eax,eax |
jnz _uFMOD_StopSong+4 ; buffer not created |
if DEBUG |
mov edx,OFFSET sDBGMSG3 |
call DBG_print_s |
endif |
xchg eax,esi ; return the driver handle |
endif ; AC97SND_ON = 0 |
; *** ENABLE PCM OUTPUT |
mov [SW_Exit],eax |
pop ebp |
pop edi |
pop esi |
pop ebx |
ret |
; Stop the currently playing song, if any, and free all resources allocated for that song. |
PUBLIC _uFMOD_StopSong |
_uFMOD_StopSong: |
push ebx |
push esi |
push edi |
push ebp |
; _uFMOD_StopSong+4 |
xor edi,edi |
mov ebp,OFFSET ufmod_heap |
; *** DISABLE PCM OUTPUT |
mov [ebp+16],edi ; SW_Exit |
if AC97SND_ON |
else |
; *** STOP AND DESTROY THE PCM BUFFER |
mov eax,[ebp+12] ; hBuff |
test eax,eax |
jz SND_buffer_free |
push eax ; buffer |
mov edx,esp |
push edi ; .out_size |
push edi ; .output |
push 4 ; .inp_size |
push edx ; .input |
push 11 ; .code = SND_STOP |
push DWORD PTR [ebp+8] ; .handle = [hSound] |
lea eax,[edi+68] |
lea ebx,[edi+17] |
mov ecx,esp |
int 40h |
mov DWORD PTR [esp+4],2 ; .code = SND_DESTROY_BUFF |
lea eax,[edi+68] |
int 40h |
add esp,28 |
if DEBUG |
mov edx,OFFSET sDBGMSG4 |
call DBG_print_s |
endif |
SND_buffer_free: |
mov [ebp+12],edi ; hBuff |
endif ; AC97SND_ON = 0 |
; *** FREE THE HEAP |
mov esi,[ebp] ; ufmod_heap |
heapfree: |
test esi,esi |
jz free_R |
mov ecx,esi |
mov esi,[esi] |
lea eax,[edi+68] |
lea ebx,[edi+13] |
int 40h |
jmp heapfree |
free_R: |
xor eax,eax |
if AC97SND_ON |
else |
if INFO_API_ON |
; *** CLEAR THE INFO API DATA |
lea ecx,[eax+4] |
mov edi,OFFSET time_ms |
rep stosd |
endif |
endif ; AC97SND_ON = 0 |
mov DWORD PTR [ebp],eax ; ufmod_heap |
pop ebp |
pop edi |
pop esi |
pop ebx |
ret |
PUBLIC _uFMOD_WaveOut |
_uFMOD_WaveOut: |
push edi |
push ebp |
xor edi,edi |
if AC97SND_ON |
; *** PCM OUTPUT ENABLED? |
cmp DWORD PTR [SW_Exit],edi |
lea eax,[edi+1] ; return error if output not enabled |
je _uFMOD_WaveOut_R |
; *** COMPUTE THE NUMBER OF FREE BLOCKS AVAILABLE |
lea ecx,[esp+12] ; &hBuff |
push edi ; space = 0 |
mov edx,esp |
push 4 ; .out_size |
push edx ; .output = &space |
push 4 ; .inp_size |
push ecx ; .input |
push 17 ; .code = SND_GETFREESPACE |
mov ecx,[ecx] |
push DWORD PTR [hSound] ; .handle |
mov [hBuff],ecx |
else |
mov ebp,OFFSET hSound |
; *** PCM OUTPUT ENABLED? |
cmp [ebp+8],edi ; SW_Exit |
lea eax,[edi+1] ; return error if output not enabled |
je _uFMOD_WaveOut_R |
; *** COMPUTE THE NUMBER OF FREE BLOCKS AVAILABLE |
push edi ; space = 0 |
mov edx,esp |
push 4 ; .out_size |
lea ecx,[ebp+4] ; &hBuff |
push edx ; .output = &space |
push 4 ; .inp_size |
push ecx ; .input |
push 17 ; .code = SND_GETFREESPACE |
push DWORD PTR [ebp] ; .handle = [hSound] |
endif ; AC97SND_ON = 0 |
lea ebx,[edi+17] |
lea eax,[edi+68] |
mov ecx,esp |
int 40h |
add esp,24 |
pop edi ; <- space |
shr edi,FSOUND_Block+2 ; / (FSOUND_BlockSize * 4) |
jz _uFMOD_WaveOut_R ; no free blocks available |
_uFMOD_WaveOut_loop: |
call uFMOD_do_WaveOut |
neg eax |
dec edi |
ja _uFMOD_WaveOut_loop |
_uFMOD_WaveOut_R: |
pop ebp |
pop edi |
ret |
uFMOD_do_WaveOut: |
mov ecx,FSOUND_BlockSize*2 |
push ebx |
push esi |
push edi |
mov edi,OFFSET MixBuf |
xor eax,eax |
push edi ; mixbuffer <= MixBuf |
push edi ; <- MixPtr |
; MIXBUFFER CLEAR |
mov esi,OFFSET _mod+36 |
rep stosd |
if AC97SND_ON |
else |
if PAUSE_RESUME_ON |
cmp [ufmod_pause_],al |
xchg eax,ebp |
jne do_swfill |
endif |
endif ; AC97SND_ON = 0 |
mov ebp,FSOUND_BlockSize |
; UPDATE MUSIC |
mov ebx,[esi+FMUSIC_MODULE.mixer_samplesleft-36] |
fill_loop_1: |
test ebx,ebx |
jnz mixedleft_nz |
; UPDATE XM EFFECTS |
cmp [esi+FMUSIC_MODULE.tick-36],ebx ; new note |
mov ecx,[esi+FMUSIC_MODULE.pattern-36] |
jne update_effects |
dec ebx |
; process any rows commands to set the next order/row |
mov edx,[esi+FMUSIC_MODULE.nextorder-36] |
mov eax,[esi+FMUSIC_MODULE.nextrow-36] |
mov [esi+FMUSIC_MODULE.nextorder-36],ebx |
test edx,edx |
mov [esi+FMUSIC_MODULE.nextrow-36],ebx |
jl fill_nextrow |
mov [esi+FMUSIC_MODULE.order-36],edx |
fill_nextrow: |
test eax,eax |
jl update_note |
mov [esi+FMUSIC_MODULE.row-36],eax |
update_note: |
; mod+36 : ESI |
call DoNote |
if ROWCOMMANDS_ON |
cmp DWORD PTR [esi+FMUSIC_MODULE.nextrow-36],-1 |
jne inc_tick |
endif |
mov eax,[esi+FMUSIC_MODULE.row-36] |
inc eax |
; if end of pattern |
; "if(mod->nextrow >= mod->pattern[mod->orderlist[mod->order]].rows)" |
cmp ax,[ebx] |
jl set_nextrow |
mov edx,[esi+FMUSIC_MODULE.order-36] |
movzx ecx,WORD PTR [esi+FMUSIC_MODULE.numorders-36] |
inc edx |
xor eax,eax |
cmp edx,ecx |
jl set_nextorder |
if AC97SND_ON |
else |
; We've reached the end of the order list. So, stop playing, unless looping is enabled. |
if NOLOOP_ON |
cmp [ufmod_noloop],al |
je set_restart |
pop eax ; skip MixPtr |
pop edx ; skip mixbuffer |
pop edi |
inc eax ; end of loop reached while XM_NOLOOP flag is enabled |
pop esi |
pop ebx |
ret |
set_restart: |
endif |
endif ; AC97SND_ON = 0 |
movzx edx,WORD PTR [esi+FMUSIC_MODULE.restart-36] |
cmp edx,ecx |
sbb ecx,ecx |
and edx,ecx |
set_nextorder: |
mov [esi+FMUSIC_MODULE.nextorder-36],edx |
set_nextrow: |
mov [esi+FMUSIC_MODULE.nextrow-36],eax |
jmp inc_tick |
update_effects: |
; mod+36 : ESI |
call DoEffs |
inc_tick: |
mov eax,[esi+FMUSIC_MODULE.speed-36] |
mov ebx,[esi+FMUSIC_MODULE.mixer_samplespertick-36] |
inc DWORD PTR [esi+FMUSIC_MODULE.tick-36] |
if PATTERNDELAY_ON |
add eax,[esi+FMUSIC_MODULE.patterndelay-36] |
endif |
cmp [esi+FMUSIC_MODULE.tick-36],eax |
jl mixedleft_nz |
if PATTERNDELAY_ON |
and DWORD PTR [esi+FMUSIC_MODULE.patterndelay-36],0 |
endif |
and DWORD PTR [esi+FMUSIC_MODULE.tick-36],0 |
mixedleft_nz: |
mov edi,ebp |
cmp ebx,edi |
jae fill_ramp |
mov edi,ebx |
fill_ramp: |
pop edx ; <- MixPtr |
sub ebp,edi |
lea eax,[edx+edi*8] |
push eax ; MixPtr += (SamplesToMix<<3) |
; tail : [arg0] |
; len : EDI |
; mixptr : EDX |
; _mod+36 : ESI |
call Ramp |
if AC97SND_ON |
else |
if INFO_API_ON |
lea eax,[edi+edi*4] |
cdq |
shl eax,2 |
mov ecx,FSOUND_MixRate/50 |
div ecx |
; time_ms += SamplesToMix*FSOUND_OOMixRate*1000 |
add [time_ms],eax |
endif |
endif ; AC97SND_ON = 0 |
sub ebx,edi ; MixedLeft -= SamplesToMix |
test ebp,ebp |
jnz fill_loop_1 |
mov [esi+FMUSIC_MODULE.mixer_samplesleft-36],ebx ; <= MixedLeft |
if AC97SND_ON |
else |
if INFO_API_ON |
mov ecx,[esi + FMUSIC_MODULE.row-36] |
or ecx,[esi + FMUSIC_MODULE.order-2-36] |
mov DWORD PTR [s_row],ecx |
endif |
endif ; AC97SND_ON = 0 |
do_swfill: |
; *** CLIP AND COPY BLOCK TO OUTPUT BUFFER |
pop eax ; skip MixPtr |
pop esi ; <- mixbuffer |
if AC97SND_ON |
else |
if INFO_API_ON |
; ebx : L channel RMS volume |
; ebp : R channel RMS volume |
xor ebx,ebx |
endif |
endif ; AC97SND_ON = 0 |
mov edi,esi |
mov ecx,FSOUND_BlockSize*2 |
align 4 |
fill_loop_2: |
lodsd |
if AC97SND_ON |
mov ebx,eax |
cdq |
xor eax,edx |
sub eax,edx |
mov ebp,255*volumerampsteps/2 |
xor edx,edx |
div ebp |
cmp edx,255*volumerampsteps/4 |
sbb eax,-1 |
cmp eax,8000h |
sbb edx,edx |
not edx |
or eax,edx |
sar ebx,31 |
and eax,7FFFh |
xor eax,ebx |
sub eax,ebx |
else |
if INFO_API_ON |
push edi |
cdq |
mov edi,eax |
push esi |
xor eax,edx |
mov esi,255*volumerampsteps/2 |
sub eax,edx |
xor edx,edx |
div esi |
cmp edx,255*volumerampsteps/4 |
pop esi |
sbb eax,-1 |
cmp eax,8000h |
sbb edx,edx |
not edx |
or eax,edx |
sar edi,31 |
and eax,7FFFh |
if VOL_CONTROL_ON |
mul DWORD PTR [ufmod_vol] |
shr eax,15 |
endif |
; sum. the L and R channel RMS volume |
ror ecx,1 |
sbb edx,edx |
and edx,eax |
add ebp,edx ; += |vol| |
rol ecx,1 |
sbb edx,edx |
not edx |
and edx,eax |
add ebx,edx ; += |vol| |
xor eax,edi |
sub eax,edi |
pop edi |
else |
mov ebx,eax |
cdq |
xor eax,edx |
sub eax,edx |
mov ebp,255*volumerampsteps/2 |
xor edx,edx |
div ebp |
cmp edx,255*volumerampsteps/4 |
sbb eax,-1 |
cmp eax,8000h |
sbb edx,edx |
not edx |
or eax,edx |
sar ebx,31 |
and eax,7FFFh |
if VOL_CONTROL_ON |
mul DWORD PTR [ufmod_vol] |
shr eax,15 |
endif |
xor eax,ebx |
sub eax,ebx |
endif |
endif ; AC97SND_ON = 0 |
dec ecx |
stosw |
jnz fill_loop_2 |
if AC97SND_ON |
else |
if INFO_API_ON |
shr ebp,FSOUND_Block ; R_vol / FSOUND_BlockSize |
shl ebx,16-FSOUND_Block ; (L_vol / FSOUND_BlockSize) << 16 |
mov bx,bp |
mov DWORD PTR [L_vol],ebx |
endif |
endif ; AC97SND_ON = 0 |
; *** DISPATCH DATA TO THE AC97 DRIVER |
push FSOUND_BlockSize*4 ; size |
push OFFSET MixBuf ; &src |
push DWORD PTR [hBuff] ; buffer |
mov edx,esp |
push ecx ; .out_size |
push ecx ; .output |
push 12 ; .inp_size |
push edx ; .input |
push 9 ; .code = SND_OUT |
push DWORD PTR [hSound] ; .handle |
lea eax,[ecx+68] |
lea ebx,[ecx+17] |
mov ecx,esp |
int 40h |
add esp,36 |
pop edi |
pop esi |
pop ebx |
ret |
/programs/develop/libraries/ufmod/ufmod.inc |
---|
0,0 → 1,253 |
; uFMOD API reference (NORMAL/UNSAFE mode) |
; ==================================================================== |
; NOTE: All functions follow the cdecl calling convention! |
; _uFMOD_LoadSong |
; _uFMOD_WaveOut |
; _uFMOD_StopSong |
; _uFMOD_Jump2Pattern |
; _uFMOD_Pause |
; _uFMOD_Resume |
; _uFMOD_GetStats |
; _uFMOD_GetRowOrder |
; _uFMOD_GetTime |
; _uFMOD_GetTitle |
; _uFMOD_SetVolume |
; ==================================================================== |
; HANDLE _uFMOD_LoadSong( |
; void *lpXM, |
; void *param, |
; int fdwSong |
; ) |
; --- |
; Description: |
; --- |
; Loads the given XM song and starts playing it as soon as you |
; call _uFMOD_WaveOut for the first time. Playback won't begin |
; if XM_SUSPENDED flag is specified. It will stop any currently |
; playing song before loading the new one. |
; --- |
; Parameters: |
; --- |
; lpXM |
; Specifies the song to load. If this parameter is 0, any |
; currently playing song is stopped. In such a case, function |
; does not return a meaningful value. fdwSong parameter |
; determines whether this value is interpreted as a filename |
; or as a pointer to an image of the song in memory. |
; param |
; If XM_MEMORY is specified, this parameter should be the size |
; of the image of the song in memory. |
; If XM_FILE is specified, this parameter is ignored. |
; fdwSong |
; Flags for playing the song. The following values are defined: |
; XM_FILE lpXM points to filename. param is ignored. |
; XM_MEMORY lpXM points to an image of a song in memory. |
; param is the image size. Once, _uFMOD_LoadSong |
; returns, it's safe to free/discard the memory |
; buffer. |
; XM_NOLOOP An XM track plays repeatedly by default. Specify |
; this flag to play it only once. |
; XM_SUSPENDED The XM track is loaded in a suspended state, |
; and will not play until the _uFMOD_Resume function |
; is called. This is useful for preloading a song |
; or testing an XM track for validity. |
; --- |
; Return Values: |
; --- |
; On success, returns the handle of the Infinity Sound driver. |
; Returns 0 on failure. |
; ==================================================================== |
; int _uFMOD_WaveOut(void) |
; --- |
; Description: |
; --- |
; Updates the internal playback buffer. |
; --- |
; Remarks: |
; --- |
; This function should be called from the same thread |
; _uFMOD_LoadSong was previously called. Playback doesn't actually |
; begin when calling _uFMOD_LoadSong, but when calling _uFMOD_WaveOut |
; after a successful _uFMOD_LoadSong call. Afterwards, you should |
; call _uFMOD_WaveOut repeatedly at least once every 250 ms to |
; prevent "buffer underruns". |
; _uFMOD_WaveOut is a non-blocking function. The accuracy of the |
; InfoAPI functions (_uFMOD_GetStats, _uFMOD_GetRowOrder and |
; _uFMOD_GetTime) depends on the periodicity of this function being |
; invoked. |
; --- |
; Return Values: |
; --- |
; Returns non zero on error. |
; ==================================================================== |
; void _uFMOD_StopSong(void) |
; --- |
; Description: |
; --- |
; Stops the currently playing song, freeing the associated |
; resources. |
; --- |
; Remarks: |
; --- |
; Does nothing if no song is playing at the time the call is made. |
; ==================================================================== |
; void _uFMOD_Jump2Pattern( |
; unsigned int pat |
; ) |
; --- |
; Description: |
; --- |
; Jumps to the specified pattern index. |
; --- |
; Parameters: |
; --- |
; pat |
; Next zero based pattern index. |
; --- |
; Remarks: |
; --- |
; uFMOD doesn't automatically perform Note Off effects before jumping |
; to the target pattern. In other words, the original pattern will |
; remain in the mixer until it fades out. You can use this feature to |
; your advantage. If you don't like it, just insert leading Note Off |
; commands in all patterns intended to be used as _uFMOD_Jump2Pattern |
; targets. |
; if the pattern index lays outside of the bounds of the pattern order |
; table, calling this function jumps to pattern 0, effectively |
; rewinding playback. |
; ==================================================================== |
; void _uFMOD_Pause(void) |
; --- |
; Description: |
; --- |
; Pauses the currently playing song, if any. |
; --- |
; Remarks: |
; --- |
; While paused you can still control the volume (_uFMOD_SetVolume) and |
; the pattern order (_uFMOD_Jump2Pattern). The RMS volume coefficients |
; (_uFMOD_GetStats) will go down to 0 and the progress tracker |
; (_uFMOD_GetTime) will "freeze" while the song is paused. |
; _uFMOD_Pause doesn't perform the request immediately. Instead, it |
; signals to pause when playback reaches next chunk of data. |
; This way, _uFMOD_Pause performs asynchronously and returns very fast. |
; It is not cumulative. So, calling _uFMOD_Pause many times in a row |
; has the same effect as calling it once. |
; You shouldn't stop calling _uFMOD_WaveOut while the song is paused! |
; ==================================================================== |
; void _uFMOD_Resume(void) |
; --- |
; Description: |
; --- |
; Resumes the currently paused song, if any. |
; --- |
; Remarks: |
; --- |
; _uFMOD_Resume doesn't perform the request immediately. Instead, it |
; signals to resume when _uFMOD_WaveOut is called again. _uFMOD_Resume |
; is not cumulative. So, calling it many times in a row has the same |
; effect as calling it once. |
; ==================================================================== |
; unsigned int _uFMOD_GetStats(void) |
; --- |
; Description: |
; --- |
; Returns the current RMS volume coefficients in (L)eft and (R)ight |
; channels. |
; low-order word: RMS volume in R channel |
; hi-order word: RMS volume in L channel |
; Range from 0 (silence) to $7FFF (maximum) on each channel. |
; --- |
; Remarks: |
; --- |
; This function is useful for updating a VU meter. It's recommended |
; to rescale the output to log10 (decibels or dB for short), because |
; human ears track volume changes in a dB scale. You may call |
; _uFMOD_GetStats() as often as you like, but take in mind that uFMOD |
; updates both channel RMS volumes at the same rate _uFMOD_WaveOut |
; function is called. In other words, you should call _uFMOD_WaveOut |
; more often to increase the accuracy of _uFMOD_GetStats. |
; ==================================================================== |
; unsigned int _uFMOD_GetRowOrder(void) |
; --- |
; Description: |
; --- |
; Returns the currently playing row and order. |
; low-order word: row |
; hi-order word: order |
; --- |
; Remarks: |
; --- |
; This function is useful for synchronization. uFMOD updates both |
; row and order values at the same rate _uFMOD_WaveOut function is |
; called. In other words, you should call _uFMOD_WaveOut more often |
; to increase the accuracy of _uFMOD_GetRowOrder. |
; ==================================================================== |
; unsigned int _uFMOD_GetTime(void) |
; --- |
; Description: |
; --- |
; Returns the time in milliseconds since the song was started. |
; --- |
; Remarks: |
; --- |
; This function is useful for synchronizing purposes. Multimedia |
; applications can use _uFMOD_GetTime to synchronize GFX to sound, |
; for example. An XM player can use this function to update a progress |
; meter. |
; ==================================================================== |
; unsigned char* _uFMOD_GetTitle(void) |
; --- |
; Description: |
; --- |
; Returns the current song's title. |
; --- |
; Remarks: |
; --- |
; Not every song has a title, so be prepared to get an empty string. |
; ==================================================================== |
; void _uFMOD_SetVolume( |
; unsigned int vol |
; ) |
; --- |
; Description: |
; --- |
; Sets the global volume. The volume scale is linear. |
; --- |
; Parameters: |
; --- |
; vol |
; New volume. Range: from uFMOD_MIN_VOL (muting) to uFMOD_MAX_VOL |
; (maximum volume). Any value above uFMOD_MAX_VOL maps to maximum |
; volume. |
; --- |
; Remarks: |
; --- |
; uFMOD internally converts the given values to a logarithmic scale (dB). |
; Maximum volume is set by default. The volume value is preserved across |
; _uFMOD_LoadSong calls. You can set the desired volume level before |
; actually starting to play a song. |
; You can use Infinity Sound API to control the L and R channels volumes |
; separately. It also has a wider range than _uFMOD_SetVolume, sometimes |
; allowing to amplify the sound volume as well, as opposed to |
; _uFMOD_SetVolume only being able to attenuate it. |
XM_MEMORY equ 1 |
XM_FILE equ 2 |
XM_NOLOOP equ 8 |
XM_SUSPENDED equ 16 |
uFMOD_MIN_VOL equ 0 |
uFMOD_MAX_VOL equ 25 |
uFMOD_DEFAULT_VOL equ 25 |
/programs/develop/libraries/ufmod/. |
---|
Property changes: |
Added: tsvn:logminsize |
+5 |
\ No newline at end of property |