diff options
-rw-r--r-- | apps/codecs/mpa.c | 35 | ||||
-rw-r--r-- | apps/pcmbuf.c | 31 | ||||
-rw-r--r-- | apps/playback.c | 8 | ||||
-rw-r--r-- | firmware/export/pcm_playback.h | 1 | ||||
-rw-r--r-- | firmware/pcm_playback.c | 24 |
5 files changed, 62 insertions, 37 deletions
diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c index 2c946f3f0d..1be6222ccf 100644 --- a/apps/codecs/mpa.c +++ b/apps/codecs/mpa.c | |||
@@ -72,6 +72,22 @@ void recalc_samplecount(void) | |||
72 | samplecount -= start_skip + stop_skip; | 72 | samplecount -= start_skip + stop_skip; |
73 | } | 73 | } |
74 | 74 | ||
75 | void init_mad(void) | ||
76 | { | ||
77 | ci->memset(&stream, 0, sizeof(struct mad_stream)); | ||
78 | ci->memset(&frame, 0, sizeof(struct mad_frame)); | ||
79 | ci->memset(&synth, 0, sizeof(struct mad_synth)); | ||
80 | |||
81 | mad_stream_init(&stream); | ||
82 | mad_frame_init(&frame); | ||
83 | mad_synth_init(&synth); | ||
84 | |||
85 | /* We do this so libmad doesn't try to call codec_calloc() */ | ||
86 | ci->memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap)); | ||
87 | frame.overlap = &mad_frame_overlap; | ||
88 | stream.main_data = &mad_main_data; | ||
89 | } | ||
90 | |||
75 | /* this is the codec entry point */ | 91 | /* this is the codec entry point */ |
76 | enum codec_status codec_start(struct codec_api *api) | 92 | enum codec_status codec_start(struct codec_api *api) |
77 | { | 93 | { |
@@ -107,18 +123,7 @@ enum codec_status codec_start(struct codec_api *api) | |||
107 | * Reinitializing seems to be necessary to avoid playback quircks when seeking. */ | 123 | * Reinitializing seems to be necessary to avoid playback quircks when seeking. */ |
108 | next_track: | 124 | next_track: |
109 | 125 | ||
110 | ci->memset(&stream, 0, sizeof(struct mad_stream)); | 126 | init_mad(); |
111 | ci->memset(&frame, 0, sizeof(struct mad_frame)); | ||
112 | ci->memset(&synth, 0, sizeof(struct mad_synth)); | ||
113 | |||
114 | mad_stream_init(&stream); | ||
115 | mad_frame_init(&frame); | ||
116 | mad_synth_init(&synth); | ||
117 | |||
118 | /* We do this so libmad doesn't try to call codec_calloc() */ | ||
119 | ci->memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap)); | ||
120 | frame.overlap = &mad_frame_overlap; | ||
121 | stream.main_data = &mad_main_data; | ||
122 | 127 | ||
123 | file_end = 0; | 128 | file_end = 0; |
124 | while (!*ci->taginfo_ready && !ci->stop_codec) | 129 | while (!*ci->taginfo_ready && !ci->stop_codec) |
@@ -168,11 +173,7 @@ enum codec_status codec_start(struct codec_api *api) | |||
168 | if (!ci->seek_buffer(newpos)) | 173 | if (!ci->seek_buffer(newpos)) |
169 | goto next_track; | 174 | goto next_track; |
170 | ci->seek_complete(); | 175 | ci->seek_complete(); |
171 | if (newpos == 0) | 176 | init_mad(); |
172 | { | ||
173 | ci->id3->elapsed = 0; | ||
174 | goto next_track; | ||
175 | } | ||
176 | } | 177 | } |
177 | 178 | ||
178 | /* Lock buffers */ | 179 | /* Lock buffers */ |
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index fc58d9ccb3..e21f735bbb 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c | |||
@@ -60,6 +60,8 @@ static bool crossfade_init; | |||
60 | static int crossfade_pos; | 60 | static int crossfade_pos; |
61 | static int crossfade_rem; | 61 | static int crossfade_rem; |
62 | 62 | ||
63 | static struct mutex pcmbuf_mutex; | ||
64 | |||
63 | /* Crossfade modes. If CFM_CROSSFADE is selected, normal | 65 | /* Crossfade modes. If CFM_CROSSFADE is selected, normal |
64 | * crossfader will activate. Selecting CFM_FLUSH is a special | 66 | * crossfader will activate. Selecting CFM_FLUSH is a special |
65 | * operation that only overwrites the pcm buffer without crossfading. | 67 | * operation that only overwrites the pcm buffer without crossfading. |
@@ -252,7 +254,14 @@ bool pcmbuf_crossfade_init(void) | |||
252 | 254 | ||
253 | void pcmbuf_play_stop(void) | 255 | void pcmbuf_play_stop(void) |
254 | { | 256 | { |
257 | mutex_lock(&pcmbuf_mutex); | ||
258 | |||
259 | /** Prevent a very tiny pop from happening by muting audio | ||
260 | * until dma has been initialized. */ | ||
261 | pcm_mute(true); | ||
255 | pcm_play_stop(); | 262 | pcm_play_stop(); |
263 | pcm_mute(false); | ||
264 | |||
256 | last_chunksize = 0; | 265 | last_chunksize = 0; |
257 | pcmbuf_unplayed_bytes = 0; | 266 | pcmbuf_unplayed_bytes = 0; |
258 | pcmbuf_mix_used_bytes = 0; | 267 | pcmbuf_mix_used_bytes = 0; |
@@ -266,11 +275,13 @@ void pcmbuf_play_stop(void) | |||
266 | 275 | ||
267 | pcmbuf_set_boost_mode(false); | 276 | pcmbuf_set_boost_mode(false); |
268 | pcmbuf_boost(false); | 277 | pcmbuf_boost(false); |
269 | 278 | ||
279 | mutex_unlock(&pcmbuf_mutex); | ||
270 | } | 280 | } |
271 | 281 | ||
272 | void pcmbuf_init(long bufsize) | 282 | void pcmbuf_init(long bufsize) |
273 | { | 283 | { |
284 | mutex_init(&pcmbuf_mutex); | ||
274 | pcmbuf_size = bufsize; | 285 | pcmbuf_size = bufsize; |
275 | audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) - | 286 | audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) - |
276 | pcmbuf_size - PCMBUF_GUARD]; | 287 | pcmbuf_size - PCMBUF_GUARD]; |
@@ -304,7 +315,16 @@ void pcmbuf_flush_audio(void) | |||
304 | void pcmbuf_play_start(void) | 315 | void pcmbuf_play_start(void) |
305 | { | 316 | { |
306 | if (!pcm_is_playing() && pcmbuf_unplayed_bytes) | 317 | if (!pcm_is_playing() && pcmbuf_unplayed_bytes) |
318 | { | ||
319 | /** Prevent a very tiny pop from happening by muting audio | ||
320 | * until dma has been initialized. */ | ||
321 | pcm_mute(true); | ||
322 | |||
307 | pcm_play_data(pcmbuf_callback); | 323 | pcm_play_data(pcmbuf_callback); |
324 | |||
325 | /* Now unmute the audio. */ | ||
326 | pcm_mute(false); | ||
327 | } | ||
308 | } | 328 | } |
309 | 329 | ||
310 | /** | 330 | /** |
@@ -314,6 +334,8 @@ void pcmbuf_flush_fillpos(void) | |||
314 | { | 334 | { |
315 | int copy_n; | 335 | int copy_n; |
316 | 336 | ||
337 | mutex_lock(&pcmbuf_mutex); | ||
338 | |||
317 | copy_n = MIN(audiobuffer_fillpos, CHUNK_SIZE); | 339 | copy_n = MIN(audiobuffer_fillpos, CHUNK_SIZE); |
318 | 340 | ||
319 | if (copy_n) { | 341 | if (copy_n) { |
@@ -324,7 +346,8 @@ void pcmbuf_flush_fillpos(void) | |||
324 | /* This is a fatal error situation that should never happen. */ | 346 | /* This is a fatal error situation that should never happen. */ |
325 | if (!pcm_is_playing()) { | 347 | if (!pcm_is_playing()) { |
326 | logf("pcm_flush_fillpos error"); | 348 | logf("pcm_flush_fillpos error"); |
327 | pcm_play_data(pcmbuf_callback); | 349 | pcmbuf_play_start(); |
350 | mutex_unlock(&pcmbuf_mutex); | ||
328 | return ; | 351 | return ; |
329 | } | 352 | } |
330 | } | 353 | } |
@@ -336,6 +359,8 @@ void pcmbuf_flush_fillpos(void) | |||
336 | audiobuffer_free -= copy_n; | 359 | audiobuffer_free -= copy_n; |
337 | audiobuffer_fillpos -= copy_n; | 360 | audiobuffer_fillpos -= copy_n; |
338 | } | 361 | } |
362 | |||
363 | mutex_unlock(&pcmbuf_mutex); | ||
339 | } | 364 | } |
340 | 365 | ||
341 | /** | 366 | /** |
@@ -576,7 +601,7 @@ static bool prepare_insert(long length) | |||
576 | crossfade_active = false; | 601 | crossfade_active = false; |
577 | if (audiobuffer_free < pcmbuf_size - CHUNK_SIZE*4) { | 602 | if (audiobuffer_free < pcmbuf_size - CHUNK_SIZE*4) { |
578 | logf("pcm starting"); | 603 | logf("pcm starting"); |
579 | pcm_play_data(pcmbuf_callback); | 604 | pcmbuf_play_start(); |
580 | } | 605 | } |
581 | } | 606 | } |
582 | 607 | ||
diff --git a/apps/playback.c b/apps/playback.c index 77a199bd81..779fd97bde 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -294,8 +294,6 @@ bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2, | |||
294 | 294 | ||
295 | while (paused) | 295 | while (paused) |
296 | { | 296 | { |
297 | if (pcm_is_playing()) | ||
298 | pcm_play_pause(false); | ||
299 | sleep(1); | 297 | sleep(1); |
300 | if (ci.stop_codec || ci.reload_codec || ci.seek_time) | 298 | if (ci.stop_codec || ci.reload_codec || ci.seek_time) |
301 | return true; | 299 | return true; |
@@ -1845,15 +1843,15 @@ void audio_thread(void) | |||
1845 | 1843 | ||
1846 | case AUDIO_PAUSE: | 1844 | case AUDIO_PAUSE: |
1847 | logf("audio_pause"); | 1845 | logf("audio_pause"); |
1848 | /* We will pause the pcm playback in audiobuffer insert function | 1846 | pcm_mute(true); |
1849 | to prevent a loop inside the pcm buffer. */ | 1847 | pcm_play_pause(false); |
1850 | // pcm_play_pause(false); | ||
1851 | paused = true; | 1848 | paused = true; |
1852 | break ; | 1849 | break ; |
1853 | 1850 | ||
1854 | case AUDIO_RESUME: | 1851 | case AUDIO_RESUME: |
1855 | logf("audio_resume"); | 1852 | logf("audio_resume"); |
1856 | pcm_play_pause(true); | 1853 | pcm_play_pause(true); |
1854 | pcm_mute(false); | ||
1857 | paused = false; | 1855 | paused = false; |
1858 | break ; | 1856 | break ; |
1859 | 1857 | ||
diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h index 3972e45768..5b61beb34d 100644 --- a/firmware/export/pcm_playback.h +++ b/firmware/export/pcm_playback.h | |||
@@ -29,6 +29,7 @@ void pcm_calculate_peaks(int *left, int *right); | |||
29 | long pcm_get_bytes_waiting(void); | 29 | long pcm_get_bytes_waiting(void); |
30 | 30 | ||
31 | void pcm_play_stop(void); | 31 | void pcm_play_stop(void); |
32 | void pcm_mute(bool mute); | ||
32 | void pcm_play_pause(bool play); | 33 | void pcm_play_pause(bool play); |
33 | bool pcm_is_paused(void); | 34 | bool pcm_is_paused(void); |
34 | bool pcm_is_playing(void); | 35 | bool pcm_is_playing(void); |
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 6a190e4d23..ccac7843ad 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c | |||
@@ -75,11 +75,6 @@ static void dma_start(const void *addr, long size) | |||
75 | EBU1CONFIG = IIS_RESET | EBU_DEFPARM; | 75 | EBU1CONFIG = IIS_RESET | EBU_DEFPARM; |
76 | #endif | 76 | #endif |
77 | 77 | ||
78 | /** Prevent a very tiny pop from happening by muting audio | ||
79 | * until dma has been initialized. */ | ||
80 | uda1380_mute(true); | ||
81 | sleep(HZ/16); | ||
82 | |||
83 | /* Set up DMA transfer */ | 78 | /* Set up DMA transfer */ |
84 | SAR0 = ((unsigned long)addr); /* Source address */ | 79 | SAR0 = ((unsigned long)addr); /* Source address */ |
85 | DAR0 = (unsigned long)&PDOR3; /* Destination address */ | 80 | DAR0 = (unsigned long)&PDOR3; /* Destination address */ |
@@ -92,9 +87,6 @@ static void dma_start(const void *addr, long size) | |||
92 | EBU1CONFIG = EBU_DEFPARM; | 87 | EBU1CONFIG = EBU_DEFPARM; |
93 | #endif | 88 | #endif |
94 | DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_SINC | DMA_START; | 89 | DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_SINC | DMA_START; |
95 | |||
96 | /* Now unmute the audio. */ | ||
97 | uda1380_mute(false); | ||
98 | } | 90 | } |
99 | 91 | ||
100 | /* Stops the DMA transfer and interrupt */ | 92 | /* Stops the DMA transfer and interrupt */ |
@@ -220,14 +212,17 @@ long pcm_get_bytes_waiting(void) | |||
220 | return next_size + (BCR0 & 0xffffff); | 212 | return next_size + (BCR0 & 0xffffff); |
221 | } | 213 | } |
222 | 214 | ||
215 | void pcm_mute(bool mute) | ||
216 | { | ||
217 | uda1380_mute(mute); | ||
218 | if (mute) | ||
219 | sleep(HZ/16); | ||
220 | } | ||
221 | |||
223 | void pcm_play_stop(void) | 222 | void pcm_play_stop(void) |
224 | { | 223 | { |
225 | if (pcm_playing) { | 224 | if (pcm_playing) { |
226 | /* Same muting trick here to prevent a tiny pop. */ | ||
227 | uda1380_mute(true); | ||
228 | sleep(HZ/16); | ||
229 | dma_stop(); | 225 | dma_stop(); |
230 | uda1380_mute(false); | ||
231 | } | 226 | } |
232 | } | 227 | } |
233 | 228 | ||
@@ -465,6 +460,11 @@ void pcm_play_stop(void) | |||
465 | } | 460 | } |
466 | } | 461 | } |
467 | 462 | ||
463 | void pcm_mute(bool mute) | ||
464 | { | ||
465 | (void)mute; | ||
466 | } | ||
467 | |||
468 | void pcm_play_pause(bool play) | 468 | void pcm_play_pause(bool play) |
469 | { | 469 | { |
470 | if(pcm_paused && play && next_size) | 470 | if(pcm_paused && play && next_size) |