mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 21:25:19 -05:00
Commit FS#12150 - Fully-functional audio mixer - and finally whip old limitations about playback of voice and other sounds when paused. Channels are independent in state and amplitude. Fade on stop/pause is handled by the channel's volume control rather than global volume which means it now works from anywhere. Opens up the possibility of plugin sounds during music playback by merely adding an additional channel enum. If any PCM drivers were not properly modified, see one of the last comments in the task for a description of the simple change that is expected. Some params are tunable in firmware/export/pcm-mixer.h as well.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30097 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
8411614b8a
commit
a2b6703a36
43 changed files with 1931 additions and 429 deletions
|
|
@ -29,6 +29,7 @@
|
|||
#include "as3514.h"
|
||||
#include "audiohw.h"
|
||||
#include "mmu-arm.h"
|
||||
#include "pcm-internal.h"
|
||||
|
||||
#define MAX_TRANSFER (4*((1<<11)-1)) /* maximum data we can transfer via DMA
|
||||
* i.e. 32 bits at once (size of I2SO_DATA)
|
||||
|
|
@ -104,9 +105,13 @@ static void dma_callback(void)
|
|||
|
||||
/* force writeback */
|
||||
clean_dcache_range(dma_start_addr, dma_start_size);
|
||||
play_start_pcm();
|
||||
pcm_play_dma_started_callback();
|
||||
}
|
||||
else
|
||||
{
|
||||
play_start_pcm();
|
||||
}
|
||||
|
||||
play_start_pcm();
|
||||
}
|
||||
|
||||
void pcm_play_dma_start(const void *addr, size_t size)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "ccm-imx31.h"
|
||||
#include "sdma-imx31.h"
|
||||
#include "mmu-imx31.h"
|
||||
#include "pcm-internal.h"
|
||||
|
||||
#define DMA_PLAY_CH_NUM 2
|
||||
#define DMA_REC_CH_NUM 1
|
||||
|
|
@ -105,6 +106,8 @@ static void play_dma_callback(void)
|
|||
dma_play_bd.mode.command = TRANSFER_16BIT;
|
||||
dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
|
||||
sdma_channel_run(DMA_PLAY_CH_NUM);
|
||||
|
||||
pcm_play_dma_started_callback();
|
||||
}
|
||||
|
||||
void pcm_play_lock(void)
|
||||
|
|
|
|||
182
firmware/target/arm/pcm-mixer-armv4.c
Normal file
182
firmware/target/arm/pcm-mixer-armv4.c
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2011 by Michael Sevakis
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#define MIXER_OPTIMIZED_WRITE_SAMPLES
|
||||
#define MIXER_OPTIMIZED_MIX_SAMPLES
|
||||
|
||||
/* Mix channels' samples and apply gain factors */
|
||||
static FORCE_INLINE void mix_samples(void *out,
|
||||
void *src0,
|
||||
int32_t src0_amp,
|
||||
void *src1,
|
||||
int32_t src1_amp,
|
||||
size_t size)
|
||||
{
|
||||
if (src0_amp == MIX_AMP_UNITY && src1_amp == MIX_AMP_UNITY)
|
||||
{
|
||||
/* Both are unity amplitude */
|
||||
int32_t l0, l1, h0, h1;
|
||||
asm volatile (
|
||||
"1: \n"
|
||||
"ldrsh %4, [%1], #2 \n"
|
||||
"ldrsh %5, [%2], #2 \n"
|
||||
"ldrsh %6, [%1], #2 \n"
|
||||
"ldrsh %7, [%2], #2 \n"
|
||||
"add %4, %4, %5 \n"
|
||||
"add %6, %6, %7 \n"
|
||||
"mov %5, %4, asr #15 \n"
|
||||
"teq %5, %5, asr #31 \n"
|
||||
"eorne %4, %8, %4, asr #31 \n"
|
||||
"mov %7, %6, asr #15 \n"
|
||||
"teq %7, %7, asr #31 \n"
|
||||
"eorne %6, %8, %6, asr #31 \n"
|
||||
"subs %3, %3, #4 \n"
|
||||
"and %4, %4, %8, lsr #16 \n"
|
||||
"orr %6, %4, %6, lsl #16 \n"
|
||||
"str %6, [%0], #4 \n"
|
||||
"bhi 1b \n"
|
||||
: "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
|
||||
"=&r"(l0), "=&r"(l1), "=&r"(h0), "=&r"(h1)
|
||||
: "r"(0xffff7fff));
|
||||
}
|
||||
else if (src0_amp != MIX_AMP_UNITY && src1_amp != MIX_AMP_UNITY)
|
||||
{
|
||||
/* Neither are unity amplitude */
|
||||
int32_t l0, l1, h0, h1;
|
||||
asm volatile (
|
||||
"1: \n"
|
||||
"ldrsh %4, [%1], #2 \n"
|
||||
"ldrsh %5, [%2], #2 \n"
|
||||
"ldrsh %6, [%1], #2 \n"
|
||||
"ldrsh %7, [%2], #2 \n"
|
||||
"mul %4, %8, %4 \n"
|
||||
"mul %5, %9, %5 \n"
|
||||
"mul %6, %8, %6 \n"
|
||||
"mul %7, %9, %7 \n"
|
||||
"mov %4, %4, asr #16 \n"
|
||||
"add %4, %4, %5, asr #16 \n"
|
||||
"mov %6, %6, asr #16 \n"
|
||||
"add %6, %6, %7, asr #16 \n"
|
||||
"mov %5, %4, asr #15 \n"
|
||||
"teq %5, %5, asr #31 \n"
|
||||
"eorne %4, %10, %4, asr #31 \n"
|
||||
"mov %7, %6, asr #15 \n"
|
||||
"teq %7, %7, asr #31 \n"
|
||||
"eorne %6, %10, %6, asr #31 \n"
|
||||
"subs %3, %3, #4 \n"
|
||||
"and %4, %4, %10, lsr #16 \n"
|
||||
"orr %6, %4, %6, lsl #16 \n"
|
||||
"str %6, [%0], #4 \n"
|
||||
"bhi 1b \n"
|
||||
: "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
|
||||
"=&r"(l0), "=&r"(l1), "=&r"(h0), "=&r"(h1)
|
||||
: "r"(src0_amp), "r"(src1_amp), "r"(0xffff7fff));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* One is unity amplitude */
|
||||
if (src0_amp != MIX_AMP_UNITY)
|
||||
{
|
||||
/* Keep unity in src0, amp0 */
|
||||
int16_t *src_tmp = src0;
|
||||
src0 = src1;
|
||||
src1 = src_tmp;
|
||||
src1_amp = src0_amp;
|
||||
src0_amp = MIX_AMP_UNITY;
|
||||
}
|
||||
|
||||
int32_t l0, l1, h0, h1;
|
||||
asm volatile (
|
||||
"1: \n"
|
||||
"ldrsh %4, [%1], #2 \n"
|
||||
"ldrsh %5, [%2], #2 \n"
|
||||
"ldrsh %6, [%1], #2 \n"
|
||||
"ldrsh %7, [%2], #2 \n"
|
||||
"mul %5, %8, %5 \n"
|
||||
"mul %7, %8, %7 \n"
|
||||
"add %4, %4, %5, asr #16 \n"
|
||||
"add %6, %6, %7, asr #16 \n"
|
||||
"mov %5, %4, asr #15 \n"
|
||||
"teq %5, %5, asr #31 \n"
|
||||
"eorne %4, %9, %4, asr #31 \n"
|
||||
"mov %7, %6, asr #15 \n"
|
||||
"teq %7, %7, asr #31 \n"
|
||||
"eorne %6, %9, %6, asr #31 \n"
|
||||
"subs %3, %3, #4 \n"
|
||||
"and %4, %4, %9, lsr #16 \n"
|
||||
"orr %6, %4, %6, lsl #16 \n"
|
||||
"str %6, [%0], #4 \n"
|
||||
"bhi 1b \n"
|
||||
: "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
|
||||
"=&r"(l0), "=&r"(l1), "=&r"(h0), "=&r"(h1)
|
||||
: "r"(src1_amp), "r"(0xffff7fff));
|
||||
}
|
||||
}
|
||||
|
||||
/* Write channel's samples and apply gain factor */
|
||||
static FORCE_INLINE void write_samples(void *out,
|
||||
void *src,
|
||||
int32_t amp,
|
||||
size_t size)
|
||||
{
|
||||
if (LIKELY(amp == MIX_AMP_UNITY))
|
||||
{
|
||||
/* Channel is unity amplitude */
|
||||
asm volatile (
|
||||
"ands r1, %2, #0x1f \n"
|
||||
"beq 2f \n"
|
||||
"1: \n"
|
||||
"ldr r0, [%1], #4 \n"
|
||||
"subs r1, r1, #4 \n"
|
||||
"str r0, [%0], #4 \n"
|
||||
"bne 1b \n"
|
||||
"bics %2, %2, #0x1f \n"
|
||||
"beq 3f \n"
|
||||
"2: \n"
|
||||
"ldmia %1!, { r0-r7 } \n"
|
||||
"subs %2, %2, #32 \n"
|
||||
"stmia %0!, { r0-r7 } \n"
|
||||
"bhi 2b \n"
|
||||
"3: \n"
|
||||
: "+r"(out), "+r"(src), "+r"(size)
|
||||
:
|
||||
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Channel needs amplitude cut */
|
||||
uint32_t l, h;
|
||||
asm volatile (
|
||||
"1: \n"
|
||||
"ldrsh %3, [%1], #2 \n"
|
||||
"ldrsh %4, [%1], #2 \n"
|
||||
"subs %2, %2, #4 \n"
|
||||
"mul %3, %5, %3 \n"
|
||||
"mul %4, %5, %4 \n"
|
||||
"and %4, %4, %6, lsl #16 \n"
|
||||
"orr %4, %4, %3, lsr #16 \n"
|
||||
"str %4, [%0], #4 \n"
|
||||
"bhi 1b \n"
|
||||
: "+r"(out), "+r"(src), "+r"(size),
|
||||
"=&r"(l), "=&r"(h)
|
||||
: "r"(amp), "r"(0xffffffffu));
|
||||
}
|
||||
}
|
||||
106
firmware/target/arm/pcm-mixer-armv5.c
Normal file
106
firmware/target/arm/pcm-mixer-armv5.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2011 by Michael Sevakis
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#define MIXER_OPTIMIZED_WRITE_SAMPLES
|
||||
#define MIXER_OPTIMIZED_MIX_SAMPLES
|
||||
|
||||
/* Mix channels' samples and apply gain factors */
|
||||
static FORCE_INLINE void mix_samples(void *out,
|
||||
void *src0,
|
||||
int32_t src0_amp,
|
||||
void *src1,
|
||||
int32_t src1_amp,
|
||||
size_t size)
|
||||
{
|
||||
int32_t s0, s1, tmp;
|
||||
asm volatile (
|
||||
"1: \n"
|
||||
"ldr %4, [%1], #4 \n"
|
||||
"ldr %5, [%2], #4 \n"
|
||||
"smulwb %6, %7, %4 \n"
|
||||
"smulwt %4, %7, %4 \n"
|
||||
"smlawb %6, %8, %5, %6 \n"
|
||||
"smlawt %4, %8, %5, %4 \n"
|
||||
"mov %5, %6, asr #15 \n"
|
||||
"teq %5, %5, asr #31 \n"
|
||||
"eorne %6, %9, %6, asr #31 \n"
|
||||
"mov %5, %4, asr #15 \n"
|
||||
"teq %5, %5, asr #31 \n"
|
||||
"eorne %4, %9, %4, asr #31 \n"
|
||||
"subs %3, %3, #4 \n"
|
||||
"and %6, %6, %9, lsr #16 \n"
|
||||
"orr %6, %6, %4, lsl #16 \n"
|
||||
"str %6, [%0], #4 \n"
|
||||
"bhi 1b \n"
|
||||
: "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
|
||||
"=&r"(s0), "=&r"(s1), "=&r"(tmp)
|
||||
: "r"(src0_amp), "r"(src1_amp), "r"(0xffff7fff));
|
||||
}
|
||||
|
||||
/* Write channel's samples and apply gain factor */
|
||||
static FORCE_INLINE void write_samples(void *out,
|
||||
void *src,
|
||||
int32_t amp,
|
||||
size_t size)
|
||||
{
|
||||
if (LIKELY(amp == MIX_AMP_UNITY))
|
||||
{
|
||||
/* Channel is unity amplitude */
|
||||
asm volatile (
|
||||
"ands r1, %2, #0x1f \n"
|
||||
"beq 2f \n"
|
||||
"1: \n"
|
||||
"ldr r0, [%1], #4 \n"
|
||||
"subs r1, r1, #4 \n"
|
||||
"str r0, [%0], #4 \n"
|
||||
"bne 1b \n"
|
||||
"bics %2, %2, #0x1f \n"
|
||||
"beq 3f \n"
|
||||
"2: \n"
|
||||
"ldmia %1!, { r0-r7 } \n"
|
||||
"subs %2, %2, #32 \n"
|
||||
"stmia %0!, { r0-r7 } \n"
|
||||
"bhi 2b \n"
|
||||
"3: \n"
|
||||
: "+r"(out), "+r"(src), "+r"(size)
|
||||
:
|
||||
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Channel needs amplitude cut */
|
||||
uint32_t l, h;
|
||||
asm volatile (
|
||||
"1: \n"
|
||||
"ldr %3, [%1], #4 \n"
|
||||
"subs %2, %2, #4 \n"
|
||||
"smulwt %4, %5, %3 \n"
|
||||
"smulwb %3, %5, %3 \n"
|
||||
"mov %4, %4, lsl #16 \n"
|
||||
"mov %3, %3, lsl #16 \n"
|
||||
"orr %4, %4, %3, lsr #16 \n"
|
||||
"str %4, [%0], #4 \n"
|
||||
"bhi 1b \n"
|
||||
: "+r"(out), "+r"(src), "+r"(size),
|
||||
"=&r"(l), "=&r"(h)
|
||||
: "r"(amp));
|
||||
}
|
||||
}
|
||||
118
firmware/target/arm/pcm-mixer-armv6.c
Normal file
118
firmware/target/arm/pcm-mixer-armv6.c
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2011 by Michael Sevakis
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#define MIXER_OPTIMIZED_MIX_SAMPLES
|
||||
#define MIXER_OPTIMIZED_WRITE_SAMPLES
|
||||
|
||||
/* Mix channels' samples and apply gain factors */
|
||||
static FORCE_INLINE void mix_samples(void *out,
|
||||
void *src0,
|
||||
int32_t src0_amp,
|
||||
void *src1,
|
||||
int32_t src1_amp,
|
||||
size_t size)
|
||||
{
|
||||
uint32_t s0, s1;
|
||||
|
||||
if (src0_amp == MIX_AMP_UNITY && src1_amp == MIX_AMP_UNITY)
|
||||
{
|
||||
/* Both are unity amplitude */
|
||||
asm volatile (
|
||||
"1: \n"
|
||||
"ldr %4, [%1], #4 \n"
|
||||
"ldr %5, [%2], #4 \n"
|
||||
"subs %3, %3, #4 \n"
|
||||
"qadd16 %5, %5, %4 \n"
|
||||
"str %5, [%0], #4 \n"
|
||||
"bhi 1b \n"
|
||||
: "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
|
||||
"=&r"(s0), "=&r"(s1));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* One or neither are unity amplitude */
|
||||
uint32_t tmp;
|
||||
asm volatile (
|
||||
"1: \n"
|
||||
"ldr %4, [%1], #4 \n"
|
||||
"ldr %5, [%2], #4 \n"
|
||||
"subs %3, %3, #4 \n"
|
||||
"smulwb %6, %7, %4 \n"
|
||||
"smulwt %4, %7, %4 \n"
|
||||
"smlawb %6, %8, %5, %6 \n"
|
||||
"smlawt %4, %8, %5, %4 \n"
|
||||
"ssat %6, #16, %6 \n"
|
||||
"ssat %4, #16, %4 \n"
|
||||
"pkhbt %6, %6, %4, asl #16 \n"
|
||||
"str %6, [%0], #4 \n"
|
||||
"bhi 1b \n"
|
||||
: "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
|
||||
"=&r"(s0), "=&r"(s1), "=&r"(tmp)
|
||||
: "r"(src0_amp), "r"(src1_amp));
|
||||
}
|
||||
}
|
||||
|
||||
/* Write channel's samples and apply gain factor */
|
||||
static FORCE_INLINE void write_samples(void *out,
|
||||
void *src,
|
||||
int32_t amp,
|
||||
size_t size)
|
||||
{
|
||||
if (LIKELY(amp == MIX_AMP_UNITY))
|
||||
{
|
||||
/* Channel is unity amplitude */
|
||||
asm volatile (
|
||||
"ands r1, %2, #0x1f \n"
|
||||
"beq 2f \n"
|
||||
"1: \n"
|
||||
"ldr r0, [%1], #4 \n"
|
||||
"subs r1, r1, #4 \n"
|
||||
"str r0, [%0], #4 \n"
|
||||
"bne 1b \n"
|
||||
"bics %2, %2, #0x1f \n"
|
||||
"beq 3f \n"
|
||||
"2: \n"
|
||||
"ldmia %1!, { r0-r7 } \n"
|
||||
"subs %2, %2, #32 \n"
|
||||
"stmia %0!, { r0-r7 } \n"
|
||||
"bhi 2b \n"
|
||||
"3: \n"
|
||||
: "+r"(out), "+r"(src), "+r"(size)
|
||||
:
|
||||
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Channel needs amplitude cut */
|
||||
uint32_t s, tmp;
|
||||
asm volatile(
|
||||
"1: \n"
|
||||
"ldr %3, [%1], #4 \n"
|
||||
"subs %2, %2, #4 \n"
|
||||
"smulwt %4, %5, %3 \n"
|
||||
"smulwb %3, %5, %3 \n"
|
||||
"pkhbt %4, %3, %4, asl #16 \n"
|
||||
"str %4, [%0], #4 \n"
|
||||
"bhi 1b \n"
|
||||
: "+r"(out), "+r"(src), "+r"(size),
|
||||
"=&r"(s), "=&r"(tmp)
|
||||
: "r"(amp));
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
#include "sound.h"
|
||||
#include "pcm.h"
|
||||
#include "pcm_sampr.h"
|
||||
#include "pcm-internal.h"
|
||||
|
||||
/** DMA **/
|
||||
|
||||
|
|
@ -115,6 +116,7 @@ void pcm_dma_apply_settings(void)
|
|||
/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
|
||||
void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
|
||||
{
|
||||
bool new_buffer = false;
|
||||
register size_t size;
|
||||
|
||||
DMA0_STATUS; /* Clear any pending interrupt */
|
||||
|
|
@ -136,9 +138,14 @@ void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
|
|||
/* Set the new DMA values and activate channel */
|
||||
DMA0_RAM_ADDR = dma_play_data.addr;
|
||||
DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
|
||||
|
||||
if (new_buffer)
|
||||
pcm_play_dma_started_callback();
|
||||
return;
|
||||
}
|
||||
|
||||
new_buffer = true;
|
||||
|
||||
/* Buffer empty. Try to get more. */
|
||||
pcm_play_get_more_callback((void **)&dma_play_data.addr,
|
||||
&dma_play_data.size);
|
||||
|
|
@ -181,8 +188,9 @@ void fiq_playback(void)
|
|||
* r0-r3 and r12 is a working register.
|
||||
*/
|
||||
asm volatile (
|
||||
"stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */
|
||||
"stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */
|
||||
|
||||
"mov r4, #0 \n" /* Was the callback called? */
|
||||
#if CONFIG_CPU == PP5002
|
||||
"ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */
|
||||
"ldr r12, [r12] \n"
|
||||
|
|
@ -212,16 +220,13 @@ void fiq_playback(void)
|
|||
"tst r1, #1 \n" /* two samples (one word) left? */
|
||||
"ldrne r12, [r8], #4 \n" /* load two samples */
|
||||
"strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
|
||||
|
||||
"cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
|
||||
"bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
|
||||
#elif SAMPLE_SIZE == 32
|
||||
".check_fifo: \n"
|
||||
"ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
|
||||
"and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */
|
||||
|
||||
"movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */
|
||||
"beq .exit \n" /* no complete pair? -> exit */
|
||||
"beq .fifo_fill_complete \n" /* no complete pair? -> exit */
|
||||
"cmp r1, r9, lsr #2 \n" /* number of words from source */
|
||||
"movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
|
||||
"sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
|
||||
|
|
@ -234,11 +239,23 @@ void fiq_playback(void)
|
|||
"subs r1, r1, #1 \n" /* one more loop? */
|
||||
"bgt .fifo_loop \n" /* yes, continue */
|
||||
|
||||
".fifo_fill_complete: \n"
|
||||
#endif
|
||||
"cmp r4, #0 \n" /* If fill came after get_more... */
|
||||
"beq .still_old_buffer \n"
|
||||
"mov r4, #0 \n"
|
||||
"ldr r2, =pcm_play_dma_started \n"
|
||||
"ldrne r2, [r2] \n"
|
||||
"cmp r2, #0 \n"
|
||||
"movne lr, pc \n"
|
||||
"bxne r2 \n"
|
||||
|
||||
".still_old_buffer: \n"
|
||||
"cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
|
||||
"bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
|
||||
#endif
|
||||
|
||||
".more_data: \n"
|
||||
"mov r4, #1 \n" /* Remember we did this */
|
||||
"ldr r2, =pcm_play_get_more_callback \n"
|
||||
"mov r0, r11 \n" /* r0 = &p */
|
||||
"add r1, r11, #4 \n" /* r1 = &size */
|
||||
|
|
@ -250,7 +267,7 @@ void fiq_playback(void)
|
|||
|
||||
".exit: \n" /* (r9=0 if stopping, look above) */
|
||||
"stmia r11, { r8-r9 } \n" /* save p and size */
|
||||
"ldmfd sp!, { r0-r3, lr } \n"
|
||||
"ldmfd sp!, { r0-r4, lr } \n"
|
||||
"subs pc, lr, #4 \n" /* FIQ specific return sequence */
|
||||
".ltorg \n"
|
||||
: /* These must only be integers! No regs */
|
||||
|
|
@ -264,6 +281,8 @@ void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR;
|
|||
/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
|
||||
void fiq_playback(void)
|
||||
{
|
||||
bool new_buffer = false;
|
||||
|
||||
#if CONFIG_CPU == PP5002
|
||||
inl(0xcf001040);
|
||||
#endif
|
||||
|
|
@ -271,6 +290,10 @@ void fiq_playback(void)
|
|||
do {
|
||||
while (dma_play_data.size > 0) {
|
||||
if (IIS_TX_FREE_COUNT < 2) {
|
||||
if (new_buffer) {
|
||||
new_buffer = false;
|
||||
pcm_play_dma_started_callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
#if SAMPLE_SIZE == 16
|
||||
|
|
@ -282,9 +305,15 @@ void fiq_playback(void)
|
|||
dma_play_data.size -= 4;
|
||||
}
|
||||
|
||||
if (new_buffer) {
|
||||
new_buffer = false;
|
||||
pcm_play_dma_started_callback();
|
||||
}
|
||||
|
||||
/* p is empty, get some more data */
|
||||
pcm_play_get_more_callback((void **)&dma_play_data.addr,
|
||||
&dma_play_data.size);
|
||||
new_buffer = true;
|
||||
} while (dma_play_data.size);
|
||||
|
||||
/* No more data */
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "sound.h"
|
||||
#include "i2s.h"
|
||||
#include "pcm.h"
|
||||
#include "pcm-internal.h"
|
||||
|
||||
struct dma_data
|
||||
{
|
||||
|
|
@ -247,6 +248,8 @@ void fiq_handler(void)
|
|||
* r0-r3 and r12 is a working register.
|
||||
*/
|
||||
asm volatile (
|
||||
"stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */
|
||||
"mov r4, #0 \n" /* Was the callback called? */
|
||||
#if defined(CPU_TCC780X)
|
||||
"mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */
|
||||
"ldr r9, =0xf3001004 \n" /* CREQ */
|
||||
|
|
@ -279,33 +282,41 @@ void fiq_handler(void)
|
|||
"sub r9, r9, #0x10 \n" /* 4 words written */
|
||||
"stmia r11, { r8-r9 } \n" /* save p and size */
|
||||
|
||||
"cmp r4, #0 \n" /* Callback called? */
|
||||
"beq .exit \n"
|
||||
/* "mov r4, #0 \n" If get_more could be called multiple times! */
|
||||
"ldr r2, =pcm_play_dma_started\n"
|
||||
"ldr r2, [r2] \n"
|
||||
"cmp r2, #0 \n"
|
||||
"blxne r2 \n"
|
||||
|
||||
".exit: \n"
|
||||
"ldmfd sp!, { r0-r4, lr } \n"
|
||||
"subs pc, lr, #4 \n" /* FIQ specific return sequence */
|
||||
|
||||
".more_data: \n"
|
||||
"stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */
|
||||
"mov r4, #1 \n" /* Remember we got more data in this FIQ */
|
||||
"ldr r2, =pcm_play_get_more_callback \n"
|
||||
"mov r0, r11 \n" /* r0 = &p */
|
||||
"add r1, r11, #4 \n" /* r1 = &size */
|
||||
"blx r2 \n" /* call pcm_play_get_more_callback */
|
||||
"ldmia r11, { r8-r9 } \n" /* load new p and size */
|
||||
"cmp r9, #0x10 \n" /* did we actually get enough data? */
|
||||
"ldmfd sp!, { r0-r3, lr } \n"
|
||||
"bpl .fill_fifo \n" /* not stop and enough? refill */
|
||||
"b .exit \n"
|
||||
".ltorg \n"
|
||||
);
|
||||
}
|
||||
#else /* C version for reference */
|
||||
void fiq_handler(void) ICODE_ATTR __attribute__((naked));
|
||||
void fiq_handler(void) ICODE_ATTR;
|
||||
void fiq_handler(void)
|
||||
{
|
||||
asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */
|
||||
"sub sp, sp, #8 \n"); /* Reserve stack */
|
||||
register bool new_buffer = false;
|
||||
|
||||
if (dma_play_data.size < 16)
|
||||
{
|
||||
/* p is empty, get some more data */
|
||||
new_buffer = true;
|
||||
pcm_play_get_more_callback((void**)&dma_play_data.p,
|
||||
&dma_play_data.size);
|
||||
}
|
||||
|
|
@ -327,9 +338,8 @@ void fiq_handler(void)
|
|||
/* Clear FIQ status */
|
||||
CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK;
|
||||
|
||||
asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */
|
||||
"ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
|
||||
"subs pc, lr, #4 \n"); /* Return from FIQ */
|
||||
if (new_buffer)
|
||||
pcm_play_dma_started_callback();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "system.h"
|
||||
#include "audio.h"
|
||||
#include "string.h"
|
||||
#include "pcm-internal.h"
|
||||
|
||||
#define DMA_BUF_SAMPLES 0x100
|
||||
|
||||
|
|
@ -63,6 +64,8 @@ static inline void fill_dma_buf(int offset)
|
|||
|
||||
if (pcm_playing && !pcm_paused)
|
||||
{
|
||||
bool new_buffer =false;
|
||||
|
||||
do
|
||||
{
|
||||
int count;
|
||||
|
|
@ -102,10 +105,20 @@ static inline void fill_dma_buf(int offset)
|
|||
count--;
|
||||
}
|
||||
p = tmp_p;
|
||||
|
||||
if (new_buffer)
|
||||
{
|
||||
new_buffer = false;
|
||||
pcm_play_dma_started_callback();
|
||||
}
|
||||
|
||||
if (l >= lend)
|
||||
return;
|
||||
|
||||
pcm_play_get_more_callback((void**)&p, &p_size);
|
||||
|
||||
if (p_size)
|
||||
new_buffer = true;
|
||||
}
|
||||
while (p_size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "audio.h"
|
||||
#include "sound.h"
|
||||
#include "file.h"
|
||||
#include "pcm-internal.h"
|
||||
|
||||
/* PCM interrupt routine lockout */
|
||||
static struct
|
||||
|
|
@ -235,6 +236,8 @@ void fiq_handler(void)
|
|||
|
||||
/* Re-Activate the channel */
|
||||
DMASKTRIG2 = 0x2;
|
||||
|
||||
pcm_play_dma_started_callback();
|
||||
}
|
||||
|
||||
size_t pcm_get_bytes_waiting(void)
|
||||
|
|
|
|||
|
|
@ -99,14 +99,15 @@ void TIMER3(void)
|
|||
INTPND = TIMER3_MASK;
|
||||
}
|
||||
|
||||
void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
|
||||
void beep_play(unsigned int frequency, unsigned int duration,
|
||||
unsigned int amplitude)
|
||||
{
|
||||
#define TIMER3_TICK_SEC (TIMER_FREQ / TIMER234_PRESCALE)
|
||||
|
||||
unsigned long tcnt, tcmp;
|
||||
int oldstatus;
|
||||
|
||||
if (amplitude <= 0)
|
||||
if (frequency == 0 || duration == 0 || amplitude == 0)
|
||||
{
|
||||
beep_stop(); /* won't hear it anyway */
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "audio.h"
|
||||
#include "sound.h"
|
||||
#include "file.h"
|
||||
#include "pcm-internal.h"
|
||||
|
||||
/* PCM interrupt routine lockout */
|
||||
static struct
|
||||
|
|
@ -275,6 +276,8 @@ void fiq_handler(void)
|
|||
|
||||
/* Re-Activate the channel */
|
||||
DMASKTRIG2 = 0x2;
|
||||
|
||||
pcm_play_dma_started_callback();
|
||||
}
|
||||
|
||||
size_t pcm_get_bytes_waiting(void)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "panic.h"
|
||||
#include "audiohw.h"
|
||||
#include "pcm.h"
|
||||
#include "pcm-internal.h"
|
||||
#include "pcm_sampr.h"
|
||||
#include "dma-target.h"
|
||||
#include "mmu-arm.h"
|
||||
|
|
@ -100,6 +101,7 @@ void pcm_play_unlock(void)
|
|||
void INT_DMA(void) ICODE_ATTR;
|
||||
void INT_DMA(void)
|
||||
{
|
||||
bool new_buffer = false;
|
||||
DMACOM0 = 7;
|
||||
while (!(DMACON0 & (1 << 18)))
|
||||
{
|
||||
|
|
@ -112,8 +114,12 @@ void INT_DMA(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!nextsize) pcm_play_get_more_callback((void**)&nextbuf, &nextsize);
|
||||
if (!nextsize) break;
|
||||
if (!nextsize)
|
||||
{
|
||||
pcm_play_get_more_callback((void**)&nextbuf, &nextsize);
|
||||
if (!nextsize) break;
|
||||
new_buffer = true;
|
||||
}
|
||||
queuedsize = MIN(sizeof(dblbuf), nextsize / 2);
|
||||
nextsize -= queuedsize;
|
||||
queuedbuf = nextbuf + nextsize;
|
||||
|
|
@ -124,7 +130,14 @@ void INT_DMA(void)
|
|||
clean_dcache();
|
||||
DMACOM0 = 4;
|
||||
DMACOM0 = 7;
|
||||
|
||||
if (new_buffer)
|
||||
{
|
||||
pcm_play_dma_started_callback();
|
||||
new_buffer = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void pcm_play_dma_start(const void* addr, size_t size)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "panic.h"
|
||||
#include "audiohw.h"
|
||||
#include "pcm.h"
|
||||
#include "pcm-internal.h"
|
||||
#include "pcm_sampr.h"
|
||||
#include "mmu-arm.h"
|
||||
#include "pcm-target.h"
|
||||
|
|
@ -113,6 +114,8 @@ void INT_DMAC0C0(void)
|
|||
DMAC0C0CONFIG = 0x8a81;
|
||||
}
|
||||
else DMAC0C0NEXTLLI = pcm_lli;
|
||||
|
||||
pcm_play_dma_started_callback();
|
||||
}
|
||||
|
||||
void pcm_play_dma_start(const void* addr, size_t size)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "dm320.h"
|
||||
#include "audiohw.h"
|
||||
#include "dsp-target.h"
|
||||
#include "pcm-internal.h"
|
||||
|
||||
void pcm_play_dma_init(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "dsp-target.h"
|
||||
#include "dsp/ipc.h"
|
||||
#include "mmu-arm.h"
|
||||
#include "pcm-internal.h"
|
||||
|
||||
/* This is global to save some latency when pcm_play_dma_get_peak_buffer is
|
||||
* called.
|
||||
|
|
@ -178,6 +179,8 @@ void DSPHINT(void)
|
|||
|
||||
DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx",
|
||||
(unsigned long)start, (unsigned long)sdem_addr);
|
||||
|
||||
pcm_play_dma_started_callback();
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue