summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-08-23 01:37:59 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-08-23 01:37:59 +0000
commit5078d460c678705aa3226fd2768bc85d7b3008ad (patch)
treeb32f638f99de904c4b5b4aee2b1e1b50b8bd77eb
parentfbde6baab59d7c8d047ef267884373d6d9f9e59d (diff)
downloadrockbox-5078d460c678705aa3226fd2768bc85d7b3008ad.tar.gz
rockbox-5078d460c678705aa3226fd2768bc85d7b3008ad.zip
Fix FS#12238 - WPS delay on pause introduced by r30097 which was the excuse I wanted anyway to do a better PCM fade on stop/pause implementation. New fade is asynchronous tick-based. Restores skin update points in the WPS that were removed when fading mechanism was changed.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30340 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/gui/wps.c49
-rw-r--r--apps/pcmbuf.c112
-rw-r--r--apps/pcmbuf.h1
-rw-r--r--apps/playback.c40
4 files changed, 130 insertions, 72 deletions
diff --git a/apps/gui/wps.c b/apps/gui/wps.c
index 80522d04bd..48d9e0912e 100644
--- a/apps/gui/wps.c
+++ b/apps/gui/wps.c
@@ -119,14 +119,28 @@ char* wps_default_skin(enum screen_type screen)
119 return skin_buf[screen]; 119 return skin_buf[screen];
120} 120}
121 121
122static void update_non_static(void)
123{
124 int i;
125 FOR_NB_SCREENS(i)
126 skin_update(WPS, i, SKIN_REFRESH_NON_STATIC);
127}
128
122void pause_action(bool may_fade, bool updatewps) 129void pause_action(bool may_fade, bool updatewps)
123{ 130{
124#if CONFIG_CODEC != SWCODEC 131#if CONFIG_CODEC == SWCODEC
132 /* Do audio first, then update, unless skin were to use its local
133 status in which case, reverse it */
134 audio_pause();
135
136 if (updatewps)
137 update_non_static();
138#else
125 if (may_fade && global_settings.fade_on_stop) 139 if (may_fade && global_settings.fade_on_stop)
126 fade(false, updatewps); 140 fade(false, updatewps);
127 else 141 else
128#endif
129 audio_pause(); 142 audio_pause();
143#endif
130 144
131 if (global_settings.pause_rewind) { 145 if (global_settings.pause_rewind) {
132 long newpos; 146 long newpos;
@@ -139,18 +153,26 @@ void pause_action(bool may_fade, bool updatewps)
139 audio_ff_rewind(newpos > 0 ? newpos : 0); 153 audio_ff_rewind(newpos > 0 ? newpos : 0);
140 } 154 }
141 155
142 (void)may_fade; (void)updatewps; 156 (void)may_fade;
143} 157}
144 158
145void unpause_action(bool may_fade, bool updatewps) 159void unpause_action(bool may_fade, bool updatewps)
146{ 160{
147#if CONFIG_CODEC != SWCODEC 161#if CONFIG_CODEC == SWCODEC
162 /* Do audio first, then update, unless skin were to use its local
163 status in which case, reverse it */
164 audio_resume();
165
166 if (updatewps)
167 update_non_static();
168#else
148 if (may_fade && global_settings.fade_on_stop) 169 if (may_fade && global_settings.fade_on_stop)
149 fade(true, updatewps); 170 fade(true, updatewps);
150 else 171 else
151#endif
152 audio_resume(); 172 audio_resume();
153 (void)may_fade; (void)updatewps; 173#endif
174
175 (void)may_fade;
154} 176}
155 177
156#if CONFIG_CODEC != SWCODEC 178#if CONFIG_CODEC != SWCODEC
@@ -159,7 +181,7 @@ void fade(bool fade_in, bool updatewps)
159 int fp_global_vol = global_settings.volume << 8; 181 int fp_global_vol = global_settings.volume << 8;
160 int fp_min_vol = sound_min(SOUND_VOLUME) << 8; 182 int fp_min_vol = sound_min(SOUND_VOLUME) << 8;
161 int fp_step = (fp_global_vol - fp_min_vol) / 10; 183 int fp_step = (fp_global_vol - fp_min_vol) / 10;
162 int i; 184
163 skin_get_global_state()->is_fading = !fade_in; 185 skin_get_global_state()->is_fading = !fade_in;
164 if (fade_in) { 186 if (fade_in) {
165 /* fade in */ 187 /* fade in */
@@ -171,10 +193,8 @@ void fade(bool fade_in, bool updatewps)
171 sleep(HZ/10); /* let audio thread run */ 193 sleep(HZ/10); /* let audio thread run */
172 audio_resume(); 194 audio_resume();
173 195
174 if (updatewps) { 196 if (updatewps)
175 FOR_NB_SCREENS(i) 197 update_non_static();
176 skin_update(WPS, i, SKIN_REFRESH_NON_STATIC);
177 }
178 198
179 while (fp_volume < fp_global_vol - fp_step) { 199 while (fp_volume < fp_global_vol - fp_step) {
180 fp_volume += fp_step; 200 fp_volume += fp_step;
@@ -187,10 +207,8 @@ void fade(bool fade_in, bool updatewps)
187 /* fade out */ 207 /* fade out */
188 int fp_volume = fp_global_vol; 208 int fp_volume = fp_global_vol;
189 209
190 if (updatewps) { 210 if (updatewps)
191 FOR_NB_SCREENS(i) 211 update_non_static();
192 skin_update(WPS, i, SKIN_REFRESH_NON_STATIC);
193 }
194 212
195 while (fp_volume > fp_min_vol + fp_step) { 213 while (fp_volume > fp_min_vol + fp_step) {
196 fp_volume -= fp_step; 214 fp_volume -= fp_step;
@@ -1140,6 +1158,7 @@ long gui_wps_show(void)
1140 fade(false, true); 1158 fade(false, true);
1141#else 1159#else
1142 audio_pause(); 1160 audio_pause();
1161 update_non_static();
1143#endif 1162#endif
1144 if (bookmark) 1163 if (bookmark)
1145 bookmark_autobookmark(true); 1164 bookmark_autobookmark(true);
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index 2e8bc3f47c..2ba6b6f154 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -91,6 +91,13 @@ static bool track_transition;
91 91
92/* Fade effect */ 92/* Fade effect */
93static unsigned int fade_vol = MIX_AMP_UNITY; 93static unsigned int fade_vol = MIX_AMP_UNITY;
94static enum
95{
96 PCM_NOT_FADING = 0,
97 PCM_FADING_IN,
98 PCM_FADING_OUT,
99} fade_state = PCM_NOT_FADING;
100static bool fade_out_complete = false;
94 101
95/* Voice */ 102/* Voice */
96static bool soft_mode = false; 103static bool soft_mode = false;
@@ -628,8 +635,9 @@ bool pcmbuf_start_track_change(bool auto_skip)
628 * operations involved in sending a new chunk to the DMA. */ 635 * operations involved in sending a new chunk to the DMA. */
629static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) 636static void pcmbuf_pcm_callback(unsigned char** start, size_t* size)
630{ 637{
638 struct chunkdesc *pcmbuf_current = read_chunk;
639
631 { 640 {
632 struct chunkdesc *pcmbuf_current = read_chunk;
633 /* Take the finished chunk out of circulation */ 641 /* Take the finished chunk out of circulation */
634 read_chunk = pcmbuf_current->link; 642 read_chunk = pcmbuf_current->link;
635 643
@@ -657,25 +665,28 @@ static void pcmbuf_pcm_callback(unsigned char** start, size_t* size)
657 665
658 { 666 {
659 /* Commit last samples at end of playlist */ 667 /* Commit last samples at end of playlist */
660 if (pcmbuffer_fillpos && !read_chunk) 668 if (pcmbuffer_fillpos && !pcmbuf_current)
661 { 669 {
662 logf("pcmbuf_pcm_callback: commit last samples"); 670 logf("pcmbuf_pcm_callback: commit last samples");
663 commit_chunk(false); 671 commit_chunk(false);
664 } 672 }
665 } 673 }
666 674
675 /* Stop at this frame */
676 pcmbuf_current = fade_out_complete ? NULL : read_chunk;
677
667 { 678 {
668 /* Send the new chunk to the DMA */ 679 /* Send the new chunk to the DMA */
669 if(read_chunk) 680 if(pcmbuf_current)
670 { 681 {
671 last_chunksize = read_chunk->size; 682 last_chunksize = pcmbuf_current->size;
672 pcmbuf_unplayed_bytes -= last_chunksize; 683 pcmbuf_unplayed_bytes -= last_chunksize;
673 *size = last_chunksize; 684 *size = last_chunksize;
674 *start = read_chunk->addr; 685 *start = pcmbuf_current->addr;
675 } 686 }
676 else 687 else
677 { 688 {
678 /* No more chunks */ 689 /* No more chunks or pause indicated */
679 logf("pcmbuf_pcm_callback: no more chunks"); 690 logf("pcmbuf_pcm_callback: no more chunks");
680 last_chunksize = 0; 691 last_chunksize = 0;
681 *size = 0; 692 *size = 0;
@@ -694,8 +705,8 @@ void pcmbuf_play_start(void)
694 logf("pcmbuf_play_start"); 705 logf("pcmbuf_play_start");
695 last_chunksize = read_chunk->size; 706 last_chunksize = read_chunk->size;
696 pcmbuf_unplayed_bytes -= last_chunksize; 707 pcmbuf_unplayed_bytes -= last_chunksize;
697 mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, 708 mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, pcmbuf_pcm_callback,
698 pcmbuf_pcm_callback, NULL, 0); 709 read_chunk->addr, last_chunksize);
699 } 710 }
700} 711}
701 712
@@ -1087,58 +1098,75 @@ static void pcmbuf_update_volume(void)
1087/* Quiet-down the channel if 'shhh' is true or else play at normal level */ 1098/* Quiet-down the channel if 'shhh' is true or else play at normal level */
1088void pcmbuf_soft_mode(bool shhh) 1099void pcmbuf_soft_mode(bool shhh)
1089{ 1100{
1101 /* "Hate this" alert (messing with IRQ in app code): Have to block
1102 the tick or improper order could leave volume in soft mode if
1103 fading reads the old value first but updates after us. */
1104 int oldlevel = disable_irq_save();
1090 soft_mode = shhh; 1105 soft_mode = shhh;
1091 pcmbuf_update_volume(); 1106 pcmbuf_update_volume();
1107 restore_irq(oldlevel);
1092} 1108}
1093 1109
1094/* Fade channel in or out */ 1110/* Tick that does the fade for the playback channel */
1095void pcmbuf_fade(bool fade, bool in) 1111static void pcmbuf_fade_tick(void)
1096{ 1112{
1097 if (!fade) 1113 /* ~1/3 second for full range fade */
1098 { 1114 const unsigned int fade_step = MIX_AMP_UNITY / (HZ / 3);
1099 /* Simply set the level */ 1115
1100 fade_vol = in ? MIX_AMP_UNITY : MIX_AMP_MUTE; 1116 if (fade_state == PCM_FADING_IN)
1101 } 1117 fade_vol += MIN(fade_step, MIX_AMP_UNITY - fade_vol);
1102 else 1118 else if (fade_state == PCM_FADING_OUT)
1103 { 1119 fade_vol -= MIN(fade_step, fade_vol - MIX_AMP_MUTE);
1104 /* Start from the opposing end */
1105 fade_vol = in ? MIX_AMP_MUTE : MIX_AMP_UNITY;
1106 }
1107 1120
1108 pcmbuf_update_volume(); 1121 pcmbuf_update_volume();
1109 1122
1110 if (fade) 1123 if (fade_vol == MIX_AMP_MUTE || fade_vol == MIX_AMP_UNITY)
1111 { 1124 {
1112 /* Do this on thread for now */ 1125 /* Fade is complete */
1113#ifdef HAVE_PRIORITY_SCHEDULING 1126 tick_remove_task(pcmbuf_fade_tick);
1114 int old_prio = thread_set_priority(thread_self(), PRIORITY_REALTIME);
1115#endif
1116 1127
1117 while (1) 1128 if (fade_state == PCM_FADING_OUT)
1118 { 1129 {
1119 /* Linear fade actually sounds better */ 1130 /* Tell PCM to stop at its earliest convenience */
1120 if (in) 1131 fade_out_complete = true;
1121 fade_vol += MIN(MIX_AMP_UNITY/16, MIX_AMP_UNITY - fade_vol); 1132 }
1122 else
1123 fade_vol -= MIN(MIX_AMP_UNITY/16, fade_vol - MIX_AMP_MUTE);
1124 1133
1125 pcmbuf_update_volume(); 1134 fade_state = PCM_NOT_FADING;
1135 }
1136}
1126 1137
1127 if (fade_vol > MIX_AMP_MUTE && fade_vol < MIX_AMP_UNITY) 1138/* Fade channel in or out in the background - must pause it first */
1128 { 1139void pcmbuf_fade(bool fade, bool in)
1129 sleep(0); 1140{
1130 continue; 1141 pcm_play_lock();
1131 }
1132 1142
1133 break; 1143 if (fade_state != PCM_NOT_FADING)
1134 } 1144 tick_remove_task(pcmbuf_fade_tick);
1135 1145
1136#ifdef HAVE_PRIORITY_SCHEDULING 1146 fade_out_complete = false;
1137 thread_set_priority(thread_self(), old_prio); 1147
1138#endif 1148 pcm_play_unlock();
1149
1150 if (!fade)
1151 {
1152 /* Simply set the level */
1153 fade_state = PCM_NOT_FADING;
1154 fade_vol = in ? MIX_AMP_UNITY : MIX_AMP_MUTE;
1155 pcmbuf_update_volume();
1156 }
1157 else
1158 {
1159 /* Set direction and resume fade from current point */
1160 fade_state = in ? PCM_FADING_IN : PCM_FADING_OUT;
1161 tick_add_task(pcmbuf_fade_tick);
1139 } 1162 }
1140} 1163}
1141 1164
1165/* Return 'true' if fade is in progress */
1166bool pcmbuf_fading(void)
1167{
1168 return fade_state != PCM_NOT_FADING;
1169}
1142 1170
1143/** Misc */ 1171/** Misc */
1144 1172
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h
index b7f5a3c2d6..a5cd3163e1 100644
--- a/apps/pcmbuf.h
+++ b/apps/pcmbuf.h
@@ -65,6 +65,7 @@ unsigned char *pcmbuf_get_meminfo(size_t *length);
65 65
66/* Misc */ 66/* Misc */
67void pcmbuf_fade(bool fade, bool in); 67void pcmbuf_fade(bool fade, bool in);
68bool pcmbuf_fading(void);
68void pcmbuf_soft_mode(bool shhh); 69void pcmbuf_soft_mode(bool shhh);
69bool pcmbuf_is_lowdata(void); 70bool pcmbuf_is_lowdata(void);
70void pcmbuf_set_low_latency(bool state); 71void pcmbuf_set_low_latency(bool state);
diff --git a/apps/playback.c b/apps/playback.c
index a38534a2da..3adf6f6a49 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -1100,6 +1100,14 @@ static void audio_clear_paused_pcm(void)
1100 pcmbuf_play_stop(); 1100 pcmbuf_play_stop();
1101} 1101}
1102 1102
1103/* Wait for any in-progress fade to complete */
1104static void audio_wait_fade_complete(void)
1105{
1106 /* Just loop until it's done */
1107 while (pcmbuf_fading())
1108 sleep(0);
1109}
1110
1103/* End the ff/rw mode */ 1111/* End the ff/rw mode */
1104static void audio_ff_rewind_end(void) 1112static void audio_ff_rewind_end(void)
1105{ 1113{
@@ -2439,7 +2447,12 @@ static void audio_stop_playback(void)
2439 if (play_status == PLAY_STOPPED) 2447 if (play_status == PLAY_STOPPED)
2440 return; 2448 return;
2441 2449
2442 pcmbuf_fade(global_settings.fade_on_stop, false); 2450 bool do_fade = global_settings.fade_on_stop && filling != STATE_ENDED;
2451
2452 pcmbuf_fade(do_fade, false);
2453
2454 /* Wait for fade-out */
2455 audio_wait_fade_complete();
2443 2456
2444 /* Stop the codec and unload it */ 2457 /* Stop the codec and unload it */
2445 halt_decoding_track(true); 2458 halt_decoding_track(true);
@@ -2480,27 +2493,22 @@ static void audio_on_pause(bool pause)
2480 if (play_status == PLAY_STOPPED || pause == (play_status == PLAY_PAUSED)) 2493 if (play_status == PLAY_STOPPED || pause == (play_status == PLAY_PAUSED))
2481 return; 2494 return;
2482 2495
2483 bool const do_fade = global_settings.fade_on_stop; 2496 play_status = pause ? PLAY_PAUSED : PLAY_PLAYING;
2484
2485 if (pause)
2486 pcmbuf_fade(do_fade, false);
2487 2497
2488 if (!ff_rw_mode) 2498 if (!pause && codec_skip_pending)
2489 { 2499 {
2490 /* Not in ff/rw mode - may set the state (otherwise this could make 2500 /* Actually do the skip that is due - resets the status flag */
2491 old data play because seek hasn't completed and cleared it) */ 2501 audio_on_codec_complete(codec_skip_status);
2492 pcmbuf_pause(pause);
2493 } 2502 }
2494 2503
2495 if (!pause) 2504 bool do_fade = global_settings.fade_on_stop;
2496 pcmbuf_fade(do_fade, true);
2497 2505
2498 play_status = pause ? PLAY_PAUSED : PLAY_PLAYING; 2506 pcmbuf_fade(do_fade, !pause);
2499 2507
2500 if (!pause && codec_skip_pending) 2508 if (!ff_rw_mode && !(do_fade && pause))
2501 { 2509 {
2502 /* Actually do the skip that is due - resets the status flag */ 2510 /* Not in ff/rw mode - can actually change the audio state now */
2503 audio_on_codec_complete(codec_skip_status); 2511 pcmbuf_pause(pause);
2504 } 2512 }
2505} 2513}
2506 2514
@@ -2644,6 +2652,8 @@ static void audio_on_pre_ff_rewind(void)
2644 2652
2645 ff_rw_mode = true; 2653 ff_rw_mode = true;
2646 2654
2655 audio_wait_fade_complete();
2656
2647 if (play_status == PLAY_PAUSED) 2657 if (play_status == PLAY_PAUSED)
2648 return; 2658 return;
2649 2659