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