summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/playback.c109
-rw-r--r--apps/plugins/codecvorbis.c3
-rw-r--r--firmware/export/pcm_playback.h1
-rw-r--r--firmware/pcm_playback.c19
4 files changed, 110 insertions, 22 deletions
diff --git a/apps/playback.c b/apps/playback.c
index 6751266d7f..d1678a89e1 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -114,11 +114,11 @@ char *codecbuf;
114int codecbuflen; 114int codecbuflen;
115 115
116/* Bytes available in the buffer. */ 116/* Bytes available in the buffer. */
117volatile int codecbufused; 117static volatile int codecbufused;
118 118
119/* Ring buffer read and write indexes. */ 119/* Ring buffer read and write indexes. */
120static int buf_ridx; 120static volatile int buf_ridx;
121static int buf_widx; 121static volatile int buf_widx;
122 122
123#define MAX_TRACK 10 123#define MAX_TRACK 10
124struct track_info { 124struct track_info {
@@ -140,8 +140,8 @@ struct track_info {
140/* Track information (count in file buffer, read/write indexes for 140/* Track information (count in file buffer, read/write indexes for
141 track ring structure. */ 141 track ring structure. */
142static int track_count; 142static int track_count;
143static int track_ridx; 143static volatile int track_ridx;
144static int track_widx; 144static volatile int track_widx;
145static bool track_changed; 145static bool track_changed;
146 146
147/* Playlist position to tell the next track. */ 147/* Playlist position to tell the next track. */
@@ -224,7 +224,6 @@ size_t codec_filebuf_callback(void *ptr, size_t size)
224 part_n = MIN(copy_n, codecbuflen - buf_ridx); 224 part_n = MIN(copy_n, codecbuflen - buf_ridx);
225 memcpy(buf, &codecbuf[buf_ridx], part_n); 225 memcpy(buf, &codecbuf[buf_ridx], part_n);
226 if (part_n < copy_n) { 226 if (part_n < copy_n) {
227 part_n = copy_n - part_n;
228 memcpy(&buf[part_n], &codecbuf[0], copy_n - part_n); 227 memcpy(&buf[part_n], &codecbuf[0], copy_n - part_n);
229 } 228 }
230 229
@@ -293,6 +292,8 @@ void codec_advance_buffer_loc_callback(void *ptr)
293 codec_advance_buffer_callback(amount); 292 codec_advance_buffer_callback(amount);
294} 293}
295 294
295int mp3_get_file_pos(void);
296
296off_t codec_mp3_get_filepos_callback(int newtime) 297off_t codec_mp3_get_filepos_callback(int newtime)
297{ 298{
298 int oldtime; 299 int oldtime;
@@ -300,7 +301,7 @@ off_t codec_mp3_get_filepos_callback(int newtime)
300 301
301 oldtime = cur_ti->id3.elapsed; 302 oldtime = cur_ti->id3.elapsed;
302 cur_ti->id3.elapsed = newtime; 303 cur_ti->id3.elapsed = newtime;
303 newpos = audio_get_file_pos(); 304 newpos = mp3_get_file_pos();
304 cur_ti->id3.elapsed = oldtime; 305 cur_ti->id3.elapsed = oldtime;
305 306
306 return newpos; 307 return newpos;
@@ -394,6 +395,18 @@ int probe_file_format(const char *filename)
394 395
395} 396}
396 397
398void yield_codecs(void)
399{
400#ifndef SIMULATOR
401 if (!pcm_is_playing())
402 sleep(5);
403 while (pcm_is_lowdata())
404 yield();
405#else
406 yield();
407#endif
408}
409
397void audio_fill_file_buffer(void) 410void audio_fill_file_buffer(void)
398{ 411{
399 size_t i; 412 size_t i;
@@ -402,7 +415,9 @@ void audio_fill_file_buffer(void)
402 logf("Filling buffer..."); 415 logf("Filling buffer...");
403 i = 0; 416 i = 0;
404 while ((off_t)i < tracks[track_widx].filerem) { 417 while ((off_t)i < tracks[track_widx].filerem) {
405 sleep(5); /* Give codecs some processing time. */ 418 /* Give codecs some processing time. */
419 yield_codecs();
420
406 if (!playing) { 421 if (!playing) {
407 logf("Filling interrupted"); 422 logf("Filling interrupted");
408 close(current_fd); 423 close(current_fd);
@@ -413,13 +428,13 @@ void audio_fill_file_buffer(void)
413 if (fill_bytesleft < MIN(AUDIO_FILE_CHUNK, 428 if (fill_bytesleft < MIN(AUDIO_FILE_CHUNK,
414 tracks[track_widx].filerem - i)) 429 tracks[track_widx].filerem - i))
415 break ; 430 break ;
416
417 rc = MIN(AUDIO_FILE_CHUNK, codecbuflen - buf_widx); 431 rc = MIN(AUDIO_FILE_CHUNK, codecbuflen - buf_widx);
418 rc = read(current_fd, &codecbuf[buf_widx], rc); 432 rc = read(current_fd, &codecbuf[buf_widx], rc);
419 if (rc <= 0) { 433 if (rc <= 0) {
420 tracks[track_widx].filerem = 0; 434 tracks[track_widx].filerem = 0;
421 break ; 435 break ;
422 } 436 }
437
423 buf_widx += rc; 438 buf_widx += rc;
424 if (buf_widx == codecbuflen) 439 if (buf_widx == codecbuflen)
425 buf_widx = 0; 440 buf_widx = 0;
@@ -521,7 +536,7 @@ bool loadcodec(const char *trackname, bool start_play)
521 536
522 i = 0; 537 i = 0;
523 while (i < size) { 538 while (i < size) {
524 yield(); 539 yield_codecs();
525 if (!playing) { 540 if (!playing) {
526 logf("Buffering interrupted"); 541 logf("Buffering interrupted");
527 close(fd); 542 close(fd);
@@ -616,7 +631,7 @@ bool audio_load_track(int offset, bool start_play)
616 i = 0; 631 i = 0;
617 while (i < size) { 632 while (i < size) {
618 /* Give codecs some processing time to prevent glitches. */ 633 /* Give codecs some processing time to prevent glitches. */
619 sleep(5); 634 yield_codecs();
620 if (!playing) { 635 if (!playing) {
621 logf("Buffering interrupted"); 636 logf("Buffering interrupted");
622 close(fd); 637 close(fd);
@@ -635,7 +650,7 @@ bool audio_load_track(int offset, bool start_play)
635 return false; 650 return false;
636 } 651 }
637 buf_widx += rc; 652 buf_widx += rc;
638 if (buf_widx == codecbuflen) 653 if (buf_widx >= codecbuflen)
639 buf_widx = 0; 654 buf_widx = 0;
640 i += rc; 655 i += rc;
641 tracks[track_widx].available += rc; 656 tracks[track_widx].available += rc;
@@ -731,6 +746,7 @@ void audio_check_buffer(void)
731 for (i = 0; i < MAX_TRACK - track_count; i++) { 746 for (i = 0; i < MAX_TRACK - track_count; i++) {
732 if (++cur_idx >= MAX_TRACK) 747 if (++cur_idx >= MAX_TRACK)
733 cur_idx = 0; 748 cur_idx = 0;
749 tracks[cur_idx].filesize = 0;
734 tracks[cur_idx].available = 0; 750 tracks[cur_idx].available = 0;
735 } 751 }
736 752
@@ -806,7 +822,7 @@ bool codec_request_next_track_callback(void)
806 if (ci.reload_codec && new_track > 0) { 822 if (ci.reload_codec && new_track > 0) {
807 if (++track_ridx == MAX_TRACK) 823 if (++track_ridx == MAX_TRACK)
808 track_ridx = 0; 824 track_ridx = 0;
809 if (track_ridx == track_widx && tracks[track_ridx].filerem == 0) { 825 if (tracks[track_ridx].filesize == 0) {
810 logf("Loading from disk..."); 826 logf("Loading from disk...");
811 new_track = 0; 827 new_track = 0;
812 queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset)); 828 queue_post(&audio_queue, AUDIO_PLAY, (void *)(last_offset));
@@ -820,7 +836,7 @@ bool codec_request_next_track_callback(void)
820 track_ridx = MAX_TRACK-1; 836 track_ridx = MAX_TRACK-1;
821 if (tracks[track_ridx].filesize == 0 || 837 if (tracks[track_ridx].filesize == 0 ||
822 codecbufused+ci.curpos+tracks[track_ridx].filesize 838 codecbufused+ci.curpos+tracks[track_ridx].filesize
823 + (off_t)tracks[track_ridx].codecsize > codecbuflen) { 839 /*+ (off_t)tracks[track_ridx].codecsize*/ > codecbuflen) {
824 logf("Loading from disk..."); 840 logf("Loading from disk...");
825 last_offset -= track_count; 841 last_offset -= track_count;
826 if (last_offset < 0) 842 if (last_offset < 0)
@@ -946,7 +962,7 @@ void codec_thread(void)
946 break ; 962 break ;
947 } 963 }
948 codecbufused -=codecsize; 964 codecbufused -=codecsize;
949 cur_ti->codecsize = 0; 965 // cur_ti->codecsize = 0;
950 966
951 ci.stop_codec = false; 967 ci.stop_codec = false;
952 wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf; 968 wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf;
@@ -1136,6 +1152,68 @@ int audio_get_file_pos(void)
1136 return 0; 1152 return 0;
1137} 1153}
1138 1154
1155
1156/* Copied from mpeg.c. Should be moved somewhere else. */
1157int mp3_get_file_pos(void)
1158{
1159 int pos = -1;
1160 struct mp3entry *id3 = audio_current_track();
1161
1162 if (id3->vbr)
1163 {
1164 if (id3->has_toc)
1165 {
1166 /* Use the TOC to find the new position */
1167 unsigned int percent, remainder;
1168 int curtoc, nexttoc, plen;
1169
1170 percent = (id3->elapsed*100)/id3->length;
1171 if (percent > 99)
1172 percent = 99;
1173
1174 curtoc = id3->toc[percent];
1175
1176 if (percent < 99)
1177 nexttoc = id3->toc[percent+1];
1178 else
1179 nexttoc = 256;
1180
1181 pos = (id3->filesize/256)*curtoc;
1182
1183 /* Use the remainder to get a more accurate position */
1184 remainder = (id3->elapsed*100)%id3->length;
1185 remainder = (remainder*100)/id3->length;
1186 plen = (nexttoc - curtoc)*(id3->filesize/256);
1187 pos += (plen/100)*remainder;
1188 }
1189 else
1190 {
1191 /* No TOC exists, estimate the new position */
1192 pos = (id3->filesize / (id3->length / 1000)) *
1193 (id3->elapsed / 1000);
1194 }
1195 }
1196 else if (id3->bpf && id3->tpf)
1197 pos = (id3->elapsed/id3->tpf)*id3->bpf;
1198 else
1199 {
1200 return -1;
1201 }
1202
1203 if (pos >= (int)(id3->filesize - id3->id3v1len))
1204 {
1205 /* Don't seek right to the end of the file so that we can
1206 transition properly to the next song */
1207 pos = id3->filesize - id3->id3v1len - 1;
1208 }
1209 else if (pos < (int)id3->first_frame_offset)
1210 {
1211 /* skip past id3v2 tag and other leading garbage */
1212 pos = id3->first_frame_offset;
1213 }
1214 return pos;
1215}
1216
1139#ifndef SIMULATOR 1217#ifndef SIMULATOR
1140void audio_set_buffer_margin(int seconds) 1218void audio_set_buffer_margin(int seconds)
1141{ 1219{
@@ -1181,6 +1259,7 @@ void audio_init(void)
1181 ci.seek_buffer = codec_seek_buffer_callback; 1259 ci.seek_buffer = codec_seek_buffer_callback;
1182 ci.set_elapsed = codec_set_elapsed_callback; 1260 ci.set_elapsed = codec_set_elapsed_callback;
1183 1261
1262 queue_init(&audio_queue);
1184 queue_init(&codec_queue); 1263 queue_init(&codec_queue);
1185 1264
1186 create_thread(codec_thread, codec_stack, sizeof(codec_stack), 1265 create_thread(codec_thread, codec_stack, sizeof(codec_stack),
diff --git a/apps/plugins/codecvorbis.c b/apps/plugins/codecvorbis.c
index 41db223494..2fcc031ce5 100644
--- a/apps/plugins/codecvorbis.c
+++ b/apps/plugins/codecvorbis.c
@@ -106,6 +106,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
106 106
107 /* This function sets up the buffers and reads the file into RAM */ 107 /* This function sets up the buffers and reads the file into RAM */
108 108
109 /* We need to flush reserver memory every track load. */
110 next_track:
109 if (codec_init(api, ci)) { 111 if (codec_init(api, ci)) {
110 return PLUGIN_ERROR; 112 return PLUGIN_ERROR;
111 } 113 }
@@ -118,7 +120,6 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
118 callbacks.tell_func=tell_handler; 120 callbacks.tell_func=tell_handler;
119 callbacks.close_func=close_handler; 121 callbacks.close_func=close_handler;
120 122
121 next_track:
122 error=ov_open_callbacks(ci,&vf,NULL,0,callbacks); 123 error=ov_open_callbacks(ci,&vf,NULL,0,callbacks);
123 124
124 vi=ov_info(&vf,-1); 125 vi=ov_info(&vf,-1);
diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h
index f83443b3e9..3c29018394 100644
--- a/firmware/export/pcm_playback.h
+++ b/firmware/export/pcm_playback.h
@@ -41,6 +41,7 @@ int pcm_play_num_used_buffers(void);
41void pcm_play_set_watermark(int numbytes, void (*callback)(int bytes_left)); 41void pcm_play_set_watermark(int numbytes, void (*callback)(int bytes_left));
42 42
43void pcm_set_boost_mode(bool state); 43void pcm_set_boost_mode(bool state);
44bool pcm_is_lowdata(void);
44unsigned int audiobuffer_get_latency(void); 45unsigned int audiobuffer_get_latency(void);
45bool audiobuffer_insert(char *buf, size_t length); 46bool audiobuffer_insert(char *buf, size_t length);
46 47
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c
index 318cfd4aa0..61573e6602 100644
--- a/firmware/pcm_playback.c
+++ b/firmware/pcm_playback.c
@@ -211,8 +211,7 @@ void pcm_play_data(const unsigned char* start, int size,
211 callback_for_more = get_more; 211 callback_for_more = get_more;
212 dma_start(start, size); 212 dma_start(start, size);
213 213
214 if (get_more == pcm_play_callback) 214 get_more(&next_start, &next_size);
215 get_more(&next_start, &next_size);
216} 215}
217 216
218void pcm_play_stop(void) 217void pcm_play_stop(void)
@@ -256,7 +255,6 @@ void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
256void DMA0(void) 255void DMA0(void)
257{ 256{
258 int res = DSR0; 257 int res = DSR0;
259 bool rockboy = callback_for_more != pcm_play_callback;
260 258
261 DSR0 = 1; /* Clear interrupt */ 259 DSR0 = 1; /* Clear interrupt */
262 260
@@ -267,13 +265,11 @@ void DMA0(void)
267 } 265 }
268 else 266 else
269 { 267 {
270 if (callback_for_more && rockboy)
271 callback_for_more(&next_start, &next_size);
272 if(next_size) 268 if(next_size)
273 { 269 {
274 SAR0 = (unsigned long)next_start; /* Source address */ 270 SAR0 = (unsigned long)next_start; /* Source address */
275 BCR0 = next_size; /* Bytes to transfer */ 271 BCR0 = next_size; /* Bytes to transfer */
276 if (callback_for_more && !rockboy) 272 if (callback_for_more)
277 callback_for_more(&next_start, &next_size); 273 callback_for_more(&next_start, &next_size);
278 } 274 }
279 else 275 else
@@ -366,6 +362,17 @@ unsigned int audiobuffer_get_latency(void)
366 return latency; 362 return latency;
367} 363}
368 364
365bool pcm_is_lowdata(void)
366{
367 if (!pcm_is_playing())
368 return false;
369
370 if (PCMBUF_SIZE - audiobuffer_free <= PCM_WATERMARK)
371 return true;
372
373 return false;
374}
375
369bool audiobuffer_insert(char *buf, size_t length) 376bool audiobuffer_insert(char *buf, size_t length)
370{ 377{
371 size_t copy_n = 0; 378 size_t copy_n = 0;