|
1 /** |
|
2 * $Id: audioplayer.c 53 2008-01-10 00:19:41Z mbroeker $ |
|
3 * $URL: http://localhost/svn/c/VirtualReader/trunk/src/audioplayer.c $ |
|
4 */ |
|
5 |
|
6 #include <audioplayer.h> |
|
7 |
|
8 typedef struct { |
|
9 SDL_AudioSpec spec; // internal structure |
|
10 Uint8 *sound_buffer; // malloced pointer from sdl |
|
11 Uint32 sound_pos; // position |
|
12 Uint32 sound_len; // length in bytes |
|
13 Uint32 length; // Length in Milliseconds |
|
14 |
|
15 int opened; // bool opened |
|
16 int loaded; // bool loaded |
|
17 int verbose; // verbose messages |
|
18 int timeout; // timeout |
|
19 int timer; // bool timer |
|
20 } AudioDevice; |
|
21 |
|
22 AudioDevice AD; |
|
23 |
|
24 int audio_init () |
|
25 { |
|
26 /* |
|
27 * initialize SDL for audio output |
|
28 */ |
|
29 if (SDL_Init (SDL_INIT_AUDIO) < 0) { |
|
30 fprintf (stderr, "audio_init: Cannot initialize SDL-Subsystem\n"); |
|
31 return -1; |
|
32 } |
|
33 |
|
34 AD.sound_buffer = 0; |
|
35 AD.sound_pos = 0; |
|
36 AD.sound_len = 0; |
|
37 |
|
38 AD.opened = 0; |
|
39 AD.loaded = 0; |
|
40 AD.verbose = 0; |
|
41 |
|
42 AD.timeout = 0; |
|
43 AD.timer = 0; |
|
44 |
|
45 return 0; |
|
46 } |
|
47 |
|
48 void audio_shutdown () |
|
49 { |
|
50 /* |
|
51 * quit sdl |
|
52 */ |
|
53 SDL_AudioQuit (); |
|
54 SDL_Quit (); |
|
55 } |
|
56 |
|
57 static void Callback (void *userdata, Uint8 * stream, int len) |
|
58 { |
|
59 Uint8 *waveptr = NULL; |
|
60 |
|
61 /* |
|
62 * loaded = 0 Segmentation fault |
|
63 * len = 0 nothing to play |
|
64 */ |
|
65 if (!(AD.loaded && len)) |
|
66 return; |
|
67 |
|
68 waveptr = AD.sound_buffer + AD.sound_pos; |
|
69 SDL_MixAudio (stream, waveptr, len, SDL_MIX_MAXVOLUME); |
|
70 AD.sound_pos += len; /* bereits gespielt */ |
|
71 |
|
72 if (audioplayer_gettime () > (AD.length - AD.timeout)) { |
|
73 AD.sound_pos = AD.length; |
|
74 AD.sound_len = 0; |
|
75 AD.timer = 0; |
|
76 } |
|
77 } |
|
78 |
|
79 Uint32 audioplayer_getsoundlen () |
|
80 { |
|
81 return AD.sound_len; |
|
82 } |
|
83 |
|
84 void audioplayer_media_info (char *fname) |
|
85 { |
|
86 AD.length = audioplayer_getwavelength (fname); |
|
87 |
|
88 printf ("Playing %s: %d Hz, %d Bit Audio, %d Channel(s), %3.2d ms\n", |
|
89 fname, AD.spec.freq, audioplayer_getbitrate (), AD.spec.channels, AD.length); |
|
90 } |
|
91 |
|
92 int audioplayer_getbitrate () |
|
93 { |
|
94 int bitrate = 0; |
|
95 |
|
96 switch (AD.spec.format) { |
|
97 case AUDIO_U8: |
|
98 case AUDIO_S8: |
|
99 bitrate = 8; |
|
100 break; |
|
101 case AUDIO_S16LSB: |
|
102 case AUDIO_S16MSB: |
|
103 case AUDIO_U16LSB: |
|
104 case AUDIO_U16MSB: |
|
105 bitrate = 16; |
|
106 break; |
|
107 } |
|
108 |
|
109 return bitrate; |
|
110 } |
|
111 |
|
112 Uint32 audioplayer_getwavelength (char *fname) |
|
113 { |
|
114 struct stat info; |
|
115 Uint32 value = 0; |
|
116 |
|
117 if (fname == NULL) |
|
118 return AD.length; |
|
119 |
|
120 if (stat (fname, &info) == 0) |
|
121 /* |
|
122 * the value is really big, so be carefull |
|
123 * changes in the order result in different values |
|
124 * the storage type isn`t well choosen... |
|
125 */ |
|
126 value = ((info.st_size) / (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)) * 1000.0); |
|
127 |
|
128 return (value); |
|
129 } |
|
130 |
|
131 Uint32 audioplayer_getposition () |
|
132 { |
|
133 return AD.sound_pos; |
|
134 } |
|
135 |
|
136 Uint32 audioplayer_gettime () |
|
137 { |
|
138 Uint32 ret; |
|
139 |
|
140 ret = AD.sound_pos / (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)) * 1000.0; |
|
141 |
|
142 return ret; |
|
143 } |
|
144 |
|
145 void audioplayer_settime (long tm) |
|
146 { |
|
147 AD.sound_pos = tm / 1000.0 * (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)); |
|
148 |
|
149 /* |
|
150 * Eine Adresse ... |
|
151 */ |
|
152 while ((AD.sound_pos % 2) != 0) |
|
153 AD.sound_pos++; |
|
154 |
|
155 if (AD.verbose) |
|
156 printf ("\e[31m[ATTENTION]\e[37m [#%d/#%d] = %d ms\n", AD.sound_pos, AD.sound_len, audioplayer_gettime ()); |
|
157 } |
|
158 |
|
159 void audioplayer_stop () |
|
160 { |
|
161 /* |
|
162 * stops the callback function |
|
163 */ |
|
164 SDL_PauseAudio (1); |
|
165 AD.spec.callback = NULL; |
|
166 |
|
167 if (AD.loaded == 1) |
|
168 SDL_FreeWAV (AD.sound_buffer); |
|
169 |
|
170 AD.loaded = 0; |
|
171 AD.timer = 0; |
|
172 } |
|
173 |
|
174 void audioplayer_delay (Uint32 milliseconds) |
|
175 { |
|
176 struct timespec tm; |
|
177 |
|
178 tm.tv_sec = 0; |
|
179 tm.tv_nsec = milliseconds * 1000; |
|
180 |
|
181 while (AD.timer) |
|
182 nanosleep (&tm, NULL); |
|
183 } |
|
184 |
|
185 void audioplayer_setverbose (int verbose) |
|
186 { |
|
187 AD.verbose = verbose; |
|
188 } |
|
189 |
|
190 int audioplayer (char *fname, Uint32 timeout) |
|
191 { |
|
192 if (SDL_LoadWAV (fname, &AD.spec, &AD.sound_buffer, &AD.sound_len) == NULL) { |
|
193 printf ("SDL: %s\n", SDL_GetError ()); |
|
194 return -1; |
|
195 } |
|
196 |
|
197 AD.loaded = 1; |
|
198 |
|
199 if (!AD.opened) { |
|
200 AD.spec.callback = Callback; |
|
201 if (SDL_OpenAudio (&AD.spec, NULL) < 0) { |
|
202 fprintf (stderr, "Cannot open audio device: %s\n", SDL_GetError ()); |
|
203 return -1; |
|
204 } |
|
205 AD.opened = 1; |
|
206 } |
|
207 |
|
208 /* |
|
209 * calls implicitly getwavelength |
|
210 */ |
|
211 audioplayer_media_info (fname); |
|
212 |
|
213 AD.sound_pos = 0; |
|
214 |
|
215 /* |
|
216 * starts playback via Callback function |
|
217 */ |
|
218 SDL_PauseAudio (0); |
|
219 |
|
220 /* |
|
221 * initializes the timeout mechanism |
|
222 */ |
|
223 AD.timer = 1; |
|
224 AD.timeout = timeout; |
|
225 |
|
226 /* |
|
227 * controlled delay |
|
228 */ |
|
229 audioplayer_delay (timeout); |
|
230 |
|
231 return 0; |
|
232 } |