diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/pcm_playback.c | 113 |
1 files changed, 107 insertions, 6 deletions
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 16e8f5e3af..7382661f48 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c | |||
@@ -98,6 +98,8 @@ size_t pcm_get_bytes_waiting(void) | |||
98 | 98 | ||
99 | static int pcm_freq = 0x6; /* 44.1 is default */ | 99 | static int pcm_freq = 0x6; /* 44.1 is default */ |
100 | 100 | ||
101 | int peak_left = 0, peak_right = 0; | ||
102 | |||
101 | /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ | 103 | /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ |
102 | static void dma_start(const void *addr, size_t size) | 104 | static void dma_start(const void *addr, size_t size) |
103 | { | 105 | { |
@@ -205,7 +207,6 @@ void DMA0(void) | |||
205 | SAR0 = (unsigned long)next_start; /* Source address */ | 207 | SAR0 = (unsigned long)next_start; /* Source address */ |
206 | BCR0 = next_size; /* Bytes to transfer */ | 208 | BCR0 = next_size; /* Bytes to transfer */ |
207 | DCR0 |= DMA_EEXT; | 209 | DCR0 |= DMA_EEXT; |
208 | |||
209 | } | 210 | } |
210 | else | 211 | else |
211 | { | 212 | { |
@@ -846,6 +847,109 @@ bool pcm_is_paused(void) { | |||
846 | return pcm_paused; | 847 | return pcm_paused; |
847 | } | 848 | } |
848 | 849 | ||
850 | |||
851 | #if defined(CPU_COLDFIRE) | ||
852 | /* Peaks ahead in the DMA buffer based upon the calling period to | ||
853 | attempt to compensate for the delay. Keeps a moving average of | ||
854 | length four. */ | ||
855 | void pcm_calculate_peaks(int *left, int *right) | ||
856 | { | ||
857 | unsigned long samples; | ||
858 | unsigned long *addr, *end; | ||
859 | long peak_p, peak_n; | ||
860 | |||
861 | static unsigned long last_peak_tick = 0; | ||
862 | static unsigned long frame_period = 0; | ||
863 | |||
864 | /* Throttled peak ahead based on calling period */ | ||
865 | unsigned long period = current_tick - last_peak_tick; | ||
866 | |||
867 | /* Keep reasonable limits on period */ | ||
868 | if (period < 1) | ||
869 | period = 1; | ||
870 | else if (period > HZ/5) | ||
871 | period = HZ/5; | ||
872 | |||
873 | frame_period = (3*frame_period + period) >> 2; | ||
874 | |||
875 | last_peak_tick = current_tick; | ||
876 | |||
877 | if (!pcm_playing || pcm_paused) | ||
878 | { | ||
879 | peak_left = peak_right = 0; | ||
880 | goto peak_done; | ||
881 | } | ||
882 | |||
883 | samples = (BCR0 & 0xffffff) >> 2; | ||
884 | addr = (long *)(SAR0 & ~3); | ||
885 | samples = MIN(frame_period*44100/HZ, samples); | ||
886 | end = addr + samples; | ||
887 | peak_p = peak_n = 0; | ||
888 | |||
889 | if (left && right) | ||
890 | { | ||
891 | if (samples > 0) | ||
892 | { | ||
893 | long peak_rp = 0, peak_rn = 0; | ||
894 | |||
895 | do | ||
896 | { | ||
897 | long value = *addr; | ||
898 | long ch; | ||
899 | |||
900 | ch = value >> 16; | ||
901 | if (ch > peak_p) peak_p = ch; | ||
902 | else if (ch < peak_n) peak_n = ch; | ||
903 | |||
904 | ch = (short)value; | ||
905 | if (ch > peak_rp) peak_rp = ch; | ||
906 | else if (ch < peak_rn) peak_rn = ch; | ||
907 | |||
908 | addr += 4; | ||
909 | } | ||
910 | while (addr < end); | ||
911 | |||
912 | peak_left = MAX(peak_p, -peak_n); | ||
913 | peak_right = MAX(peak_rp, -peak_rn); | ||
914 | } | ||
915 | } | ||
916 | else if (left || right) | ||
917 | { | ||
918 | if (samples > 0) | ||
919 | { | ||
920 | if (left) | ||
921 | { | ||
922 | /* Put left channel in low word */ | ||
923 | addr = (long *)((short *)addr - 1); | ||
924 | end = (long *)((short *)end - 1); | ||
925 | } | ||
926 | |||
927 | do | ||
928 | { | ||
929 | long value = *(short *)addr; | ||
930 | |||
931 | if (value > peak_p) peak_p = value; | ||
932 | else if (value < peak_n) peak_n = value; | ||
933 | |||
934 | addr += 4; | ||
935 | } | ||
936 | while (addr < end); | ||
937 | |||
938 | if (left) | ||
939 | peak_left = MAX(peak_p, -peak_n); | ||
940 | else | ||
941 | peak_right = MAX(peak_p, -peak_n); | ||
942 | } | ||
943 | } | ||
944 | |||
945 | peak_done: | ||
946 | if (left) | ||
947 | *left = peak_left; | ||
948 | |||
949 | if (right) | ||
950 | *right = peak_right; | ||
951 | } | ||
952 | #else | ||
849 | /* | 953 | /* |
850 | * This function goes directly into the DMA buffer to calculate the left and | 954 | * This function goes directly into the DMA buffer to calculate the left and |
851 | * right peak values. To avoid missing peaks it tries to look forward two full | 955 | * right peak values. To avoid missing peaks it tries to look forward two full |
@@ -860,7 +964,6 @@ bool pcm_is_paused(void) { | |||
860 | /* Up to 1/50th of a second of audio for peak calculation */ | 964 | /* Up to 1/50th of a second of audio for peak calculation */ |
861 | /* This should use NATIVE_FREQUENCY, or eventually an adjustable freq. value */ | 965 | /* This should use NATIVE_FREQUENCY, or eventually an adjustable freq. value */ |
862 | #define PEAK_SAMPLES (44100/50) | 966 | #define PEAK_SAMPLES (44100/50) |
863 | |||
864 | void pcm_calculate_peaks(int *left, int *right) | 967 | void pcm_calculate_peaks(int *left, int *right) |
865 | { | 968 | { |
866 | #if (CONFIG_CPU == S3C2440) | 969 | #if (CONFIG_CPU == S3C2440) |
@@ -870,10 +973,7 @@ void pcm_calculate_peaks(int *left, int *right) | |||
870 | short *addr; | 973 | short *addr; |
871 | short *end; | 974 | short *end; |
872 | { | 975 | { |
873 | #ifdef CPU_COLDFIRE | 976 | #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \ |
874 | size_t samples = (BCR0 & 0xffffff) / 4; | ||
875 | addr = (short *) (SAR0 & ~3); | ||
876 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | ||
877 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) \ | 977 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) \ |
878 | || (CONFIG_CPU == PNX0101) | 978 | || (CONFIG_CPU == PNX0101) |
879 | size_t samples = p_size / 4; | 979 | size_t samples = p_size / 4; |
@@ -931,3 +1031,4 @@ void pcm_calculate_peaks(int *left, int *right) | |||
931 | } | 1031 | } |
932 | #endif | 1032 | #endif |
933 | } | 1033 | } |
1034 | #endif /* CPU_COLDFIRE */ | ||