diff options
-rw-r--r-- | apps/plugin.c | 1 | ||||
-rw-r--r-- | apps/plugin.h | 4 | ||||
-rw-r--r-- | apps/plugins/oscilloscope.c | 3 | ||||
-rw-r--r-- | apps/plugins/starfield.c | 3 | ||||
-rw-r--r-- | apps/plugins/vu_meter.c | 3 | ||||
-rw-r--r-- | apps/recorder/peakmeter.c | 4 | ||||
-rw-r--r-- | firmware/export/pcm-internal.h | 10 | ||||
-rw-r--r-- | firmware/export/pcm_mixer.h | 4 | ||||
-rw-r--r-- | firmware/pcm.c | 53 | ||||
-rw-r--r-- | firmware/pcm_mixer.c | 28 |
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 | ||
25 | struct pcm_peaks | ||
26 | { | ||
27 | long period; | ||
28 | long tick; | ||
29 | uint16_t val[2]; | ||
30 | }; | ||
31 | |||
32 | void 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 */ |
104 | void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count); | 104 | void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count); |
105 | 105 | ||
106 | /* Calculate peak values for channel */ | ||
107 | void 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 */ |
107 | void mixer_reset(void); | 111 | void 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 */ |
94 | int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT; | 94 | int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT; |
95 | 95 | ||
96 | /* peak data for the global peak values - i.e. what the final output is */ | ||
97 | static struct pcm_peaks global_peaks; | ||
98 | |||
96 | /* Called internally by functions to reset the state */ | 99 | /* Called internally by functions to reset the state */ |
97 | static void pcm_play_stopped(void) | 100 | static 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 | */ |
110 | static void pcm_peak_peeker(const int32_t *addr, int count, int peaks[2]) | 113 | static 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 | ||
148 | void pcm_calculate_peaks(int *left, int *right) | 151 | void 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 | |||
184 | void 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 | ||
196 | const void* pcm_get_peak_buffer(int * count) | 199 | const void* pcm_get_peak_buffer(int * count) |
@@ -437,7 +440,7 @@ static void pcm_recording_stopped(void) | |||
437 | */ | 440 | */ |
438 | void pcm_calculate_rec_peaks(int *left, int *right) | 441 | void 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 */ |
60 | static struct mixer_channel channels[PCM_MIXER_NUM_CHANNELS] IBSS_ATTR; | 61 | static struct mixer_channel channels[PCM_MIXER_NUM_CHANNELS] IBSS_ATTR; |
61 | 62 | ||
63 | /* History for channel peaks */ | ||
64 | static 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 */ |
63 | static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR; | 67 | static 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 */ | ||
503 | void 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 */ |
496 | void mixer_reset(void) | 522 | void mixer_reset(void) |
497 | { | 523 | { |