Hello!
.LET_CODE_BEGIN:
; ###############################################
; .LET_MACROS_BEGIN:
; [!!!] Define some NASM macros [!!!]
; ###############################################
; Macro: cextern
; + example provided
; -------------------------------------------------------------------
%macro cextern 1 ; cextern printf
extern _%1 ; extern _printf
%ifndef %1 ; %ifndef printf
%define %1 _%1 ; %define printf _printf
%endif ; %endif
%endmacro ; %endmacro
; Macro: cglobal
; + example provided
; -------------------------------------------------------------------
%macro cglobal 1 ; cglobal main
global _%1 ; global _main
%ifndef %1 ; %ifndef main
%define %1 _%1 ; %define main _main
%endif ; %endif
%endmacro ; %endmacro
; Macro: cexternList
; -------------------------------------------------------------------
%macro cexternList 1-*
%rep %0
cextern %1
%rotate 1
%endrep
%endmacro
; Macro: invoke
; This macro will call a cdecl procedure and clean up stack
; Param NR.1 is the function name
; Rest of params could be function, at param NR.1, params
; -------------------------------------------------------------------
%macro invoke 1-*
%assign max %0-1
%if %0 > 1
%rotate max
%rep max
push dword %1
%rotate -1
%endrep
%endif
call %1
add esp,dword max * 4
%endmacro
; Macro: invoke_error
; This macro used in conjunction with macro invoke
; It compares eax at param NR.2
; It takes jump type at param NR.1
; It jumps at location at param NR.3
; -------------------------------------------------------------------
%macro invoke_error 3
cmp eax,dword %2
%1 %3
%endmacro
; Macro: invoke_returns_at
; This macro used in conjunction with macro invoke
; It moves value of eax into param NR.1
; -------------------------------------------------------------------
%macro invoke_returns_at 1
mov dword %1, eax
%endmacro
; ###############################################
; .LET_CODE_BEGIN:
; Simple DirectMedia Layer 2: AUDIO
; ###############################################
; # Tell compiler what cpu type to use
cpu 386
; # Tell compiler to generate 32 bit code
bits 32
; # Use our predefined macro, define functions
; SDL functions
cexternList SDL_Init, \
SDL_GetError, \
SDL_Quit, \
SDL_RWFromFile, \
SDL_LoadWAV_RW, \
SDL_FreeWAV, \
SDL_OpenAudioDevice, \
SDL_PauseAudioDevice, \
SDL_Delay, \
SDL_CloseAudioDevice, \
SDL_memset, \
SDL_memcpy
; C functions
cexternList printf, \
atexit, \
; C global def's
cglobal main
; # Define some constants
; SDL Constants ----------------------------------------------------------------------
SDL_AUDIO_ALLOW_FREQUENCY_CHANGE equ 0x00000001
SDL_AUDIO_ALLOW_FORMAT_CHANGE equ 0x00000002
SDL_AUDIO_ALLOW_CHANNELS_CHANGE equ 0x00000004
SDL_AUDIO_ALLOW_ANY_CHANGE equ SDL_AUDIO_ALLOW_CHANNELS_CHANGE \
+ SDL_AUDIO_ALLOW_FORMAT_CHANGE \
+ SDL_AUDIO_ALLOW_FREQUENCY_CHANGE
SDL_INIT_TIMER equ 0x00000001
SDL_INIT_AUDIO equ 0x00000010
SDL_INIT_VIDEO equ 0x00000020
SDL_INIT_JOYSTICK equ 0x00000200
SDL_INIT_HAPTIC equ 0x00001000
SDL_INIT_GAMECONTROLLER equ 0x00002000
SDL_INIT_EVENTS equ 0x00004000
SDL_INIT_NOPARACHUTE equ 0x00100000
SDL_INIT_EVERYTHING equ SDL_INIT_TIMER \
+ SDL_INIT_AUDIO \
+ SDL_INIT_VIDEO \
+ SDL_INIT_EVENTS \
+ SDL_INIT_JOYSTICK \
+ SDL_INIT_HAPTIC \
+ SDL_INIT_GAMECONTROLLER
; SDL Structures ----------------------------------------------------------------------
; SDL_AudioSpec:
; A structure that contains the audio output format.
; It also contains a callback that is called when the audio device needs more data.
struc SDL_AudioSpec
.freq: resb 4
.format: resb 2
.channels: resb 1
.silence: resb 1
.samples: resb 2
.padding: resb 2
.size: resb 4
.callback: resb 4
.userdata: resb 4
endstruc
; SDL_AUDIO_USER_DATA:
; User defined structure, i design it, on my own.
struc SDL_AUDIO_USER_DATA
.wav_audio_buf: resb 4
.wav_audio_len: resb 4
.played_len: resb 4
.done: resb 4
endstruc
;# Data segment
; ---------------------------------------------------------------
segment .data use32
; Textual data:
txt_error_format db 13,"SDL Error: %s",13,0
; Wav file name: (http://www.wavsource.com)
txt_wav_name db "this_is_the_end_x.wav",0
; Info messages:
txt_play_start db 10,"Info: Playback started...",0
txt_playing db 10,"Info: Playing...",0
txt_play_end db 10,"Info: Playback en dead...",0
; Data used by SDL_LoadWav:
wav_audio_spec:
istruc SDL_AudioSpec
iend
wav_audio_buf: dd 0
wav_audio_len: dd 0
; Data used by SDL_OpenAudioDevice:
got_audio_spec:
istruc SDL_AudioSpec
iend
audio_device_id: dd 0
audio_user_data:
istruc SDL_AUDIO_USER_DATA
iend
;# Code segment
; ---------------------------------------------------------------
segment .text use32
; ###############################################
;
; main: Entry point, the magical place where code begins.
;
; ###############################################
main:
push ebp
mov ebp,esp
; SDL_Init:
; Use this function to initialize the SDL library.
; This must be called before using any other SDL function.
; ---------------------------------------------------------
invoke SDL_Init, SDL_INIT_AUDIO
invoke_error jne,0,main.quitError
; atexit:
; Set function to be executed on exit
; ---------------------------------------------------------
; SDL_Quit:
; Use this function to clean up all initialized subsystems.
; You should call it upon all exit conditions.
; ---------------------------------------------------------
invoke atexit, SDL_Quit
; SDL_LoadWAV:
; Use this function to load a WAVE from a file.
; * Warning: be aware, that value returned into wav_audio_buf is a pointer to pointer.
; ---------------------------------------------------------
invoke SDL_LoadWAV,txt_wav_name,wav_audio_spec,wav_audio_buf,wav_audio_len
invoke_error je,0,main.quitError
; Wav file SDL_AudioSpec obtained, update callback and user data:
; ---------------------------------------------------------
mov dword [wav_audio_spec+SDL_AudioSpec.callback],SDL_AudioCallback
mov dword [wav_audio_spec+SDL_AudioSpec.userdata],audio_user_data
; Fill audio user data: SDL_AUDIO_USER_DATA
; ---------------------------------------------------------
mov eax,dword [wav_audio_buf]
mov dword [audio_user_data+SDL_AUDIO_USER_DATA.wav_audio_buf],eax
mov eax,dword [wav_audio_len]
mov dword [audio_user_data+SDL_AUDIO_USER_DATA.wav_audio_len],eax
mov dword [audio_user_data+SDL_AUDIO_USER_DATA.played_len],0
mov dword [audio_user_data+SDL_AUDIO_USER_DATA.done],0
; SDL_OpenAudioDevice:
; Use this function to open a specific audio device.
; ---------------------------------------------------------
invoke SDL_OpenAudioDevice, \
0, \
0, \
wav_audio_spec, \
got_audio_spec, \
SDL_AUDIO_ALLOW_FORMAT_CHANGE
invoke_error je,0,main.quitError
invoke_returns_at [audio_device_id]
; SDL_PauseAudioDevice:
; (Start playback, pause = 0)
; Use this function to pause and unpause audio playback on a specified device.
; ---------------------------------------------------------
invoke SDL_PauseAudioDevice,[audio_device_id],0
; Display info: Playback started
; ---------------------------------------------------
pushad
invoke printf,txt_play_start
popad
.mainLoop:
; SDL_Delay:
; Use this function to wait a specified number of milliseconds before returning.
; ---------------------------------------------------------
invoke SDL_Delay,100
; Is playback done: ?
; ---------------------------------------------------
mov eax,dword audio_user_data
cmp dword [eax + SDL_AUDIO_USER_DATA.done],1
jne .mainLoop
; Display info: Playback ended
; ---------------------------------------------------
pushad
invoke printf,txt_play_end
popad
; SDL_PauseAudioDevice:
; (Stop playback, pause = 1)
; Use this function to pause and unpause audio playback on a specified device.
; ---------------------------------------------------------
invoke SDL_PauseAudioDevice,[audio_device_id],1
; SDL_CloseAudioDevice:
; Use this function to shut down audio processing and close the audio device.
; ---------------------------------------------------------
invoke SDL_CloseAudioDevice,[audio_device_id]
; SDL_FreeWAV:
; Use this function to free data
; previously allocated with SDL_LoadWAV() or SDL_LoadWAV_RW().
; ---------------------------------------------------------
invoke SDL_FreeWAV,wav_audio_buf
; Quit normal:
; ---------------------------------------------------------
mov eax,dword 0
pop ebp
ret
; Quit Error:
; ---------------------------------------------------------
main.quitError:
; SDL_GetError:
; Use this function to retrieve a message about the last error that occurred.
; ---------------------------------------------------
invoke SDL_GetError
; Print error information:
; ---------------------------------------------------
invoke printf,txt_error_format,eax
mov eax,dword 0
pop ebp
ret
; ###############################################
;
; SDL_LoadWAV: Directly nonexistant function.
; Sub calls: SDL_RWFromFile, SDL_LoadWAV_RW.
;
; ###############################################
SDL_LoadWAV:
push ebp
mov ebp,esp
; ---------------------------------------------------------
%define ebp_file ebp+8
%define ebp_spec ebp+12
%define ebp_audio_buf ebp+16
%define ebp_audio_len ebp+20
; ---------------------------------------------------------
; Jump over small data area, there:
jmp SDL_LoadWAV.theCode
; ---------------------------------------------------------
; Small data area,here:
SDL_LoadWAV.fileaccess: db "rb",0
; ---------------------------------------------------------
SDL_LoadWAV.theCode:
; ---------------------------------------------------------
; # SDL_LoadWAV: ---------------------------------------
; SDL_RWFromFile:
; Use this function to create a new SDL_RWops structure
; for reading from and/or writing to a named file.
; ---------------------------------------------------
invoke SDL_RWFromFile,[ebp_file],SDL_LoadWAV.fileaccess
invoke_error jne,0,SDL_LoadWAV.SDL_RWFromFile_Success
; Quit error:
; ---------------------------------------------------
mov eax,dword 0
pop ebp
ret
; ---------------------------------------------------------
SDL_LoadWAV.SDL_RWFromFile_Success:
; SDL_LoadWAV_RW:
; Use this function to load a WAVE from the data source,
; automatically freeing that source if freesrc is non-zero.
; ---------------------------------------------------
invoke SDL_LoadWAV_RW,eax,1, [ebp_spec], [ebp_audio_buf], [ebp_audio_len]
invoke_error jne,0,SDL_LoadWAV.SDL_LoadWAV_RW_Success
; Quit error:
; ---------------------------------------------------
mov eax,dword 0
pop ebp
ret
; ---------------------------------------------------------
SDL_LoadWAV.SDL_LoadWAV_RW_Success:
; ---------------------------------------------------------
pop ebp
ret
; ###############################################
;
; SDL_AudioCallback: Audio callback.
;
; ###############################################
SDL_AudioCallback:
push ebp
mov ebp,esp
; ---------------------------------------------------------
%define ebp_userdata ebp+8
%define ebp_peestream ebp+12
%define ebp_len ebp+16
; ---------------------------------------------------------
; user data:
; ---------------------------------------------------------
; [ebp_userdata] + SDL_AUDIO_USER_DATA.wav_audio_buf
; [ebp_userdata] + SDL_AUDIO_USER_DATA.wav_audio_len
; [ebp_userdata] + SDL_AUDIO_USER_DATA.played_len
; [ebp_userdata] + SDL_AUDIO_USER_DATA.done
; ---------------------------------------------------------
; On entry, do init all stream with silence:
; ---------------------------------------------------------
invoke SDL_memset,[ebp_peestream],0,[ebp_len]
; Address of user data, goes into: EAX
; ---------------------------------------------------------
mov eax,dword [ebp_userdata]
; Already played: ?
; ---------------------------------------------------------
cmp dword [eax+ SDL_AUDIO_USER_DATA.done],1
jne SDL_AudioCallback.continuePlay
; Yes: Already played, quit:
; ---------------------------------------------------------
pop ebp
ret
; No: Still playing, continue:
; ---------------------------------------------------------
SDL_AudioCallback.continuePlay:
; Display info:
pushad
invoke printf,txt_playing
popad
; Setup initial values of EBX, ECX:
; ---------------------------------------------------------
mov ebx,dword [eax+SDL_AUDIO_USER_DATA.wav_audio_buf]
mov ecx,dword [eax+SDL_AUDIO_USER_DATA.played_len]
; Audio buffer data pointer, goes into: EBX
; ---------------------------------------------------------
add ebx,ecx
; played_len + len, goes into: ECX
; ---------------------------------------------------------
add ecx,dword [ebp_len]
; Determine if (played_len + len) exceeds wav_audio_len
; ---------------------------------------------------------
cmp ecx,dword [eax +SDL_AUDIO_USER_DATA.wav_audio_len]
jg SDL_AudioCallback.onExceeds
; ---------------------------------------------------
; played_len + len < wav_audio_len
; ---------------------------------------------------
; Update value of SDL_AUDIO_USER_DATA.played_len
; ---------------------------------------------------
mov edx,eax
add edx,SDL_AUDIO_USER_DATA.played_len
mov [edx],ecx
; Fill stream with data,
; params: EBX(address), [ebp_len] is actual len
; ---------------------------------------------------
invoke SDL_memcpy,[ebp_peestream],ebx,[ebp_len]
pop ebp
ret
SDL_AudioCallback.onExceeds:
; ---------------------------------------------------
; played_len + len > wav_audio_len
; ---------------------------------------------------
; Reverse last aritmetic operation: ECX
sub ecx,dword [ebp_len]
; Obtain wav_audio_len into: EDX
mov edx,dword [eax +SDL_AUDIO_USER_DATA.wav_audio_len]
; wav_audio_len minus played_len: EDX
sub edx,ecx
; Fill stream: EBX(address), EDX(new len: wav_audio_len-played_len)
invoke SDL_memcpy,[ebp_peestream],ebx,edx
; Set: SDL_AUDIO_USER_DATA.done
; ---------------------------------------------------
mov eax,dword [ebp_userdata]
mov dword [eax + SDL_AUDIO_USER_DATA.done],1
; Set: SDL_AUDIO_USER_DATA.played_len
; ---------------------------------------------------
mov edx,dword [eax +SDL_AUDIO_USER_DATA.wav_audio_len]
mov dword [eax+SDL_AUDIO_USER_DATA.played_len],edx
; ---------------------------------------------------
pop ebp
ret
; ----
; END ---
; ----
There was a post limitation of 20k characters, so, split two was the result.
Bye!