summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-07-02 11:55:38 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-07-02 11:55:38 +0000
commit22b6def065ab7c2ca030f405577e34104ad20011 (patch)
tree6be548bf591d2365077b74679048737fe51792a2
parent8c954e28b75b47543f69abe2c169d83ad38c26ae (diff)
downloadrockbox-22b6def065ab7c2ca030f405577e34104ad20011.tar.gz
rockbox-22b6def065ab7c2ca030f405577e34104ad20011.zip
Use playback channel directly for peakmeters and plugins using peak calculation. Also, for now, don't allow mixer playback to overlap recording, even if full duplex works.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30119 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugin.c1
-rw-r--r--apps/plugin.h4
-rw-r--r--apps/plugins/oscilloscope.c3
-rw-r--r--apps/plugins/starfield.c3
-rw-r--r--apps/plugins/vu_meter.c3
-rw-r--r--apps/recorder/peakmeter.c4
-rw-r--r--firmware/export/pcm-internal.h10
-rw-r--r--firmware/export/pcm_mixer.h4
-rw-r--r--firmware/pcm.c53
-rw-r--r--firmware/pcm_mixer.c28
10 files changed, 81 insertions, 32 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index bfb7f0e9c1..6b3d39973f 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -781,6 +781,7 @@ static const struct plugin_api rockbox_api = {
781#if CONFIG_CODEC == SWCODEC 781#if CONFIG_CODEC == SWCODEC
782 mixer_channel_status, 782 mixer_channel_status,
783 mixer_channel_get_buffer, 783 mixer_channel_get_buffer,
784 mixer_channel_calculate_peaks,
784#endif 785#endif
785}; 786};
786 787
diff --git a/apps/plugin.h b/apps/plugin.h
index aa39829daf..77c8e831d4 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -146,7 +146,7 @@ void* plugin_get_buffer(size_t *buffer_size);
146#define PLUGIN_MAGIC 0x526F634B /* RocK */ 146#define PLUGIN_MAGIC 0x526F634B /* RocK */
147 147
148/* increase this every time the api struct changes */ 148/* increase this every time the api struct changes */
149#define PLUGIN_API_VERSION 206 149#define PLUGIN_API_VERSION 207
150 150
151/* update this to latest version if a change to the api struct breaks 151/* update this to latest version if a change to the api struct breaks
152 backwards compatibility (and please take the opportunity to sort in any 152 backwards compatibility (and please take the opportunity to sort in any
@@ -911,6 +911,8 @@ struct plugin_api {
911#if CONFIG_CODEC == SWCODEC 911#if CONFIG_CODEC == SWCODEC
912 enum channel_status (*mixer_channel_status)(enum pcm_mixer_channel channel); 912 enum channel_status (*mixer_channel_status)(enum pcm_mixer_channel channel);
913 void * (*mixer_channel_get_buffer)(enum pcm_mixer_channel channel, int *count); 913 void * (*mixer_channel_get_buffer)(enum pcm_mixer_channel channel, int *count);
914 void (*mixer_channel_calculate_peaks)(enum pcm_mixer_channel channel,
915 int *left, int *right);
914#endif 916#endif
915}; 917};
916 918
diff --git a/apps/plugins/oscilloscope.c b/apps/plugins/oscilloscope.c
index 07bf1da8bb..5eb43fae62 100644
--- a/apps/plugins/oscilloscope.c
+++ b/apps/plugins/oscilloscope.c
@@ -826,7 +826,8 @@ enum plugin_status plugin_start(const void* parameter)
826 left = rb->mas_codec_readreg(0xC); 826 left = rb->mas_codec_readreg(0xC);
827 right = rb->mas_codec_readreg(0xD); 827 right = rb->mas_codec_readreg(0xD);
828#elif (CONFIG_CODEC == SWCODEC) 828#elif (CONFIG_CODEC == SWCODEC)
829 rb->pcm_calculate_peaks(&left, &right); 829 rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
830 &left, &right);
830#endif 831#endif
831 if (osc.orientation == OSC_HORIZ) 832 if (osc.orientation == OSC_HORIZ)
832 anim_horizontal(left, right); 833 anim_horizontal(left, right);
diff --git a/apps/plugins/starfield.c b/apps/plugins/starfield.c
index 5e832aa38a..e7bbb425be 100644
--- a/apps/plugins/starfield.c
+++ b/apps/plugins/starfield.c
@@ -422,7 +422,8 @@ int plugin_main(void)
422 /* Get the peaks. ( Borrowed from vu_meter ) */ 422 /* Get the peaks. ( Borrowed from vu_meter ) */
423#if (CONFIG_CODEC == SWCODEC) 423#if (CONFIG_CODEC == SWCODEC)
424 int left_peak, right_peak; 424 int left_peak, right_peak;
425 rb->pcm_calculate_peaks(&left_peak, &right_peak); 425 rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
426 &left_peak, &right_peak);
426#else 427#else
427 int left_peak = rb->mas_codec_readreg(0xC); 428 int left_peak = rb->mas_codec_readreg(0xC);
428 int right_peak = rb->mas_codec_readreg(0xD); 429 int right_peak = rb->mas_codec_readreg(0xD);
diff --git a/apps/plugins/vu_meter.c b/apps/plugins/vu_meter.c
index 5266214723..cb1a035678 100644
--- a/apps/plugins/vu_meter.c
+++ b/apps/plugins/vu_meter.c
@@ -660,7 +660,8 @@ void analog_meter(void) {
660 int right_peak = rb->mas_codec_readreg(0xD); 660 int right_peak = rb->mas_codec_readreg(0xD);
661#elif (CONFIG_CODEC == SWCODEC) 661#elif (CONFIG_CODEC == SWCODEC)
662 int left_peak, right_peak; 662 int left_peak, right_peak;
663 rb->pcm_calculate_peaks(&left_peak, &right_peak); 663 rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
664 &left_peak, &right_peak);
664#endif 665#endif
665 666
666 if(vumeter_settings.analog_use_db_scale) { 667 if(vumeter_settings.analog_use_db_scale) {
diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c
index c13c4c9539..fd8f8d9fbe 100644
--- a/apps/recorder/peakmeter.c
+++ b/apps/recorder/peakmeter.c
@@ -44,6 +44,7 @@
44 44
45#if CONFIG_CODEC == SWCODEC 45#if CONFIG_CODEC == SWCODEC
46#include "pcm.h" 46#include "pcm.h"
47#include "pcm_mixer.h"
47 48
48#ifdef HAVE_RECORDING 49#ifdef HAVE_RECORDING
49#include "pcm_record.h" 50#include "pcm_record.h"
@@ -620,7 +621,8 @@ void peak_meter_peek(void)
620 /* read current values */ 621 /* read current values */
621#if CONFIG_CODEC == SWCODEC 622#if CONFIG_CODEC == SWCODEC
622 if (pm_playback) 623 if (pm_playback)
623 pcm_calculate_peaks(&pm_cur_left, &pm_cur_right); 624 mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
625 &pm_cur_left, &pm_cur_right);
624#ifdef HAVE_RECORDING 626#ifdef HAVE_RECORDING
625 else 627 else
626 pcm_calculate_rec_peaks(&pm_cur_left, &pm_cur_right); 628 pcm_calculate_rec_peaks(&pm_cur_left, &pm_cur_right);
diff --git a/firmware/export/pcm-internal.h b/firmware/export/pcm-internal.h
index d69138f534..bae6a368fa 100644
--- a/firmware/export/pcm-internal.h
+++ b/firmware/export/pcm-internal.h
@@ -22,6 +22,16 @@
22#ifndef PCM_INTERNAL_H 22#ifndef PCM_INTERNAL_H
23#define PCM_INTERNAL_H 23#define PCM_INTERNAL_H
24 24
25struct pcm_peaks
26{
27 long period;
28 long tick;
29 uint16_t val[2];
30};
31
32void pcm_do_peak_calculation(struct pcm_peaks *peaks, bool active,
33 const void *addr, int count);
34
25/** The following are for internal use between pcm.c and target- 35/** The following are for internal use between pcm.c and target-
26 specific portion **/ 36 specific portion **/
27 37
diff --git a/firmware/export/pcm_mixer.h b/firmware/export/pcm_mixer.h
index 9c4e06e0be..be10601ffd 100644
--- a/firmware/export/pcm_mixer.h
+++ b/firmware/export/pcm_mixer.h
@@ -103,6 +103,10 @@ size_t mixer_channel_get_bytes_waiting(enum pcm_mixer_channel channel);
103/* Return pointer to channel's playing audio data and the size remaining */ 103/* Return pointer to channel's playing audio data and the size remaining */
104void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count); 104void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count);
105 105
106/* Calculate peak values for channel */
107void mixer_channel_calculate_peaks(enum pcm_mixer_channel channel,
108 int *left, int *right);
109
106/* Stop ALL channels and PCM and reset state */ 110/* Stop ALL channels and PCM and reset state */
107void mixer_reset(void); 111void mixer_reset(void);
108 112
diff --git a/firmware/pcm.c b/firmware/pcm.c
index b7415f329b..c2ebc67687 100644
--- a/firmware/pcm.c
+++ b/firmware/pcm.c
@@ -93,6 +93,9 @@ unsigned long pcm_sampr SHAREDBSS_ATTR = HW_SAMPR_DEFAULT;
93/* samplerate frequency selection index */ 93/* samplerate frequency selection index */
94int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT; 94int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT;
95 95
96/* peak data for the global peak values - i.e. what the final output is */
97static struct pcm_peaks global_peaks;
98
96/* Called internally by functions to reset the state */ 99/* Called internally by functions to reset the state */
97static void pcm_play_stopped(void) 100static void pcm_play_stopped(void)
98{ 101{
@@ -107,7 +110,7 @@ static void pcm_play_stopped(void)
107 * 110 *
108 * Used for recording and playback. 111 * Used for recording and playback.
109 */ 112 */
110static void pcm_peak_peeker(const int32_t *addr, int count, int peaks[2]) 113static void pcm_peak_peeker(const int32_t *addr, int count, uint16_t peaks[2])
111{ 114{
112 int peak_l = 0, peak_r = 0; 115 int peak_l = 0, peak_r = 0;
113 const int32_t * const end = addr + count; 116 const int32_t * const end = addr + count;
@@ -145,18 +148,13 @@ static void pcm_peak_peeker(const int32_t *addr, int count, int peaks[2])
145 peaks[1] = peak_r; 148 peaks[1] = peak_r;
146} 149}
147 150
148void pcm_calculate_peaks(int *left, int *right) 151void pcm_do_peak_calculation(struct pcm_peaks *peaks, bool active,
152 const void *addr, int count)
149{ 153{
150 static int peaks[2] = { 0, 0 };
151 static unsigned long last_peak_tick = 0;
152 static unsigned long frame_period = 0;
153
154 long tick = current_tick; 154 long tick = current_tick;
155 int count;
156 const void *addr;
157 155
158 /* Throttled peak ahead based on calling period */ 156 /* Peak no farther ahead than expected period to avoid overcalculation */
159 long period = tick - last_peak_tick; 157 long period = tick - peaks->tick;
160 158
161 /* Keep reasonable limits on period */ 159 /* Keep reasonable limits on period */
162 if (period < 1) 160 if (period < 1)
@@ -164,33 +162,38 @@ void pcm_calculate_peaks(int *left, int *right)
164 else if (period > HZ/5) 162 else if (period > HZ/5)
165 period = HZ/5; 163 period = HZ/5;
166 164
167 frame_period = (3*frame_period + period) >> 2; 165 peaks->period = (3*peaks->period + period) >> 2;
168 166 peaks->tick = tick;
169 last_peak_tick = tick;
170 167
171 addr = pcm_play_dma_get_peak_buffer(&count); 168 if (active)
172
173 if (pcm_playing && !pcm_paused)
174 { 169 {
175 int framecount; 170 int framecount = peaks->period*pcm_curr_sampr / HZ;
176
177 framecount = frame_period*pcm_curr_sampr / HZ;
178 count = MIN(framecount, count); 171 count = MIN(framecount, count);
179 172
180 if (count > 0) 173 if (count > 0)
181 pcm_peak_peeker((int32_t *)addr, count, peaks); 174 pcm_peak_peeker((int32_t *)addr, count, peaks->val);
182 /* else keep previous peak values */ 175 /* else keep previous peak values */
183 } 176 }
184 else 177 else
185 { 178 {
186 peaks[0] = peaks[1] = 0; 179 /* peaks are zero */
180 peaks->val[0] = peaks->val[1] = 0;
187 } 181 }
182}
183
184void pcm_calculate_peaks(int *left, int *right)
185{
186 int count;
187 const void *addr = pcm_play_dma_get_peak_buffer(&count);
188
189 pcm_do_peak_calculation(&global_peaks, pcm_playing && !pcm_paused,
190 addr, count);
188 191
189 if (left) 192 if (left)
190 *left = peaks[0]; 193 *left = global_peaks.val[0];
191 194
192 if (right) 195 if (right)
193 *right = peaks[1]; 196 *right = global_peaks.val[1];
194} 197}
195 198
196const void* pcm_get_peak_buffer(int * count) 199const void* pcm_get_peak_buffer(int * count)
@@ -437,7 +440,7 @@ static void pcm_recording_stopped(void)
437 */ 440 */
438void pcm_calculate_rec_peaks(int *left, int *right) 441void pcm_calculate_rec_peaks(int *left, int *right)
439{ 442{
440 static int peaks[2]; 443 static uint16_t peaks[2];
441 444
442 if (pcm_recording) 445 if (pcm_recording)
443 { 446 {
@@ -484,10 +487,8 @@ void pcm_init_recording(void)
484{ 487{
485 logf("pcm_init_recording"); 488 logf("pcm_init_recording");
486 489
487#ifndef HAVE_PCM_FULL_DUPLEX
488 /* Stop the beasty before attempting recording */ 490 /* Stop the beasty before attempting recording */
489 mixer_reset(); 491 mixer_reset();
490#endif
491 492
492 /* Recording init is locked unlike general pcm init since this is not 493 /* Recording init is locked unlike general pcm init since this is not
493 * just a one-time event at startup and it should and must be safe by 494 * just a one-time event at startup and it should and must be safe by
diff --git a/firmware/pcm_mixer.c b/firmware/pcm_mixer.c
index 69a43cfbda..c84762938e 100644
--- a/firmware/pcm_mixer.c
+++ b/firmware/pcm_mixer.c
@@ -23,6 +23,7 @@
23#include "general.h" 23#include "general.h"
24#include "kernel.h" 24#include "kernel.h"
25#include "pcm.h" 25#include "pcm.h"
26#include "pcm-internal.h"
26#include "pcm_mixer.h" 27#include "pcm_mixer.h"
27#include "dsp.h" 28#include "dsp.h"
28 29
@@ -59,6 +60,9 @@ static size_t next_size = 0; /* Size of buffer to play next time */
59/* Descriptors for all available channels */ 60/* Descriptors for all available channels */
60static struct mixer_channel channels[PCM_MIXER_NUM_CHANNELS] IBSS_ATTR; 61static struct mixer_channel channels[PCM_MIXER_NUM_CHANNELS] IBSS_ATTR;
61 62
63/* History for channel peaks */
64static struct pcm_peaks channel_peaks[PCM_MIXER_NUM_CHANNELS];
65
62/* Packed pointer array of all playing (active) channels in "channels" array */ 66/* Packed pointer array of all playing (active) channels in "channels" array */
63static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR; 67static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR;
64 68
@@ -343,11 +347,14 @@ static void mixer_start_pcm(void)
343 if (pcm_is_playing()) 347 if (pcm_is_playing())
344 return; 348 return;
345 349
346#if defined(HAVE_RECORDING) && !defined(HAVE_PCM_FULL_DUPLEX) 350#if defined(HAVE_RECORDING)
347 if (pcm_is_recording()) 351 if (pcm_is_recording())
348 return; 352 return;
349#endif 353#endif
350 354
355 /* Requires a shared global sample rate for all channels */
356 pcm_set_frequency(NATIVE_FREQUENCY);
357
351 /* Prepare initial frames and set up the double buffer */ 358 /* Prepare initial frames and set up the double buffer */
352 mixer_buffer_callback(); 359 mixer_buffer_callback();
353 360
@@ -492,6 +499,25 @@ void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count)
492 return NULL; 499 return NULL;
493} 500}
494 501
502/* Calculate peak values for channel */
503void mixer_channel_calculate_peaks(enum pcm_mixer_channel channel,
504 int *left, int *right)
505{
506 struct mixer_channel *chan = &channels[channel];
507 struct pcm_peaks *peaks = &channel_peaks[channel];
508 int count;
509 const void *addr = mixer_channel_get_buffer(channel, &count);
510
511 pcm_do_peak_calculation(peaks, chan->status == CHANNEL_PLAYING,
512 addr, count);
513
514 if (left)
515 *left = peaks->val[0];
516
517 if (right)
518 *right = peaks->val[1];
519}
520
495/* Stop ALL channels and PCM and reset state */ 521/* Stop ALL channels and PCM and reset state */
496void mixer_reset(void) 522void mixer_reset(void)
497{ 523{