1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
/*
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 <stdio.h>
#include <stdarg.h>
#include <string.h>
#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<NUM_CHANNELS; ++i ) {
if ( channels[i].len <= 0 )
return(PlaySound(sndID, priority, i, callback));
}
for ( i=0; i<NUM_CHANNELS; ++i ) {
if ( priority > 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<NUM_CHANNELS; ++i )
HaltSound(i);
}
void HaltSound(Uint8 channel) {
channels[channel].len = 0;
}
/* Find out if a sound is playing on a channel */
int Playing(Sint16 sndID = 0, Sint8 *channel = NULL) {
Uint8 i;
for ( i=0; i<NUM_CHANNELS; ++i ) {
if ( channels[i].len <= 0 )
continue;
if ( (sndID == 0) || (sndID == channels[i].ID) ) {
if ( channel )
*channel = i;
return(1);
}
}
return(0);
}
Sint16 Priority(Uint8 channel) {
if ( channels[channel].len > 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<NUM_CHANNELS; ++i ) {
if ( channels[i].len > 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];
};
|