1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Audio stream functions.
12  *
13  *      By Shawn Hargreaves (original version by Andrew Ellem).
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 
19 #include "allegro.h"
20 #include "allegro/internal/aintern.h"
21 
22 
23 
24 /* play_audio_stream:
25  *  Creates a new audio stream and starts it playing. The length is the
26  *  size of each transfer buffer.
27  */
play_audio_stream(int len,int bits,int stereo,int freq,int vol,int pan)28 AUDIOSTREAM *play_audio_stream(int len, int bits, int stereo, int freq, int vol, int pan)
29 {
30    AUDIOSTREAM *stream;
31    int i, bufcount;
32    ASSERT(len > 0);
33    ASSERT(bits > 0);
34    ASSERT(freq > 0);
35 
36    /* decide how many buffer fragments we will need */
37    if ((digi_driver) && (digi_driver->buffer_size))
38       i = digi_driver->buffer_size();
39    else
40       i = 2048;
41 
42    if (len >= i)
43       bufcount = 1;
44    else
45       bufcount = (i + len-1) / len;
46 
47    /* create the stream structure */
48    stream = _AL_MALLOC(sizeof(AUDIOSTREAM));
49    if (!stream)
50       return NULL;
51 
52    stream->len = len;
53    stream->bufcount = bufcount;
54    stream->bufnum = 0;
55    stream->active = 1;
56    stream->locked = NULL;
57 
58    /* create the underlying sample */
59    stream->samp = create_sample(bits, stereo, freq, len*bufcount*2);
60    if (!stream->samp) {
61       _AL_FREE(stream);
62       return NULL;
63    }
64 
65    /* fill with silence */
66    if (bits == 16) {
67       unsigned short *p = stream->samp->data;
68       for (i=0; i < len*bufcount*2 * ((stereo) ? 2 : 1); i++)
69 	 p[i] = 0x8000;
70    }
71    else {
72       unsigned char *p = stream->samp->data;
73       for (i=0; i < len*bufcount*2 * ((stereo) ? 2 : 1); i++)
74 	 p[i] = 0x80;
75    }
76 
77    LOCK_DATA(stream, sizeof(AUDIOSTREAM));
78 
79    /* play the sample in looped mode */
80    stream->voice = allocate_voice(stream->samp);
81    if (stream->voice < 0) {
82       destroy_sample(stream->samp);
83       UNLOCK_DATA(stream, sizeof(AUDIOSTREAM));
84       _AL_FREE(stream);
85       return NULL;
86    }
87 
88    voice_set_playmode(stream->voice, PLAYMODE_LOOP);
89    voice_set_volume(stream->voice, vol);
90    voice_set_pan(stream->voice, pan);
91 
92    return stream;
93 }
94 
95 
96 
97 /* stop_audio_stream:
98  *  Destroys an audio stream when it is no longer required.
99  */
stop_audio_stream(AUDIOSTREAM * stream)100 void stop_audio_stream(AUDIOSTREAM *stream)
101 {
102    ASSERT(stream);
103 
104    if ((stream->locked) && (digi_driver->unlock_voice))
105       digi_driver->unlock_voice(stream->voice);
106 
107    voice_stop(stream->voice);
108    deallocate_voice(stream->voice);
109 
110    destroy_sample(stream->samp);
111 
112    UNLOCK_DATA(stream, sizeof(AUDIOSTREAM));
113    _AL_FREE(stream);
114 }
115 
116 
117 
118 /* get_audio_stream_buffer:
119  *  Returns a pointer to the next audio buffer, or NULL if the previous
120  *  data is still playing. This must be called at regular intervals while
121  *  the stream is playing, and you must fill the return address with the
122  *  appropriate number (the same length that you specified when you create
123  *  the stream) of samples. Call free_audio_stream_buffer() after loading
124  *  the new samples, to indicate that the data is now valid.
125  */
get_audio_stream_buffer(AUDIOSTREAM * stream)126 void *get_audio_stream_buffer(AUDIOSTREAM *stream)
127 {
128    int pos;
129    char *data = NULL;
130    ASSERT(stream);
131 
132    if (stream->bufnum == stream->active * stream->bufcount) {
133       /* waiting for the sample to switch halves */
134       pos = voice_get_position(stream->voice);
135 
136       if (stream->active == 0) {
137 	 if (pos < stream->len*stream->bufcount)
138 	    return NULL;
139       }
140       else {
141 	 if (pos >= stream->len*stream->bufcount)
142 	    return NULL;
143       }
144 
145       stream->active = 1-stream->active;
146    }
147 
148    /* make sure we got access to the right bit of sample data */
149    if (!stream->locked) {
150       pos = (1-stream->active) * stream->bufcount * stream->len;
151 
152       if (digi_driver->lock_voice)
153 	 data = digi_driver->lock_voice(stream->voice, pos, pos+stream->bufcount*stream->len);
154 
155       if (data)
156 	 stream->locked = data;
157       else
158 	 stream->locked = (char *)stream->samp->data + (pos * ((stream->samp->bits==8) ? 1 : sizeof(short)) * ((stream->samp->stereo) ? 2 : 1));
159    }
160 
161    return (char *)stream->locked + ((stream->bufnum % stream->bufcount) *
162 				    stream->len *
163 				    ((stream->samp->bits==8) ? 1 : sizeof(short)) *
164 				    ((stream->samp->stereo) ? 2 : 1));
165 }
166 
167 
168 
169 /* free_audio_stream_buffer:
170  *  Indicates that a sample buffer previously returned by a call to
171  *  get_audio_stream_buffer() has now been filled with valid data.
172  */
free_audio_stream_buffer(AUDIOSTREAM * stream)173 void free_audio_stream_buffer(AUDIOSTREAM *stream)
174 {
175    ASSERT(stream);
176 
177    /* flip buffers */
178    stream->bufnum++;
179 
180    if (stream->bufnum >= stream->bufcount*2)
181       stream->bufnum = 0;
182 
183    /* unlock old waveform region */
184    if ((stream->locked) &&
185        ((stream->bufnum == 0) || (stream->bufnum == stream->bufcount))) {
186 
187       if (digi_driver->unlock_voice)
188 	 digi_driver->unlock_voice(stream->voice);
189 
190       stream->locked = NULL;
191    }
192 
193    /* start playing if it wasn't already */
194    if (voice_get_position(stream->voice) == -1)
195       voice_start(stream->voice);
196 }
197