Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Mixing In Windoze...

SephirothSephiroth Fayetteville, NC, USAMember Posts: 1,035
OK, I have a stable 3D engine up now that runs in OpenGL and looks (if I say so myself) fairly decent. Now I need to get some sounds going. After all, what would UT be if it had no audio? Anyways, I've never toyed with audio playback beyond that of the Atari, so I need to not only figure out how to play a WAV, but find out how to mix a MINIMUM of four WAVs for playback at once. I also have NOT touched DirectX due to it being useless and confusing. I have been using Notepad and ANSI C/C++ for years, and after spending about a month getting nowhere with D3D, I had an OpenGL engine up after four horus of study. This being the case, I'd like to venture AWAY from DirectSound for mixing and such, unless somebody else wants to write the "audio.dll" file for me.

Anyways, can somebody point or help me with WAV playback and mixing? The engine for the game runs in Windoze 9x, NT, 2K, and XP, but seems to HATE ME (guess it's like 90% of the populas). Thanks for the help and you can contact me through my member profile or ont he two boards I moderate if you need to.

-[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]

Comments

  • blipblip Member Posts: 756
    Mixing is done by simply adding the values of each sound array element with each other to form a resultant one. Here's some ASM code for 16-bit samples (after all, this takes quite a few cycles in any language). This could be optimized by having one source buffer and a source/destination buffer, but this is the most useful form. Also, if you can tolerate extremely small errors that occur occasionally (depends on volume), then you can use DWORD operations for much more speed.
    [code]
    ;Input: ECX=Resultant buffer length in words, ESI points to first
    ; source buffer, EBX points to second source buffer, and EDI
    ; points to resultant buffer.
    ;
    ;Output: None
    ;
    ;Destroyed: ECX, ESI, EDI, EBX

    xor edx,edx ;Can't have the upper word of EDX screw up the ADD.
    StillMixing:
    xor eax,eax ;EAX's high word always needs to be zero, it can become one after the ADD.
    lodsw ;Get a word from the first buffer ([ESI])into EAX.
    mov dx,[ebx] ;Get a word from the second buffer into
    add ax,dx ;Add the two words.
    jc Chop ;If it's too big, then make it the highest value it can be.
    Back:
    add ebx,2 ;Increment the second buffer pointer by two.
    dec ecx ;Decrement the counter.
    stosw ;Write the resultant word to the resultant buffer ([EDI]).
    jnz StillMixing ;Continue mixing if ECX != 0, STOSW doesn't modify FLAGS.
    ret ;Put in the correct form of return, or none at all.
    Chop:
    mov ax,0FFFFh
    stosw
    jmp Back
    [/code]
  • SephirothSephiroth Fayetteville, NC, USAMember Posts: 1,035
    : Mixing is done by simply adding the values of each sound array element with each other to form a resultant one. Here's some ASM code for 16-bit samples (after all, this takes quite a few cycles in any language). This could be optimized by having one source buffer and a source/destination buffer, but this is the most useful form. Also, if you can tolerate extremely small errors that occur occasionally (depends on volume), then you can use DWORD operations for much more speed.

    Thanks for the example. I haven't a clue what any of it is (I did ASM way back on my Atari 800 and 1000), but I can incorporate it I think. Right now my engine is ENTIRELY C/C++, and I know that isn't the fastest code, but I have found it to be much more stable and easily debugged. Would I put that ASM source in a C/C++ function and call it each time I need to play a sound or would it be needed in the WinMain() function to be used constantly? Thanks again, blip.

    -[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]

  • blipblip Member Posts: 756
    Put it in a function, but like this (should be adequate):
    [code]
    asm {
    //Input: LengthInUInts=Resultant buffer length in words,
    // FirstSourceBuffer is the first source buffer,
    // SecondSourceBuffer is the source buffer, and
    // DestinationBuffer is the resultant buffer.
    //Output: None
    pushfd //DF will be modified, wreaks havoc in WinBloze.
    pushad //C/C++ requires that EBX, ESI, EDI, and EBP be preserved, just save 'em all.
    mov ecx,LengthInUInts //Set up the registers.
    mov esi,&FirstSourceBuffer
    mov ebx,&SecondSourceBuffer
    mov edi,&DestinationBuffer

    cld //Operate in a forward direction.
    xor edx,edx //Can't have the upper word of EDX screw up the ADD.
    StillMixing:
    xor eax,eax //EAX's high word always needs to be zero, it can become one after the ADD.
    lodsw //Get a word from the first buffer ([ESI])into EAX.
    mov dx,[ebx] //Get a word from the second buffer into
    add ax,dx //Add the two words.
    jc Chop //If it's too big, then make it the highest value it can be.
    Back:
    add ebx,2 //Increment the second buffer pointer by two.
    dec ecx //Decrement the counter.
    stosw //Write the resultant word to the resultant buffer ([EDI]).
    jnz StillMixing //Continue mixing if ECX != 0, STOSW doesn't modify FLAGS.
    popad
    popfd //Restore FLAGS.
    ret //Put in the correct form of return, or none at all.
    Chop:
    mov ax,0FFFFh
    stosw
    jmp Back
    }
    [/code]

    If you find this has a bug, just trash it and use the algorithm I described earlier.
  • SephirothSephiroth Fayetteville, NC, USAMember Posts: 1,035
    I understand parts of that from my old Atari 6502 ASM, but most is greek. However I might be able to go on what you've shown (thanks for all the comments!) and write a C/C++ fucntion to do that. Learning WAV format should be easy enough, and I have minor info on it already. I may also have a precache option for sounds since the average system now has 256mb of ram. That would mean less disk access nd faster audio playback/mixing. And best of all, NO DirectX!!

    *pets OpenGL, Glide, and home-brew audio players*

    -[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]

  • edocecrousedocecrous Member Posts: 49
    Hi!
    I just happen to work on a sound engine, pure Win32, no DirectX.
    Just a comment on mixing:
    If you set the windows to play 8-bit samples, those are not signed.
    But, if you set it to 16-bit, those samples are signed!!!
    So, 7FFFh is the highest and 8000h is the smallest sample value.
    Since I had enough of the stupid c++ different forms of numbers, and the numeric conversion hell, i wrote this part in asm.
    My code takes a 16-bit sample, converts it to 32bit signed, and adds the channels (samples) together.
    Than i check if the final (mixed) value is positive or negative, and if it's over or below the maximum values. If it is, i set the maximum/minimum.
    The whole code is less than 18 lines, and mixes up 32 channels flawlesly.
    Also, you have to do the double-buffering technic, and if the buffer is too big, the effects will be not in real time. If it's too small, windows can't handle it. /I raised the priority level of the routine, so it's working fine now/

    I would suggest to use DirectX or a third party music library, i'm working hard on my code, and windows always puts a big (huge) gate before me when i think it's done and working.

    Right now i have a music player, which uses big buffer, and an effect player, wich uses a small one, and i'm trying to put it together, the 3d day now....:-(

    Maybe the mixing work assuming unsigned samples too, i never tried. But if it does not, you will know what to do.
    Also, use .pcm files instead of .wav, the pcm has no headers, just the samples.
    And, the 8bit wav is unsigned, the 8bit pcm is signed...
    No idea about 16bit do...

    Edocecrous
    edocecrous@yahoo.com

  • SephirothSephiroth Fayetteville, NC, USAMember Posts: 1,035
    Ah, so PCM format is basically a WAV without any of that extra data at the top of the file? If that's the case, that would be AWESOME simply because of the way my sound engine works! I could just play the file and when I get EOF I'd just close the file and tell my app to free that data for another sound, should it be needed.

    -[italic][b][red]S[/red][purple]e[/purple][blue]p[/blue][green]h[/green][red]i[/red][purple]r[/purple][blue]o[/blue][green]t[/green][red]h[/red][/b][/italic]

  • edocecrousedocecrous Member Posts: 49
    [b][red]This message was edited by edocecrous at 2002-9-1 7:48:13[/red][/b][hr]
    Hi!
    Yes, .pcm is pure sound data, no headers. Maybe i'm an old fashioned guy, but you realy planning to use sound files from the harddrive? I mean: Something just blow up -> Load bumm.pcm -> play bumm.pcm -> release memory ?
    I don't have a pentium 6, just an old Athlon 750, but i've got problems with realtime sounds right stored in the memory, i can't imagine the delay from harddrive...
    Maybe i'm wrong. But let me know... :-)
    My sound-engine can reach the minimum delay of 68ms, (0.068 sec to be sure), using double buffering and callback function. /with the music player/.
    On my slower computer, this number is 0.2 sec. /baaaad/.
    Also, i tried tripple-buffering, it helps alot, i'll try quadrupple buffering too.

    I'm working on an [infinite loop pointer following pre-writer] function, it should achieve a far higher precision, but it's a method 'not recommended' by microsoft ;->
    Need any help, let me know.

    Edocecrous


  • heyiheyi Member Posts: 1
    Bu using Dirextx can we mix sound?
    If there are several audio stream,how can i mix them into one audio stream in windows?

    Thank you very much!
  • Shawn CarterShawn Carter Member Posts: 0

    _____ { http://forcoder.org } free ebooks and video tutorials about | Visual Basic .NET, Swift, Ruby, Assembly, MATLAB, Visual Basic, Go, C, Objective-C, Scratch, Java, Delphi, R, C++, C#, Python, JavaScript, Perl, PHP, PL/SQL Scheme, Transact-SQL, Scala, Clojure, Erlang, Prolog, VBScript, ABAP, FoxPro, D, Alice, Logo, Crystal, Lisp, Awk, Apex, Dart, LabVIEW, ML, Ada, Rust, Hack, Fortran, F#, Bash, Julia, Lua, Kotlin, COBOL, SAS | _____________

Sign In or Register to comment.