{ ToDO Master volume how to do } unit BMMSound; interface uses Windows,mmsystem; type BTMMSound = class private aChannel : longint; aPlaying : boolean; aModule : pointer; aStream : pointer; aVolume : longword; aLoop : boolean; procedure SetVolume(value:longword); procedure SetLoop(value:boolean); public constructor Create(h_wnd:longword); destructor Destroy; override; procedure Play; procedure Stop; procedure Pause; procedure Resume; procedure LoadFromFile(File_Name:string); property Volume : longword read aVolume write SetVolume; property Loop : boolean read aLoop write SetLoop; property Playing : boolean read aPlaying; end; implementation /// procedure VolumeData; assembler; asm // VOLUME divider 16:16 dd 7FFF0000h // 0 Mute dd 00100000h // 1 15 dd 00078000h // 2 7.5 .5*65536/10 = 8000h dd 00050000h // 3 5 dd 0003C000h // 4 3.75 .75*65536/100 = C000h dd 00030000h // 5 3 dd 00028000h // 6 2.5 dd 000223D7h // 7 2.14 .14*65536/100 = 23D7h dd 0001E147h // 8 Half 1.88 .88 = E147 dd 0001AB85h // 9 1.67 .67 = AB85 dd 00018000h // 10 1.5 = 8000 dd 00015C28h // 11 1.36 .36 = 5C28 dd 00014000h // 12 1.25 = 4000 dd 00012666h // 13 1.15 .15 = 2666 dd 000111EBh // 14 1.07 .07 = 11EB dd 00010000h // 15 Max Sound 1 end; type Sound = record // +0 +4 +8 +12 +16 +20 +24 +28 +32 +36 +40 +44 +48 +52 winuse,wsnd,wlen,wofs,wkhz,wbps,wlop,wvol,wint,wsnd2,wcbm,wlpb,wlpe :dword; end; MODcallbackProc = procedure(wsnd,wlen:dword); stdcall; var block8 : boolean; // alocate first 8 channels for mod player wsound : array [1..16] of sound; wsoundfreq :dword; wsoundticks :dword; //44100 per seconds wsoundbackproc:procedure; stdcall; libFmodOpens :dword; procedure NopProc; stdcall; begin end; ////////////////////////////// /// MOD Player { sbMod v.0.1.2 (C)2K-1 by CARSTEN WAECHTER aka THE TOXIC AVENGER/AINC. http://www.uni-ulm.de/~s_cwaech/ All changes are listed below.. } CONST mod_max_ch =8; { MAX. MOD-CHANNELS } mod_max_vol=16; { MAX. MOD-VOLUME } // maxChannel =16; MaxVolume =63; //stStop = 1; //stOnce = 2; //stLoop = 3; TYPE mod_instrument = packed record name : array[0..21]of char; length : word; finetune: byte; def_vol : byte; loop_start : word; loop_length: word; end; mod_header = packed record song_name : array[0..19]of char; instrument : array[1..31]of mod_instrument; song_length: byte; ciaa_speed : byte; song_arrangement : array[0..127]of byte; modtype : array[0..3]of char; end; my_mod_note = record instrumentnr : byte; toneheight : word; effect : byte; op : byte; end; org_mod_note = packed record instrumentnr : byte; toneheight : byte; effect : byte; op : byte; end; VAR mod_num_pat, mod_num_ch : longint; { NUMBER OF MOD-PATTERNS/MOD-CHANNELS } mod_h : mod_header; mod_pat : array[0..63,0..63,1..mod_max_ch]of my_mod_note; { MAX. 64 PATTERNS … 64 LINES … MOD_MAX_CH CHANNELS } mod_sam : array[1..31]of pointer; { SAMPLE-DATA } mod_pat_row, mod_mom_pat, mod_arrangement_pos : longint; { PATTERNROW, PATTERN PLAYED RIGHT NOW, POSITION IN ARRANGEMENT } mod_BPM, mod_num_ticks, mod_ticks, mod_timercalls : longint; mod_master_vol :longint; mod_work : boolean; TimerFreq : longint; { TIMER FREQUENCY in Hz} CONST mod_notes : array[0..60]of word=($36,$39,$3C,$40,$43,$47,$4C,$55, $5A,$5F,$65,$6B,$71,$78,$7F,$87, $8F,$97,$A0,$AA,$B4,$BE,$CA,$D6, $E2,$F0,$FE,$10D,$11D,$12E,$140, $153,$168,$17D,$194,$1AC,$1C5,$1E0, $1FC,$21A,$23A,$25C,$280,$2A6,$2D0, $2FA,$328,$358,$386,$3C1,$3FA,$436, $477,$4BB,$503,$54F,$5A0,$5F5,$650, $6B0,$6B0); FixedPointShift = 16; SampleRate : Word = 44100; {22050;} {44100} // UpdateRate : Word = 50; VAR sbvolslide : array[1..mod_max_ch]of longint; sbportamento, sbportamentonote : array[1..mod_max_ch]of longint; sbtoneheight : array[1..mod_max_ch]of word; sbarpeggiopos, sbarpeggio0, sbarpeggio1, sbarpeggio2 : array[1..mod_max_ch]of longint; playing_mod_filename:string[32]; PROCEDURE SetChannelRate(chan : byte; rate : word); BEGIN wsound[chan].wkhz := ((3579364 div rate) shl FixedPointShift) div SampleRate; END; type // wary=array[0..0] of word; bary=array[0..0] of byte; PROCEDURE MOD2Mem(mod_name : string); stdcall; Var f : file of byte; bu:^bary; v,v2,v3 : longint; note : org_mod_note; pt,pt2 : pointer; w:longint; // b:byte; // st:string; BEGIN playing_mod_filename := mod_name; assign(f,mod_name); reset(f); blockread(f,mod_h,sizeof(mod_h)); for v:=1 to 31 do with mod_h do begin instrument[v].length:=swap(instrument[v].length)*2; instrument[v].loop_start:=swap(instrument[v].loop_start)*2; instrument[v].loop_length:=swap(instrument[v].loop_length)*2; if instrument[v].def_vol>MaxVolume then instrument[v].def_vol:=MaxVolume; end; { CONVERSION OF AMIGA-WORDS } if (mod_h.modtype='6CHN') then mod_num_ch:=6 else if (mod_h.modtype='8CHN') then mod_num_ch:=8 else if (mod_h.modtype='12CH') then mod_num_ch:=12 else if (mod_h.modtype='16CH') then mod_num_ch:=16 else mod_num_ch:=4; { NUMBER OF CHANNELS } mod_num_pat:=filesize(f)-sizeof(mod_h); for v:=1 to 31 do dec(mod_num_pat,mod_h.instrument[v].length); mod_num_pat:=mod_num_pat div (sizeof(org_mod_note)*64*mod_num_ch); { CALCULATE NUM. OF PATTERNS } getmem(pt,mod_num_pat*64*mod_num_ch*sizeof(org_mod_note)); { READ PATTERNS } blockread(f,pt^,mod_num_pat*64*mod_num_ch*sizeof(org_mod_note)); pt2:=pt; for v:=0 to mod_num_pat-1 do for v2:=0 to 63 do for v3:=1 to mod_num_ch do begin move(pt2^,note,sizeof(note)); // inc(pt2,sizeof(note)); pt2 := pointer(longword(pt2) + sizeof(note)); mod_pat[v,v2,v3].instrumentnr:=(note.instrumentnr and $F0) + (note.effect shr 4); mod_pat[v,v2,v3].toneheight:=((note.instrumentnr and $0F) shl 8) + note.toneheight; mod_pat[v,v2,v3].effect:=note.effect and $0F; mod_pat[v,v2,v3].op:=note.op; end; { CONVERSION OF DUMB NOTE-FORMAT TO USEFUL FORMAT } freemem(pt,mod_num_pat*64*mod_num_ch*sizeof(org_mod_note)); for v:=1 to 31 do if mod_h.instrument[v].length>0 then begin getmem(mod_sam[v],mod_h.instrument[v].length); blockread(f,mod_sam[v]^,mod_h.instrument[v].length); bu:=mod_sam[v]; for w:=1 to mod_h.instrument[v].length do begin bu^[w - 1]:=smallint(bu[w - 1]) + 128; end; end; { READ SAMPLES } close(f); { for v:=1 to 31 do if mod_h.instrument[v].length>0 then begin str(v,st); assign(f,st+'.raw'); rewrite(f,1); blockwrite(f,mod_sam[v]^,mod_h.instrument[v].length); close(f); end; }{ WRITE SAMPLES } END; PROCEDURE FreeMOD; stdcall; export; Var v : longint; BEGIN for v:=1 to 31 do if mod_h.instrument[v].length>0 then freemem(mod_sam[v],mod_h.instrument[v].length*2); END; FUNCTION GetNote(rate : word) : longint; { I DON'T KNOW IF THIS ONE IS ALRIGHT } Var v : longint; BEGIN if (rate<=mod_notes[0]) then begin getnote:=0; exit; end; if (rate>=mod_notes[59]) then begin getnote:=59; exit; end; for v:=0 to 59 do if (rate=mod_notes[v]) or (rate0) then begin { VOLUME SLIDE FX } inc(wvol,sbvolslide[ch]); if (wvol>mod_max_vol) then begin wvol:=mod_max_vol; sbvolslide[ch]:=0; end; end; if (sbvolslide[ch]<0) then begin if (longint(wvol)+sbvolslide[ch]<0) then begin wvol:=0; sbvolslide[ch]:=0; end else inc(wvol,sbvolslide[ch]); end; if (sbportamento[ch]<>0) then begin { PORTAMENTO FX } inc(sbtoneheight[ch],sbportamento[ch]); if (sbportamentonote[ch]>0) then begin if ((sbtoneheight[ch]sbportamentonote[ch]) and (sbportamento[ch]>0)) then begin sbtoneheight[ch]:=sbportamentonote[ch]; sbportamento[ch]:=0; end; end; if (sbtoneheight[ch]<$36) then begin sbtoneheight[ch]:=$36; sbportamento[ch]:=0; end; setchannelrate(ch,sbtoneheight[ch]); end; if (sbarpeggiopos[ch]>0) then begin { ARPEGGIO FX } inc(sbarpeggiopos[ch]); case (sbarpeggiopos[ch] mod 3) of 0 : setchannelrate(ch,sbarpeggio2[ch]); 1 : setchannelrate(ch,sbarpeggio0[ch]); 2 : setchannelrate(ch,sbarpeggio1[ch]); end; end; Wvol := (( Wvol shl 16 ) div MasterVol^[mod_master_vol] ) and $F; end; {with } end; { for } goto oncemore end; mod_ticks:=0; continue:=false; for ch:=1 to mod_num_ch do begin with mod_pat[mod_mom_pat,mod_pat_row,ch] do begin with wsound[ch] do begin if (toneheight>0) and (effect<>3) then begin { FREQUENCY CHANGED } setchannelrate(ch,toneheight); sbtoneheight[ch]:=toneheight; sbportamento[ch]:=0; sbarpeggiopos[ch]:=0; sbportamentonote[ch]:=0; end; if (instrumentnr>0) then begin { INSTRUMENT CHANGED } wsnd := dword(mod_sam[instrumentnr]); wlen := mod_h.instrument[instrumentnr].length; wbps := 8; {8bit simples } wvol := mod_h.instrument[instrumentnr].def_vol*mod_max_vol div MaxVolume; wofs := 0; wint := 0; if (mod_h.instrument[instrumentnr].loop_length=0) then begin wlop := 0; { LOOP ? } end else begin wlop := 1; { yes loop } wlpb :=mod_h.instrument[instrumentnr].loop_start; wlpe :=(mod_h.instrument[instrumentnr].loop_length+mod_h.instrument[instrumentnr].loop_start); end; sbportamento[ch]:=0; sbarpeggiopos[ch]:=0; sbportamentonote[ch]:=0; sbvolslide[ch]:=0; winuse := 1; end; case effect of 0 : if (op>0) then begin { ARPEGGIO .. DON'T KNOW IF THIS ONES ALRIGHT } sbarpeggiopos[ch]:=1; sbarpeggio0[ch]:=sbtoneheight[ch]; if sbarpeggio0[ch]<$36 then sbarpeggio0[ch]:=$36; if (getnote(sbtoneheight[ch])-longint(op shr 4)<0) then sbarpeggio1[ch]:=$36 else sbarpeggio1[ch]:=mod_notes[getnote(sbtoneheight[ch])-longint(op shr 4)]; if (getnote(sbtoneheight[ch])-longint(op and $0F)<0) then sbarpeggio2[ch]:=$36 else sbarpeggio2[ch]:=mod_notes[getnote(sbtoneheight[ch])-longint(op and $0F)]; end; 1 : sbportamento[ch]:=-op; { PORTAMENTO } 2 : sbportamento[ch]:=op; 3 : if (toneheight>0) then { PORTAMENTO TO NOTE } if (sbtoneheight[ch]=mod_h.song_length then mod_arrangement_pos:=0; mod_mom_pat:=mod_h.song_arrangement[mod_arrangement_pos]; continue:=true; end; 12 : wvol:=op*mod_max_vol div MaxVolume; { VOLUME CHANGE } 13 : begin { PATTERN BREAK } mod_pat_row:=op; inc(mod_arrangement_pos); if mod_arrangement_pos>=mod_h.song_length then mod_arrangement_pos:=0; mod_mom_pat:=mod_h.song_arrangement[mod_arrangement_pos]; continue:=true; end; 15 : if (op<=31) then mod_num_ticks:=op else mod_BPM:=op; { SET SPEED } 14 : case (op shr 4) of 1 : begin { FINE PORTAMENTO } dec(sbtoneheight[ch],op and $0F); if (sbtoneheight[ch]<$36) then sbtoneheight[ch]:=$36; setchannelrate(ch,sbtoneheight[ch]); end; 2 : begin inc(sbtoneheight[ch],op and $0F); setchannelrate(ch,sbtoneheight[ch]); end; 10 : begin { FINE VOLUME SLIDE } inc(wvol,op and $0F); if (wvol>mod_max_vol) then wvol:=mod_max_vol; end; 11 : if (longint(wvol)-longint(op and $0F)<0) then wvol:=0 else dec(wvol,op and $0F); end; { case } end; { case } Wvol := (( Wvol shl 16 ) div MasterVol^[mod_master_vol] ) and $F; end; { with wsounr } end; { with mod } end; { for } if continue = false then begin inc(mod_pat_row); if (mod_pat_row>63) then begin mod_pat_row:=0; inc(mod_arrangement_pos); if mod_arrangement_pos>=mod_h.song_length then mod_arrangement_pos:=0; mod_mom_pat:=mod_h.song_arrangement[mod_arrangement_pos]; end; end; goto oncemore END; PROCEDURE PlayMOD; stdcall; BEGIN block8 := true; mod_arrangement_pos:=0; mod_mom_pat:=mod_h.song_arrangement[0]; mod_pat_row:=0; mod_BPM:=125; mod_num_ticks:=6; mod_ticks:=0; mod_timercalls:=0; timerfreq := 150; wsoundfreq := 44100 div 150; mod_work := true; wsoundbackproc := @modt; // CreateTimer(150,@modt); {150 Hz timer } //timerproc:=modt; END; PROCEDURE StopMOD; stdcall; var i:integer; BEGIN mod_work := false; wsoundbackproc := @NopProc; block8 := false; for i:=1 to mod_num_ch do wsound[i].winuse := 0; END; PROCEDURE ResumeMOD; stdcall; BEGIN mod_work := true; END; PROCEDURE PauseMOD; stdcall; BEGIN mod_work := false; END; PROCEDURE SetMODvolume(v:dword); stdcall; BEGIN if V > 255 then V := 255; V := V div 16; mod_master_vol := V and $F; END; //if FLoop then //sndPlaySound(pchar(FSoundFile), snd_Async or snd_NoDefault or SND_LOOP)else //sndPlaySound(pchar(FSoundFile), snd_Async or snd_NoDefault ); (* //////////////////////////////////////////////////////////////////////////////// SOUND NOTES: SIGNED SOUND 16 bit ** | 32767 7FFFh * * | * * | * * | 1 0001h -*------*------*-+ 0 0000h * * |-1 FFFFh * * |-2 FFFEh * * | ** |-32768 8000h //////////////////////////////////////////////////////////////////////////////// *) Const REPLAY_RATE :longint = 44100; REPLAY_DEPTH :longint = 16; REPLAY_SAMPLELEN :longint = 2; { (REPLAY_DEPTH div 8); } REPLAY_NBSOUNDBUFFER :longint = 2; type USER_CALLBACK = procedure(a:pointer;b:dword); stdcall; // bpat = array [0..0] of byte; // wpat = array [0..0] of word; // dpat = array [0..0] of dword; var m_pUserCallback :USER_CALLBACK; m_bufferSize :longint; m_hWaveOut :HWAVEOUT; // m_hMidiOut :HMIDIOUT; m_currentBuffer :longint; m_waveHeader :array [1..2] of WAVEHDR; { the size of arrey is } m_pSoundBuffer :array [1..2] of pointer; { REPLAY_NBSOUNDBUFFER } m_bServerRunning :boolean; // mixBuf :array [0..24000] of dword; { for 500 mili sec } procedure fillNextBuffer; begin // check if the buffer is already prepared (should not !) if (m_waveHeader[m_currentBuffer].dwFlags and WHDR_PREPARED) <> 0 then waveOutUnprepareHeader(m_hWaveOut,@m_waveHeader[m_currentBuffer],sizeof(WAVEHDR)); // Call the user function to fill the buffer with anything you want ! :-) m_pUserCallback(m_pSoundBuffer[m_currentBuffer],m_bufferSize); // Prepare the buffer to be sent to the WaveOut API m_waveHeader[m_currentBuffer].lpData := m_pSoundBuffer[m_currentBuffer]; m_waveHeader[m_currentBuffer].dwBufferLength := m_bufferSize; waveOutPrepareHeader(m_hWaveOut,@m_waveHeader[m_currentBuffer],sizeof(WAVEHDR)); // Send the buffer the the WaveOut queue waveOutWrite(m_hWaveOut,@m_waveHeader[m_currentBuffer],sizeof(WAVEHDR)); inc(m_currentBuffer); if (m_currentBuffer > REPLAY_NBSOUNDBUFFER) then m_currentBuffer := 1; end; procedure waveOutProc(hwo:HWAVEOUT;uMsg,dwInstance,dwParam1,dwParam2:dword); stdcall; begin if (uMsg = WOM_DONE) then begin fillNextBuffer; end; end; function Wave_Open(pUserCallback:USER_CALLBACK;totalBufferedSoundLenInMiliSec:longint):boolean; stdcall; var wfx : TWAVEFORMATEX; errCode : MMRESULT; i : integer; p : pointer; begin m_pUserCallback := pUserCallback; m_bufferSize := ((totalBufferedSoundLenInMiliSec * REPLAY_RATE) div 1000) * REPLAY_SAMPLELEN; m_bufferSize := m_bufferSize div REPLAY_NBSOUNDBUFFER; wfx.wFormatTag := 1; // PCM standart. wfx.nChannels := 1; // Mono wfx.nSamplesPerSec := REPLAY_RATE; wfx.nAvgBytesPerSec := REPLAY_RATE*REPLAY_SAMPLELEN; wfx.nBlockAlign := REPLAY_SAMPLELEN; wfx.wBitsPerSample := REPLAY_DEPTH; wfx.cbSize := 0; errCode := waveOutOpen(@m_hWaveOut,WAVE_MAPPER,@wfx, DWORD(@waveOutProc), 0, // User data. DWORD(CALLBACK_FUNCTION)); if (errCode = MMSYSERR_NOERROR) then begin // Alloc the sample buffers. for i:=1 to REPLAY_NBSOUNDBUFFER do begin getmem(m_pSoundBuffer[i],m_bufferSize); p := m_pSoundBuffer[i]; asm push esi mov esi, p mov ecx, m_bufferSize shr ecx, 1 {; to words } mov ax, 0 @@_fill: mov ds:[esi], ax add esi, 2 loop @@_fill pop esi end; fillchar(m_waveHeader[i],sizeof(WAVEHDR),0); end; // Fill all the sound buffers m_currentBuffer := 1; for i:=1 to REPLAY_NBSOUNDBUFFER do begin fillNextBuffer; end; m_bServerRunning := TRUE; end else begin m_bServerRunning := FALSE; end; Wave_Open := m_bServerRunning; end; procedure Wave_Close; stdcall; export; var //i:integer; os:TOSVERSIONINFO; begin if libFmodOpens <> 0 then Exit; //Debug('Wave_CLOSE ----------------------------------'); if (m_bServerRunning) then begin os.dwOSVersionInfoSize := sizeof(TOSVERSIONINFO); GetVersionEx(os); if os.dwMajorVersion <= 4 then begin {use only if win95, win98, winMe } {not to use on 2000 XP .NET } {NT 3 and 4 is in teh use list I dont know what will be ..:( } waveOutReset(m_hWaveOut); // Reset tout. // for i:=1 to REPLAY_NBSOUNDBUFFER do // begin // // if (m_waveHeader[m_currentBuffer].dwFlags and WHDR_PREPARED) <> 0 then // waveOutUnprepareHeader(m_hWaveOut,@m_waveHeader[i],sizeof(WAVEHDR)); // // freeMem(m_pSoundBuffer[i],m_bufferSize); // // end; end; waveOutClose(m_hWaveOut); m_bServerRunning := FALSE; end; end; procedure wsoundcallback; stdcall; begin wsoundbackproc; end; procedure Sound_mixer(pSoundBuffer:pointer;bufferLen:dword); stdcall; var nbSample:dword; note:dword; divc:dword; Chan:dword; begin ASM push edi push esi push ebx mov edi, pSoundBuffer mov eax, bufferLen shr eax, 1 // dec eax mov nbSample, eax @@nexttofill: push edi mov ecx, 16 {; 16 chanals to mix } mov Chan, ecx lea esi, wsound xor eax, eax mov note , eax mov divc , eax @@chanals: test dword ptr ds:[esi], 1 {; in use } jz @@nochanal inc divc mov eax, ds:[esi+28] {;Wvol 0-15} cmp eax, 15 jbe @@normalvol mov eax, 0Fh @@normalvol: and eax, 0Fh lea ebx, VolumeData mov ecx, ds:[ebx+eax*4] xor eax, eax mov edx, eax mov ebx, ds:[esi+12] {;Wofs pattern position} mov edi, ds:[esi+4] {;Wsnd pointer to pattern } test dword ptr ds:[esi+20], 8 {;test fro 8 bit simple } jz @@use16bit mov al, ds:[edi + ebx] imul eax, 127 { note * 128 ??????????} jmp @@noteend @@use16bit: mov ax, ds:[edi + ebx*2] imul eax, 1 jmp @@noteend @@nochanal: xor eax, eax @@noteend: { make volume } xor edx, edx shl eax, 16 { aritmetic 16:16 } idiv ecx add note, eax { -32000 0 +32000 } mov eax, ds:[esi+32] {;wint} add eax, ds:[esi+16] {;Wint := Wint + Wkhz } mov ds:[esi+32], eax test eax, 0FFFF0000h jz @@notyet and eax, 0FFFFh mov ds:[esi+32], eax { wint := wint and $FFFF } inc ebx mov ds:[esi+12], ebx { store Wofs } cmp ebx, ds:[esi+8] { if Wofs = Wlen } jne @@noendpat mov dword ptr ds:[esi], 0 { stop in use } test dword ptr ds:[esi+24], 1 {;Wlop } jz @@noloop { ; have loop } mov ebx, ds:[esi+44] { loop start } mov ds:[esi+12], ebx { store Wofs } mov ebx, ds:[esi+48] { loop end } mov ds:[esi+8], ebx { store new end } mov dword ptr ds:[esi], 1 { in use agein } @@noloop: @@noendpat: @@notyet: add esi, 52 { to next in wsound } dec chan jnz @@chanals pop edi xor eax, eax mov ecx, divc or ecx, ecx jz @@zironote xor edx, edx mov eax, note idiv ecx // shr eax, 4 { div 16 } @@zironote: mov ds:[edi], ax add edi, 2 inc wSoundTicks dec wSoundFreq jnz @@NoCallBack call wsoundCallBack @@NoCallBack: dec nbSample jnz @@nexttofill pop ebx pop esi pop edi END; end; (* procedure Sound_mixer2(pSoundBuffer:pointer;bufferLen:dword); stdcall; var i,j,nbSample,a:dword; pSample:^wpat; WordPattern:^wpat; BytePattern:^bpat; modcb : MODcallbackProc; begin pSample := pSoundBuffer; nbSample := (bufferLen div 2)-1; for i:=0 to nbSample do mixBuf[i]:=0; for j:=1 to 16 do begin with wsound[j] do begin BytePattern := pointer(wsnd); WordPattern := pointer(wsnd); wvol := 1; for i:=0 to nbSample do begin if winuse = 0 then mixBuf[i] := mixBuf[i] + 0 else begin if wbps = 8 then begin { !!!! 8 bitsound 0-256 } { 8 bit } mixBuf[i] := mixBuf[i] + dword(((smallint(smallint(BytePattern[wofs]) * 128) ) div smallint(wvol))); end else begin { !!!! 16 bitsound -32768 0 32768 } {16 bit } mixBuf[i] := mixBuf[i] + dword(((smallint(WordPattern[wofs]) ) div smallint(wvol))); end; wint := wint + wkhz; if (wint and $FFFF0000) <> 0 then begin wint := wint and $0000FFFF; inc(wofs); if wofs = wlen then begin wofs:=0; if winuse = 1 then begin if wlop = 0 then winuse := 0; end else begin a := wsnd; wsnd := wsnd2; wsnd := a; modcb := pointer(wcbm); modcb(wsnd2,wlen); {to fill back buffer } end; end; end; end; end; end; end; for i:=0 to nbSample do pSample[i] := word(mixBuf[i] div 16); end; *) function Wave_Init:boolean; stdcall; var i :integer; begin if libFmodOpens <> 1 then Exit; mod_master_vol := 15; playing_mod_filename:= ''; block8 := false; m_bServerRunning := false; { from sound server } wsoundticks := 0; wsoundbackproc := @NopProc; for i:= 1 to 16 do wsound[i].winuse := 0; Wave_Init := Wave_open(@Sound_mixer,500); end; function Wave_Play(snd,len,khz,bps,loop,vol:dword):dword; stdcall; var i:integer; res:dword; rkhz : real; begin res := 0; if vol > 15 then vol := 15; vol := vol and 15; if bps <> 16 then if bps <> 8 then Exit; i:= 1; if block8 then i := 9; repeat if wsound[i].winuse = 0 then begin with wsound[i] do begin wsnd := snd; wlen := len; wlpe := wlen; wbps := bps; wlop := loop; wvol := vol; rkhz := khz; wkhz := round( 65535 / (44100 / rkhz)) and $0000FFFF; wofs := 0; wlpb := 0; wint := 0; winuse := 1; res := i; i := 16; { exit; } end; end; inc(i); until i > 16; Wave_Play := res; end; function Wave_PlayDBC(snd,len,khz,bps,loop,vol,snd2,cback:dword):dword; stdcall; var modcb : MODcallbackProc; iind : dword; begin modcb := pointer(cback); modcb(snd,len); {to fill first buffer } modcb(snd2,len); {to fill second buffer } iind:=Wave_Play(snd,len,khz,bps,loop,vol); if iind <> 0 then begin wsound[iind].wsnd2 := snd2; wsound[iind].wcbm := cback; wsound[iind].winuse := 2; end; Wave_PlayDBC := iind; end; procedure Wave_Set(Chanel,Value:dword); stdcall; begin if wsound[Chanel].winuse = 1 then begin if Value = 0 then wsound[Chanel].winuse := 0; { stop PLAY } if Value > 0 then { This will mean VOLUME } begin if Value > 15 then Value := 15; wsound[Chanel].wvol := Value and 15; end; end; end; //////////////////////////////////////////////////////////////////////////////// //////////////// FMOD 3.5 declaration var fmod_on:boolean; type PFSoundStream = Pointer; PFMusicModule = Pointer; TFMusicTypes = ( FMUSIC_TYPE_NONE, FMUSIC_TYPE_MOD, // Protracker / FastTracker FMUSIC_TYPE_S3M, // ScreamTracker 3 FMUSIC_TYPE_XM, // FastTracker 2 FMUSIC_TYPE_IT, // Impulse Tracker FMUSIC_TYPE_MIDI // MIDI file ); TFSoundMixerTypes = ( FSOUND_MIXER_AUTODETECT, // Enables autodetection of the fastest mixer based on your cpu. FSOUND_MIXER_BLENDMODE, // Enables the standard non mmx, blendmode mixer. FSOUND_MIXER_MMXP5, // Enables the mmx, pentium optimized blendmode mixer. FSOUND_MIXER_MMXP6, // Enables the mmx, ppro/p2/p3 optimized mixer. FSOUND_MIXER_QUALITY_AUTODETECT,// Enables autodetection of the fastest quality mixer based on your cpu. FSOUND_MIXER_QUALITY_FPU, // Enables the interpolating FPU mixer. FSOUND_MIXER_QUALITY_MMXP5, // Enables the interpolating p5 MMX mixer. FSOUND_MIXER_QUALITY_MMXP6, // Enables the interpolating ppro/p2/p3 MMX mixer. FSOUND_MIXER_MONO, // Windows CE only - MONO non interpolating/low quality mixer. For speed FSOUND_MIXER_QUALITY_MONO // Windows CE only - MONO Interpolating mixer. For speed ); TFSoundOutputTypes = ( FSOUND_OUTPUT_NOSOUND, // NoSound driver, all calls to this succeed but do nothing. FSOUND_OUTPUT_WINMM, // Windows Multimedia driver. FSOUND_OUTPUT_DSOUND, // DirectSound driver. You need this to get EAX2 or EAX3 support, or FX api support. FSOUND_OUTPUT_A3D, // A3D driver. You need this to get geometry support. FSOUND_OUTPUT_OSS, // Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. FSOUND_OUTPUT_ESD, // Linux/Unix ESD (Enlightment Sound Daemon) driver. FSOUND_OUTPUT_ALSA, // Linux Alsa driver. FSOUND_OUTPUT_XBOX // Xbox driver ); const FSOUND_LOOP_OFF = $00000001; // For non looping samples. FSOUND_LOOP_NORMAL = $00000002; // For forward looping samples. FSOUND_LOADMEMORY = $00008000; // "name" will be interpreted as a pointer to data for streaming and samples. FSOUND_8BITS = $00000008; // For 8 bit samples. // FSOUND_16BITS = $00000010; // For 16 bit samples. FSOUND_MONO = $00000020; // For mono samples. // FSOUND_STEREO = $00000040; // For stereo samples. FSOUND_STEREOPAN = -1; // value for FSOUND_SetPan so that stereo sounds are not played at half volume. See FSOUND_SetPan for more on this. FSOUND_NORMAL = (FSOUND_LOOP_OFF or FSOUND_8BITS or FSOUND_MONO); FSOUND_FREE = -1; // value to play on any free channel, or to allocate a sample in a free sample slot. var libFmod :dword; FSOUND_Init : function(MixRate: Integer; MaxSoftwareChannels: Integer; Flags: Cardinal): ByteBool; stdcall ; FSOUND_Close : procedure; stdcall ; FSOUND_SetOutput : function(OutputType: TFSoundOutputTypes): ByteBool; stdcall; FSOUND_SetDriver : function(Driver: Integer): ByteBool; stdcall; FSOUND_SetMixer : function(Mixer: TFSoundMixerTypes): ByteBool; stdcall; FSOUND_SetHWND : function(Hwnd: THandle): ByteBool; stdcall; FSOUND_SetMaxHardwareChannels : function(Max: Integer): ByteBool; stdcall; FSOUND_SetSFXMasterVolume : procedure(Volume: Integer); stdcall; FSOUND_SetVolume : function(Channel: Integer; Vol: Integer): ByteBool; stdcall; FSOUND_SetPan : function(Channel: Integer; Pan: Integer): ByteBool; stdcall; FSOUND_SetPaused : function(Channel: Integer; Paused: ByteBool): ByteBool; stdcall; FSOUND_SetLoopMode : function(Channel: Integer; LoopMode: Cardinal): ByteBool; stdcall; //v3.6 fmod correction //FSOUND_Stream_OpenFile : function(const Filename: PChar; Mode: Cardinal; MemLength: Integer): PFSoundStream; stdcall; FSOUND_Stream_OpenFile: function(const name_or_data: PChar; Mode: Cardinal; Offset: Integer; Length: Integer): PFSoundStream; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; FSOUND_Stream_Play : function(Channel: Integer; Stream: PFSoundStream): Integer; stdcall; FSOUND_Stream_Stop : function(Stream: PFSoundStream): ByteBool; stdcall ; FSOUND_Stream_Close : function(Stream: PFSoundStream): ByteBool; stdcall ; FSOUND_Stream_SetMode : function (Stream: PFSoundStream; mode: Integer): ByteBool; stdcall; FMUSIC_SetLooping : function(Module: PFMusicModule; loop: ByteBool): ByteBool; stdcall; FMUSIC_SetPaused : function(Module: PFMusicModule; Pause: ByteBool): ByteBool; stdcall; FMUSIC_SetMasterVolume : function(Module: PFMusicModule; Volume: Integer): ByteBool; stdcall; FMUSIC_LoadSong : function(const Name: PChar): PFMusicModule; stdcall ; // not working 3.6 FMUSIC_LoadSongMemory : function(Data: Pointer; Length: Integer): PFMusicModule; stdcall; FMUSIC_FreeSong : function(Module: PFMusicModule): ByteBool; stdcall; FMUSIC_PlaySong : function(Module: PFMusicModule): ByteBool; stdcall; FMUSIC_StopSong : function(Module: PFMusicModule): ByteBool; stdcall; FMUSIC_SetPanSeperation : function(Module: PFMusicModule; PanSep: Single): ByteBool; stdcall; FMUSIC_GetType : function(Module: PFMusicModule): TFMusicTypes; stdcall ; var ffff:dword; function GetProc(handle: dword; name: PChar): Pointer; var r:pointer; begin inc (ffff); R := GetProcAddress(handle, name); // if r = nil then debug('not foind',ffff); GetProc := r; end; procedure _FMODW_init(H_wnd:dword); begin inc(LibFmodOpens); if LibFmodOpens <> 1 then Exit; if libFmod <> 0 then Exit; // allready done ffff:= 0; fmod_on := false; libFMod := LoadLibrary('fmod.dll'); if libFMod = 0 then exit; // this is marker to use fmod FSOUND_Init := GetProc(libFMod, '_FSOUND_Init@12'); {1} FSOUND_Close := GetProc(libFMod, '_FSOUND_Close@0'); {2} FSOUND_SetOutput := GetProc(libFMod, '_FSOUND_SetOutput@4'); {3} FSOUND_SetDriver := GetProc(libFMod, '_FSOUND_SetDriver@4'); {4} FSOUND_SetMixer := GetProc(libFMod, '_FSOUND_SetMixer@4'); {5} FSOUND_SetHWND := GetProc(libFMod, '_FSOUND_SetHWND@4'); {6} FSOUND_SetMaxHardwareChannels := GetProc(libFMod, '_FSOUND_SetMaxHardwareChannels@4'); {7} FSOUND_SetSFXMasterVolume := GetProc(libFMod, '_FSOUND_SetSFXMasterVolume@4'); {8} FSOUND_SetVolume := GetProc(libFMod, '_FSOUND_SetVolume@8'); {9} FSOUND_SetPan := GetProc(libFMod, '_FSOUND_SetPan@8'); {10} FSOUND_SetPaused := GetProc(libFMod, '_FSOUND_SetPaused@8'); {11} FSOUND_SetLoopMode := GetProc(libFMod, '_FSOUND_SetLoopMode@8'); {12} //FSOUND_Stream_OpenFile := GetProc(libFMod, '_FSOUND_Stream_OpenFile@12'); {13} FSOUND_Stream_OpenFile := GetProc(libFMod, '_FSOUND_Stream_Open@16'); {13} // ver 3.6 FSOUND_Stream_Play := GetProc(libFMod, '_FSOUND_Stream_Play@8'); {14} FSOUND_Stream_Stop := GetProc(libFMod, '_FSOUND_Stream_Stop@4'); {15} FSOUND_Stream_Close := GetProc(libFMod, '_FSOUND_Stream_Close@4'); {16} FSOUND_Stream_SetMode := GetProc(libFMod, '_FSOUND_Stream_SetMode@8'); {16} FMUSIC_SetLooping := GetProc(libFMod, '_FMUSIC_SetLooping@8'); {17} FMUSIC_SetPaused := GetProc(libFMod, '_FMUSIC_SetPaused@8'); {18} FMUSIC_SetMasterVolume := GetProc(libFMod, '_FMUSIC_SetMasterVolume@8'); {19} FMUSIC_LoadSong := GetProc(libFMod, '_FMUSIC_LoadSong@4'); {20} ///BUG DANGER 21 is not found FMUSIC_LoadSongMemory := GetProc(libFMod,'_FMUSIC_LoadSongMemory@8'); {21} FMUSIC_FreeSong := GetProc(libFMod, '_FMUSIC_FreeSong@4'); {22} FMUSIC_PlaySong := GetProc(libFMod, '_FMUSIC_PlaySong@4'); {23} FMUSIC_StopSong := GetProc(libFMod, '_FMUSIC_StopSong@4'); {24} FMUSIC_SetPanSeperation := GetProc(libFMod, '_FMUSIC_SetPanSeperation@8'); {25} FMUSIC_GetType := GetProc(libFMod, '_FMUSIC_GetType@4'); {26} if libFmod <> 0 then begin if h_wnd <> 0 then FSOUND_SetHWND(h_wnd); FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); FSOUND_SetDriver(0); FSOUND_SetMixer(FSOUND_MIXER_QUALITY_AUTODETECT); //FSOUND_MIXER_AUTODETECT); FSOUND_SetMaxHardwareChannels(0); fmod_on := FSOUND_init(22050, 128, 0); //(44100,32,0); {32 chanels } end; end; //procedure CloseSound; stdcall; forward; procedure _FMODW_close; begin // CloseSound; Dec(LibFmodOpens); if LibFmodOpens = 0 then if libFMod <> 0 then FreeLibrary(libFMod); end; //////////////////////////////////////////////////////////////////////////////// constructor BTMMSound.Create(h_wnd:longword); begin _FMODW_Init(h_wnd); if fmod_on = false then WAVE_Init; aModule := nil; aStream := nil; aPlaying := false; aLoop := false; end; destructor BTMMSound.Destroy; begin if fmod_on then begin if aModule <> nil then FMUSIC_FreeSong(aModule); if aStream <> nil then FSOUND_Stream_Close(aStream); end; _FMODW_Close; if fmod_on = false then WAVE_Close; inherited; end; procedure BTMMSound.Play; var fslop: longword; fslopb: boolean; begin if aPlaying = false then begin if fmod_on then begin if aLoop = false then begin fslop := FSOUND_LOOP_OFF; fslopb := false; end; if aLoop = true then begin fslop := FSOUND_LOOP_NORMAL; fslopb := true; end; if aModule <> nil then begin FMUSIC_PlaySong(aModule); FMUSIC_SetMasterVolume(aModule, byte(aVolume and $FF)); FMUSIC_SetLooping(amodule,fslopb); aPlaying := true; end else begin aChannel := FSOUND_Stream_Play(FSOUND_FREE, aStream); aPlaying := aChannel >= 0; { !!! last chanel } if aPlaying then begin // if aLoop then FSOund_SetLoopMode(aChannel,fslop); FSOUND_Stream_SetMode(aStream,fslop); FSOUND_SetPan(aChannel, FSOUND_STEREOPAN); FSOUND_SetVolume(aChannel, byte(aVolume and $FF)); end; end; end else begin Mod2mem('test.mod'); SetMODvolume(aVolume); PlayMOD; end; end; end; procedure BTMMSound.Stop; begin if aPlaying then begin if fmod_on then begin if aModule <> nil then FMUSIC_StopSong(aModule); if aStream <> nil then FSOUND_Stream_Stop(aStream); aPlaying := false; end else begin end; end; end; procedure BTMMSound.Pause; begin if aPlaying then begin if fmod_on then begin if aModule <> nil then FMUSIC_SetPaused(aModule,true); if aStream <> nil then FSOUND_SetPaused(aChannel,true); end else begin end; end; end; procedure BTMMSound.Resume; begin if aPlaying then begin if fmod_on then begin if aModule <> nil then FMUSIC_SetPaused(aModule,false); if aStream <> nil then FSOUND_SetPaused(aChannel,false); end else begin end; end; end; procedure BTMMSound.LoadFromFile(File_Name:string); var fn:pchar; mdl:PFMusicModule; str:PFSoundStream; begin if aPlaying then self.Stop; Volume := 255; Loop := false; if fmod_on then begin File_Name := File_Name + #0; fn := @File_Name[1]; mdl := FMUSIC_LoadSong(fn); if mdl <> nil then begin aModule := mdl; aStream := nil; FMUSIC_SetMasterVolume(mdl, aVolume); if (FMUSIC_GetType(mdl) = FMUSIC_TYPE_MOD) or (FMUSIC_GetType(mdl) = FMUSIC_TYPE_S3M) then FMUSIC_SetPanSeperation(mdl, 0.15); // 15% crossover end else begin // Str := FSOUND_Stream_OpenFile(fn,FSOUND_NORMAL or FSOUND_LOOP_NORMAL, 0,0); Str := FSOUND_Stream_OpenFile(fn,FSOUND_NORMAL or FSOUND_LOOP_OFF, 0,0); if str <> nil then begin aModule := nil; aStream := str; end; end; end else begin end; end; procedure BTMMSound.SetVolume(value:longword); begin if Value > 255 then Value := 255; aVolume := Value; if aPlaying then begin if fmod_on then begin if aModule <> nil then FMUSIC_SetMasterVolume(aModule, byte(aVolume and $FF)); if aStream <> nil then FSOUND_SetVolume(aChannel, byte(aVolume and $FF)); end else begin end; end; end; procedure BTMMSound.SetLoop(value:boolean); var fslop: longword; fslopb: boolean; begin aLoop := Value; if aPlaying then begin if fmod_on then begin if aLoop = false then begin fslop := FSOUND_LOOP_OFF; fslopb := false; end; if aLoop = true then begin fslop := FSOUND_LOOP_NORMAL; fslopb := true; end; if aModule <> nil then FMUSIC_SetLooping(amodule,fslopb); if aStream <> nil then FSOund_SetLoopMode(aChannel,fslop); end else begin end; end; end; begin libFmodOpens := 0; libFmod := 0; fmod_on := false; end.