210 return Abort(true); |
210 return Abort(true); |
211 } |
211 } |
212 |
212 |
213 // --- cOggDecoder ------------------------------------------------------------- |
213 // --- cOggDecoder ------------------------------------------------------------- |
214 |
214 |
215 cOggDecoder::cOggDecoder(const char *Filename) |
215 cOggDecoder::cOggDecoder(const char *Filename, bool preinit) |
216 :cDecoder(Filename) |
216 :cDecoder(Filename) |
217 ,file(Filename) |
217 { |
218 ,info(&file) |
218 file=0; info=0; pcm=0; |
219 { |
219 if(preinit) { |
220 pcm=0; |
220 file=new cOggFile(Filename); |
|
221 info=new cOggInfo(file); |
|
222 } |
221 } |
223 } |
222 |
224 |
223 cOggDecoder::~cOggDecoder() |
225 cOggDecoder::~cOggDecoder() |
224 { |
226 { |
225 Clean(); |
227 Clean(); |
|
228 delete info; |
|
229 delete file; |
226 } |
230 } |
227 |
231 |
228 bool cOggDecoder::Valid(void) |
232 bool cOggDecoder::Valid(void) |
229 { |
233 { |
230 bool res=false; |
234 bool res=false; |
231 if(TryLock()) { |
235 if(TryLock()) { |
232 if(file.Open(false)) res=true; |
236 if(file->Open(false)) res=true; |
233 Unlock(); |
237 Unlock(); |
234 } |
238 } |
235 return res; |
239 return res; |
236 } |
240 } |
237 |
241 |
238 cFileInfo *cOggDecoder::FileInfo(void) |
242 cFileInfo *cOggDecoder::FileInfo(void) |
239 { |
243 { |
240 cFileInfo *fi=0; |
244 cFileInfo *fi=0; |
241 if(file.HasInfo()) fi=&file; |
245 if(file->HasInfo()) fi=file; |
242 else if(TryLock()){ |
246 else if(TryLock()){ |
243 if(file.Open()) { fi=&file; file.Close(); } |
247 if(file->Open()) { fi=file; file->Close(); } |
244 Unlock(); |
248 Unlock(); |
245 } |
249 } |
246 return fi; |
250 return fi; |
247 } |
251 } |
248 |
252 |
249 cSongInfo *cOggDecoder::SongInfo(bool get) |
253 cSongInfo *cOggDecoder::SongInfo(bool get) |
250 { |
254 { |
251 cSongInfo *si=0; |
255 cSongInfo *si=0; |
252 if(info.HasInfo()) si=&info; |
256 if(info->HasInfo()) si=info; |
253 else if(get && TryLock()) { |
257 else if(get && TryLock()) { |
254 if(info.DoScan(false)) si=&info; |
258 if(info->DoScan(false)) si=info; |
255 Unlock(); |
259 Unlock(); |
256 } |
260 } |
257 return si; |
261 return si; |
258 } |
262 } |
259 |
263 |
260 cPlayInfo *cOggDecoder::PlayInfo(void) |
264 cPlayInfo *cOggDecoder::PlayInfo(void) |
261 { |
265 { |
262 if(playing) { |
266 if(playing) { |
263 pi.Index=index/1000; |
267 pi.Index=index/1000; |
264 pi.Total=info.Total; |
268 pi.Total=info->Total; |
265 return π |
269 return π |
266 } |
270 } |
267 return 0; |
271 return 0; |
268 } |
272 } |
269 |
273 |
276 |
280 |
277 bool cOggDecoder::Clean(void) |
281 bool cOggDecoder::Clean(void) |
278 { |
282 { |
279 playing=false; |
283 playing=false; |
280 delete pcm; pcm=0; |
284 delete pcm; pcm=0; |
281 file.Close(); |
285 file->Close(); |
282 return false; |
286 return false; |
283 } |
287 } |
284 |
288 |
285 #define SF_SAMPLES (sizeof(pcm->samples[0])/sizeof(mad_fixed_t)) |
289 #define SF_SAMPLES (sizeof(pcm->samples[0])/sizeof(mad_fixed_t)) |
286 |
290 |
287 bool cOggDecoder::Start(void) |
291 bool cOggDecoder::Start(void) |
288 { |
292 { |
289 Lock(true); |
293 Lock(true); |
290 Init(); playing=true; |
294 Init(); playing=true; |
291 if(file.Open() && info.DoScan(true)) { |
295 if(file->Open() && info->DoScan(true)) { |
292 d(printf("ogg: open rate=%d channels=%d seek=%d\n", |
296 d(printf("ogg: open rate=%d channels=%d seek=%d\n", |
293 info.SampleFreq,info.Channels,file.CanSeek())) |
297 info->SampleFreq,info->Channels,file->CanSeek())) |
294 if(info.Channels<=2) { |
298 if(info->Channels<=2) { |
295 Unlock(); |
299 Unlock(); |
296 return true; |
300 return true; |
297 } |
301 } |
298 else esyslog("ERROR: cannot play ogg file %s: more than 2 channels",filename); |
302 else esyslog("ERROR: cannot play ogg file %s: more than 2 channels",filename); |
299 } |
303 } |
322 struct Decode *cOggDecoder::Decode(void) |
326 struct Decode *cOggDecoder::Decode(void) |
323 { |
327 { |
324 Lock(); // this is released in Done() |
328 Lock(); // this is released in Done() |
325 if(playing) { |
329 if(playing) { |
326 short framebuff[2*SF_SAMPLES]; |
330 short framebuff[2*SF_SAMPLES]; |
327 int n=file.Stream(framebuff,SF_SAMPLES); |
331 int n=file->Stream(framebuff,SF_SAMPLES); |
328 if(n<0) return Done(dsError); |
332 if(n<0) return Done(dsError); |
329 if(n==0) return Done(dsEof); |
333 if(n==0) return Done(dsEof); |
330 |
334 |
331 pcm->samplerate=info.SampleFreq; |
335 pcm->samplerate=info->SampleFreq; |
332 pcm->channels=info.Channels; |
336 pcm->channels=info->Channels; |
333 n/=pcm->channels; |
337 n/=pcm->channels; |
334 pcm->length=n; |
338 pcm->length=n; |
335 index=file.IndexMs(); |
339 index=file->IndexMs(); |
336 |
340 |
337 short *data=framebuff; |
341 short *data=framebuff; |
338 mad_fixed_t *sam0=pcm->samples[0], *sam1=pcm->samples[1]; |
342 mad_fixed_t *sam0=pcm->samples[0], *sam1=pcm->samples[1]; |
339 const int s=MAD_F_FRACBITS+1-(sizeof(short)*8); // shift value for mad_fixed conversion |
343 const int s=MAD_F_FRACBITS+1-(sizeof(short)*8); // shift value for mad_fixed conversion |
340 if(pcm->channels>1) { |
344 if(pcm->channels>1) { |
345 } |
349 } |
346 else { |
350 else { |
347 for(; n>0 ; n--) |
351 for(; n>0 ; n--) |
348 *sam0++=(*data++) << s; |
352 *sam0++=(*data++) << s; |
349 } |
353 } |
|
354 info->InfoHook(); |
350 return Done(dsPlay); |
355 return Done(dsPlay); |
351 } |
356 } |
352 return Done(dsError); |
357 return Done(dsError); |
353 } |
358 } |
354 |
359 |
355 bool cOggDecoder::Skip(int Seconds, float bsecs) |
360 bool cOggDecoder::Skip(int Seconds, float bsecs) |
356 { |
361 { |
357 Lock(); |
362 Lock(); |
358 bool res=false; |
363 bool res=false; |
359 if(playing && file.CanSeek()) { |
364 if(playing && file->CanSeek()) { |
360 float fsecs=(float)Seconds - bsecs; |
365 float fsecs=(float)Seconds - bsecs; |
361 long long newpos=file.IndexMs()+(long long)(fsecs*1000.0); |
366 long long newpos=file->IndexMs()+(long long)(fsecs*1000.0); |
362 if(newpos<0) newpos=0; |
367 if(newpos<0) newpos=0; |
363 d(printf("ogg: skip: secs=%d fsecs=%f current=%lld new=%lld\n",Seconds,fsecs,file.IndexMs(),newpos)) |
368 d(printf("ogg: skip: secs=%d fsecs=%f current=%lld new=%lld\n",Seconds,fsecs,file->IndexMs(),newpos)) |
364 |
369 |
365 newpos=file.Seek(newpos,false); |
370 newpos=file->Seek(newpos,false); |
366 if(newpos>=0) { |
371 if(newpos>=0) { |
367 index=file.IndexMs(); |
372 index=file->IndexMs(); |
368 #ifdef DEBUG |
373 #ifdef DEBUG |
369 int i=index/1000; |
374 int i=index/1000; |
370 printf("ogg: skipping to %02d:%02d\n",i/60,i%60); |
375 printf("ogg: skipping to %02d:%02d\n",i/60,i%60); |
371 #endif |
376 #endif |
372 res=true; |
377 res=true; |