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
|
/* ______ ___ ___
* /\ _ \ /\_ \ /\_ \
* \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
* \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
* \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
* \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
* \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
* /\____/
* \_/__/
*
* Audio stream functions.
*
* By Shawn Hargreaves (original version by Andrew Ellem).
*
* See readme.txt for copyright information.
*/
#include "allegro.h"
/* play_audio_stream:
* Creates a new audio stream and starts it playing. The length is the
* size of each transfer buffer.
*/
AUDIOSTREAM *play_audio_stream(int len, int bits, int stereo, int freq, int vol, int pan)
{
AUDIOSTREAM *stream;
int i, bufcount;
/* decide how many buffer fragments we will need */
if ((digi_driver) && (digi_driver->buffer_size))
i = digi_driver->buffer_size();
else
i = 2048;
if (len >= i)
bufcount = 1;
else
bufcount = (i + len-1) / len;
/* create the stream structure */
stream = malloc(sizeof(AUDIOSTREAM));
if (!stream)
return NULL;
stream->len = len;
stream->bufcount = bufcount;
stream->bufnum = 0;
stream->active = 1;
stream->locked = NULL;
/* create the underlying sample */
stream->samp = create_sample(bits, stereo, freq, len*bufcount*2);
if (!stream->samp) {
free(stream);
return NULL;
}
/* fill with silence */
if (bits == 16) {
unsigned short *p = stream->samp->data;
for (i=0; i < len*bufcount*2 * ((stereo) ? 2 : 1); i++)
p[i] = 0x8000;
}
else {
unsigned char *p = stream->samp->data;
for (i=0; i < len*bufcount*2 * ((stereo) ? 2 : 1); i++)
p[i] = 0x80;
}
LOCK_DATA(stream, sizeof(AUDIOSTREAM));
/* play the sample in looped mode */
stream->voice = allocate_voice(stream->samp);
if (stream->voice < 0) {
destroy_sample(stream->samp);
UNLOCK_DATA(stream, sizeof(AUDIOSTREAM));
free(stream);
return NULL;
}
voice_set_playmode(stream->voice, PLAYMODE_LOOP);
voice_set_volume(stream->voice, vol);
voice_set_pan(stream->voice, pan);
return stream;
}
/* stop_audio_stream:
* Destroys an audio stream when it is no longer required.
*/
void stop_audio_stream(AUDIOSTREAM *stream)
{
if ((stream->locked) && (digi_driver->unlock_voice))
digi_driver->unlock_voice(stream->voice);
voice_stop(stream->voice);
deallocate_voice(stream->voice);
destroy_sample(stream->samp);
UNLOCK_DATA(stream, sizeof(AUDIOSTREAM));
free(stream);
}
/* get_audio_stream_buffer:
* Returns a pointer to the next audio buffer, or NULL if the previous
* data is still playing. This must be called at regular intervals while
* the stream is playing, and you must fill the return address with the
* appropriate number (the same length that you specified when you create
* the stream) of samples. Call free_audio_stream_buffer() after loading
* the new samples, to indicate that the data is now valid.
*/
void *get_audio_stream_buffer(AUDIOSTREAM *stream)
{
int pos;
char *data = NULL;
if (stream->bufnum == stream->active * stream->bufcount) {
/* waiting for the sample to switch halves */
pos = voice_get_position(stream->voice);
if (stream->active == 0) {
if (pos < stream->len*stream->bufcount)
return NULL;
}
else {
if (pos >= stream->len*stream->bufcount)
return NULL;
}
stream->active = 1-stream->active;
}
/* make sure we got access to the right bit of sample data */
if (!stream->locked) {
pos = (1-stream->active) * stream->bufcount * stream->len;
if (digi_driver->lock_voice)
data = digi_driver->lock_voice(stream->voice, pos, pos+stream->bufcount*stream->len);
if (data)
stream->locked = data;
else
stream->locked = (char *)stream->samp->data + (pos * ((stream->samp->bits==8) ? 1 : sizeof(short)) * ((stream->samp->stereo) ? 2 : 1));
}
return (char *)stream->locked + ((stream->bufnum % stream->bufcount) *
stream->len *
((stream->samp->bits==8) ? 1 : sizeof(short)) *
((stream->samp->stereo) ? 2 : 1));
}
/* free_audio_stream_buffer:
* Indicates that a sample buffer previously returned by a call to
* get_audio_stream_buffer() has now been filled with valid data.
*/
void free_audio_stream_buffer(AUDIOSTREAM *stream)
{
/* flip buffers */
stream->bufnum++;
if (stream->bufnum >= stream->bufcount*2)
stream->bufnum = 0;
/* unlock old waveform region */
if ((stream->locked) &&
((stream->bufnum == 0) || (stream->bufnum == stream->bufcount))) {
if (digi_driver->unlock_voice)
digi_driver->unlock_voice(stream->voice);
stream->locked = NULL;
}
/* start playing if it wasn't already */
if (voice_get_position(stream->voice) == -1)
voice_start(stream->voice);
}
|