/* MACLIB: A companion library to SDL for working with Macintosh (tm) data Copyright (C) 1997 Sam Lantinga This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Sam Lantinga 5635-34 Springhouse Dr. Pleasanton, CA 94588 (USA) slouken@devolution.com */ /* This is a general mixer that takes Macintosh sound resource files and mixes various sounds on command. */ #include #include #include #include "SDL_types.h" #include "SDL_mutex.h" #include "SDL_thread.h" #include "SDL_audio.h" #include "Mac_Wave.h" #define MAX_VOLUME 8 /* Software volume ranges from 0 - 8 */ #define NUM_CHANNELS 4 /* 4 sound mixing channels, limit 128 */ #define DSP_FREQUENCY 11025 /* Convert the SNDs to this frequency */ class Sound { public: Sound(const char *soundfile, Uint8 vol = 4); ~Sound(); /* Set volume in the range 0-8 */ Uint8 Volume(Uint8 vol); Uint8 Volume(void) { return(volume); } /* Play the requested sound */ int PlaySound(Uint16 sndID, Uint8 priority = 0, void (*callback)(Uint8 channel) = NULL) { int i; for ( i=0; i Priority(i) ) return(PlaySound(sndID, priority, i, callback)); } return(-1); } int PlaySound(Uint16 sndID, Uint8 priority, Uint8 channel, void (*callback)(Uint8 channel) = NULL); /* Stop mixing on the requested channels */ void HaltSound(void) { Uint8 i; for ( i=0; i 0 ) return(channels[channel].priority); return(-1); } int ChannelFree(Sint8 channel = -1) { Uint8 i; /* Checking a particular channel? */ if ( channel >= 0 ) return((channels[channel].len > 0) ? 1 : 0); /* Checking any channel */ for ( i=0; i 0 ) return(1); } return(0); } char *Error(void) { return(errstr); } /* These functions really do all the work */ static void FillAudioU8(Sound *sound, Uint8 *stream, int len); private: Uint8 playing; struct channel { Uint16 ID; Sint16 priority; int len; /* Signed, so race conditions can make it < 0 */ Uint8 *src; void (*callback)(Uint8 channel); } channels[NUM_CHANNELS]; SDL_AudioSpec *spec; Uint8 volume; /* Fake audio handler, in case we can't open the real thing */ SDL_Thread *bogus_audio; /* Functions for getting and setting a hash indexed by Uint16 */ /* We use a sparse tiered pointer page scheme :-) It's probably not unique, but I made this version up. :-) */ Wave ***hashpage; void InitHash(void) { hashpage = new Wave **[256]; memset(hashpage, 0, 256*sizeof(Wave **)); } void Hash(Uint16 index, Wave *value) { Uint8 upper, lower; upper = index>>8; lower = index&0xFF; if ( hashpage[upper] == NULL ) { hashpage[upper] = new Wave *[256]; memset(hashpage[upper], 0, 256*sizeof(Wave *)); } if ( hashpage[upper][lower] ) { #ifdef DEBUG_HASH printf("Warning: Hash page %d/%d already used!\n", upper, lower); #endif delete hashpage[upper][lower]; } #ifdef DEBUG_HASH printf("Saving Wave id %hu to hash page %d/%d\n", index, upper, lower); #endif hashpage[upper][lower] = value; } Wave *Hash(Uint16 index) { Uint8 upper, lower; upper = index>>8; lower = index&0xFF; if ( hashpage[upper] == NULL ) return(NULL); return(hashpage[upper][lower]); } void FreeHash(void) { Uint16 upper, lower; for ( upper = 0; upper < 256; ++upper ) { if ( hashpage[upper] ) { for ( lower = 0; lower < 256; ++lower ) { if ( hashpage[upper][lower] ) { #ifdef DEBUG_HASH printf("Freeing Wave id %hu at hash page %d/%d\n",(upper<<8)|lower,upper,lower); #endif delete hashpage[upper][lower]; } } delete[] hashpage[upper]; } } delete[] hashpage; } /* Useful for getting error feedback */ void error(char *fmt, ...) { va_list ap; va_start(ap, fmt); vsnprintf(errbuf, sizeof(errbuf), fmt, ap); va_end(ap); errstr = errbuf; } char *errstr; char errbuf[BUFSIZ]; };