• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
  • entries
    22
  • comments
    30
  • views
    42470

Playing simultaneous sounds in Win32

Sign in to follow this  
Followers 0
jwezorek

2902 views

There is a nice unscary Win32 API call for playing sounds that is unpretentiously called "PlaySound". It is extremely easy to use. Unfortunately, PlaySound(...) has one problem that makes it unsuitable for even casual game development: although it will play audio asynchronously, it will not play two sounds simultaneously. Depending on what you are doing this may not be a big deal, e.g. warning beeps in an editor app and such, but for anything that is media rich it basically means that you can't use PlaySound.

This leaves you with several options:

  1. Use a third party library.

  2. Use the new Windows Audio Session API which came in with Vista.

  3. Use the (legacy) low-level Win32 MCI routines.

  4. Use the (legacy) low-level Win32 waveOut interface


So if you have serious audio needs The Right Thing is 1. or 2. above.

A little background on what I'm doing: I'm working on a Win32 C++ implementation of a puzzle game that I am eventually going to directly port to iOS. I don't really need serious audio as I just want something that is playable for game design debugging, i.e. balancing. I do want simultaneous sound effects though because I plan on releasing this Win32 prototype to gather feedback and I think sound effects add playability in this case.

Anyway, I looked into 1. and 2. On 1., I couldn't find a library that was dirt simple enough to justify its use in my project given all I am really looking for is a drop-in replacement for PlaySound that supports asynchronous simultaneous audio. On 2., well, the API is dense; I'm not looking for a research project and I couldn't find a lot of sample code -- maybe, it's too new? or maybe I wasn't looking in the right places.

On 3., if you don't know what I'm talking about, I'm talking about this function and friends. I remember using the MCI (multimedia command interface, I believe) routines back in the day, probably around 1997, and they are pretty easy to use. It's a weird little API relative to the rest of win32. You send command strings to a device object that look like "LOAD 'foo.wav' as Foo" and so forth, and I think that they will do simultaneous audio output. The problem is the MCI routines don't let you play sounds from memory and I want to play from WAVE resources that are embedded into the executable. To use MCI I would have to write my resources to a temp directory at start up and then play the serialized files. This seemed too ugly.

Which leaves 4. The problem with 4. is that waveOut et. al. are like the opposite of PlaySound: super low-level and absolutely un-user friendly. Fortunately there is a lot of code out there. In particular I found CWaveBox on CodeProject by a CodeProject user named Zenith__ that does basically what I need. I had lots of problems with this code, however, and ended up significantly re-working some code that was itself a re-work of the original CWaveBox that is posted in the CodeProject comments. I basically chose to work with the comments version because it executed the demo app as well as the original, but it was much shorter.

The code I started with is verbose, baroque, and in C rather than C++. I re-factored it in the following ways:

  • Added the ability to load WAV's from resources
  • Replaced two C-style arrays: one with a std::vector and the other with an std::map
  • Cleaned up the .h file by making things that should be private private and moving as many implementation details into the .cpp file as I could
  • Simplified some of the thread synchronization stuff by using WaitSingleObject instead of looping and polling
  • Got rid of all C-isms i.e. mallocs, callocs, memsets, memcpys, etc. Replaced with C++-style allocation, std::copy, std::fill, etc.
  • Got rid of magic constants by noticing many of them served as booleans, so replaced them with booleans
  • Changed names of crazily named variables and functions
  • Generally got rid of craziness ... we're talking goto's.


    I honestly don't understand the code involved, which is weird given the amount of work I did on it. I mean, I get that there's a thread that's running and that it is playing chunks of waves in a loop, etc. That's the level at which I understand it ... kind of reminds me of this time I was working a DARPA contract and ported a function for converting from Military Grid Reference Numbers to longitude and latitude from Fortran to C without actually understanding the algorithm or knowing Fortran...

    My code is here. Usage goes likes this:

    [source lang="c++"]#include "WaveManager.h"
    #include "resource.h"
    // ...
    {
    WaveManager wave_mgr( kMaxNumSimultaneousWaves );

    wave_mgr.LoadFromResource(ID_SND_BUZZ, MAKEINTRESOURCE(ID_SND_BUZZ));
    wave_mgr.LoadFromResource(ID_SND_CLICK, MAKEINTRESOURCE(ID_SND_CLICK));

    // ...
    wave_mgr.Play(ID_SND_BUZZ);
    // ...
    // etc.
    }[/source]

    It actually works remarkably well.

    However, the code still needs work if anyone is interested. There are a lot of functions returning error codes that are never checked. I think most of these should be changed to return void and should just throw if something serious happens. Also I think in the original implementation there could have been a race condition if you tried to load a wave after the playing thread was running. I wrapped the loading stuff in the critical section the playing thread uses, but this still might be a problem -- I'm not sure. If you use this code it is safest to load all your sound assets at start up before you start playing anything. But in terms of fixing it up more, I think the main thing is that someone who actually knows what they are doing vis-a-vis wave output could probably cut the verbosity in half or so.

    Oh, and one more note on my work, I used some C++11 stuff in there ... basically I implemented loading from memory by taking the guts of the existing LoadFromFile implementation and making it into a function template that takes a handle type as the template parameter and has an additional formal parameter that is an std::function used for loading data. In the LoadFromFile case I instantiate the template with a file HANDLE as the template parameter and pass the function the Win32 call ReadFile wrapped thinly in a lambda. In the load from resource case, the template parameter is a custom buffer struct and the functor argument becomes, basically, a lambda wrapper around std::copy. But, anyway, just a heads up that this code will only compile under Visual Studio 2010 because of the lambdas. If you're interested in using it but don't do lambdas, it would be pretty easy to replace them with regular function pointers.

    From The Curiously Recurring Gimlet Pattern

4
Sign in to follow this  
Followers 0


0 Comments


There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now