1
0
Fork 0
forked from len0rd/rockbox

Sound api improvements, rockboy sound, contributed by xshock.

Playback of sound currently only works in boost mode, needs fixing.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6226 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michiel Van Der Kolk 2005-03-28 00:00:24 +00:00
parent 853bc3dcf8
commit 451dd48adc
11 changed files with 208 additions and 62 deletions

View file

@ -169,27 +169,29 @@ static void test_get_more(unsigned char **ptr, long *size)
bool uda1380_test(void) bool uda1380_test(void)
{ {
long button; long button;
int vol = 0x7f; int vol = 0x50;
bool done = false; bool done = false;
lcd_setmargins(0, 0); lcd_setmargins(0, 0);
lcd_clear_display(); lcd_clear_display();
lcd_update(); lcd_update();
cpu_boost(true);
if (load_wave("/sample.wav") == -1) if (load_wave("/sample.wav") == -1)
goto exit; goto exit;
audio_pos = 0; audio_pos = 0;
puts("Playing..");
puts("uda1380_init"); puts("uda1380_init");
if (uda1380_init() == -1) if (uda1380_init() == -1)
{ {
puts("Init failed.."); puts("UDA1380 init failed");
goto exit;
} }
puts("Playing..");
audio_pos = 0; audio_pos = 0;
pcm_set_frequency(44100);
pcm_set_volume(0xff - vol);
pcm_play_data(audio_buffer, CHUNK_SIZE, pcm_play_data(audio_buffer, CHUNK_SIZE,
test_get_more); test_get_more);
@ -224,6 +226,7 @@ bool uda1380_test(void)
exit: exit:
sleep(HZ >> 1); /* Sleep 1/2 second to fade out sound */ sleep(HZ >> 1); /* Sleep 1/2 second to fade out sound */
cpu_boost(false);
return false; return false;
} }
@ -1247,10 +1250,9 @@ bool view_battery(void)
lcd_puts(0, 3, buf); lcd_puts(0, 3, buf);
#endif #endif
#ifdef HAVE_CHARGE_CTRL #ifdef HAVE_CHARGE_CTRL
snprintf(buf, 30, "Chgr: %s %s", snprintf(buf, 30, "Charging: %s",
charger_inserted() ? "present" : "absent", charger_enabled ? "yes" : "no");
charger_enabled ? "on" : "off"); lcd_puts(0, 4, buf);
lcd_puts(0, 3, buf);
snprintf(buf, 30, "short delta: %d", short_delta); snprintf(buf, 30, "short delta: %d", short_delta);
lcd_puts(0, 5, buf); lcd_puts(0, 5, buf);
snprintf(buf, 30, "long delta: %d", long_delta); snprintf(buf, 30, "long delta: %d", long_delta);
@ -1272,7 +1274,7 @@ bool view_battery(void)
} }
break; break;
case 3: /* remaining time estimation: */ case 3: /* remeining time estimation: */
lcd_clear_display(); lcd_clear_display();
#ifdef HAVE_CHARGE_CTRL #ifdef HAVE_CHARGE_CTRL
@ -1284,24 +1286,23 @@ bool view_battery(void)
snprintf(buf, 30, "Lvl@cyc st: %d%%", powermgmt_last_cycle_level); snprintf(buf, 30, "Lvl@cyc st: %d%%", powermgmt_last_cycle_level);
lcd_puts(0, 2, buf); lcd_puts(0, 2, buf);
snprintf(buf, 30, "P=%2d I=%2d", pid_p, pid_i);
lcd_puts(0, 3, buf);
snprintf(buf, 30, "Trickle sec: %d/60", trickle_sec);
lcd_puts(0, 4, buf);
#endif #endif
snprintf(buf, 30, "Last PwrHist: %d.%02d V", snprintf(buf, 30, "Last PwrHist: %d.%02d V",
power_history[0] / 100, power_history[0] / 100,
power_history[0] % 100); power_history[0] % 100);
lcd_puts(0, 5, buf); lcd_puts(0, 3, buf);
snprintf(buf, 30, "battery level: %d%%", battery_level()); snprintf(buf, 30, "battery level: %d%%", battery_level());
lcd_puts(0, 6, buf); lcd_puts(0, 5, buf);
snprintf(buf, 30, "Est. remain: %d m", battery_time()); snprintf(buf, 30, "Est. remain: %d m", battery_time());
lcd_puts(0, 6, buf);
#ifdef HAVE_CHARGE_CTRL
snprintf(buf, 30, "Trickle sec: %d/60", trickle_sec);
lcd_puts(0, 7, buf); lcd_puts(0, 7, buf);
#endif
break; break;
} }

View file

@ -58,6 +58,10 @@
#include "power.h" #include "power.h"
#include "talk.h" #include "talk.h"
#include "plugin.h" #include "plugin.h"
#include "uda1380.h"
#ifdef CONFIG_TUNER #ifdef CONFIG_TUNER
#include "radio.h" #include "radio.h"
#endif #endif
@ -261,6 +265,9 @@ void init(void)
} }
} }
#endif /* #ifdef AUTOROCK */ #endif /* #ifdef AUTOROCK */
uda1380_init();
} }
int main(void) int main(void)

View file

@ -44,7 +44,7 @@
#include "mp3data.h" #include "mp3data.h"
#include "powermgmt.h" #include "powermgmt.h"
#include "system.h" #include "system.h"
#if (CONFIG_HWCODEC == MASNONE) && !defined(SIMULATOR) #if (CONFIG_HWCODEC == MASNONE)
#include "pcm_playback.h" #include "pcm_playback.h"
#endif #endif
@ -271,10 +271,12 @@ static const struct plugin_api rockbox_api = {
#if CONFIG_KEYPAD == IRIVER_H100_PAD #if CONFIG_KEYPAD == IRIVER_H100_PAD
button_hold, button_hold,
#endif #endif
#if (CONFIG_HWCODEC == MASNONE) && !defined(SIMULATOR) #if (CONFIG_HWCODEC == MASNONE)
pcm_play_data, pcm_play_data,
pcm_play_stop, pcm_play_stop,
pcm_set_frequency,
pcm_is_playing, pcm_is_playing,
pcm_set_volume
#endif #endif
}; };

View file

@ -43,6 +43,7 @@
#include "id3.h" #include "id3.h"
#include "mpeg.h" #include "mpeg.h"
#include "mp3_playback.h" #include "mp3_playback.h"
#include "pcm_playback.h"
#include "settings.h" #include "settings.h"
#include "thread.h" #include "thread.h"
#include "playlist.h" #include "playlist.h"
@ -317,11 +318,13 @@ struct plugin_api {
#if CONFIG_KEYPAD == IRIVER_H100_PAD #if CONFIG_KEYPAD == IRIVER_H100_PAD
bool (*button_hold)(void); bool (*button_hold)(void);
#endif #endif
#if (CONFIG_HWCODEC == MASNONE) && !defined(SIMULATOR) #if (CONFIG_HWCODEC == MASNONE)
void (*pcm_play_data)(const unsigned char *start, int size, void (*pcm_play_data)(const unsigned char *start, int size,
void (*get_more)(unsigned char** start, long*size)); void (*get_more)(unsigned char** start, long*size));
void (*pcm_play_stop)(void); void (*pcm_play_stop)(void);
void (*pcm_set_frequency)(unsigned int frequency);
bool (*pcm_is_playing)(void); bool (*pcm_is_playing)(void);
void (*pcm_set_volume)(int volume);
#endif #endif
}; };

View file

@ -9,7 +9,7 @@ struct pcm
{ {
int hz, len; int hz, len;
int stereo; int stereo;
byte *buf; short *buf;
int pos; int pos;
}; };

View file

@ -1,47 +1,120 @@
#include "rockmacros.h" #include "rockmacros.h"
#include "defs.h" #include "defs.h"
#include "pcm.h" #include "pcm.h"
#include "rc.h" #include "rc.h"
#define RBSOUND
struct pcm pcm; struct pcm pcm;
static byte buf[4096]; #define BUF_SIZE (8192)
#define DMA_PORTION (1024)
static short buf1_unal[(BUF_SIZE / sizeof(short)) + 2]; // to make sure 4 byte aligned
static short* buf1;
static short front_buf[512];
static short* last_back_pos;
static bool newly_started;
static int turns;
rcvar_t pcm_exports[] = rcvar_t pcm_exports[] =
{ {
RCV_END RCV_END
}; };
void pcm_init(void) void pcm_init(void)
{ {
pcm.hz = 44100; buf1 = (signed short*)((((unsigned int)buf1_unal) >> 2) << 2); /* here i just make sure that buffer is aligned to 4 bytes*/
pcm.stereo = 1; newly_started = true;
pcm.buf = buf; last_back_pos = buf1;
pcm.len = sizeof buf; turns = 0;
pcm.pos = 0;
pcm.hz = 11025;
pcm.stereo = 1;
pcm.buf = front_buf;
pcm.len = (sizeof(front_buf)) / sizeof(short); /* length in shorts, not bytes */
pcm.pos = 0;
rb->pcm_play_stop();
rb->pcm_set_frequency(11025);
rb->pcm_set_volume(200);
} }
void pcm_close(void) void pcm_close(void)
{ {
memset(&pcm, 0, sizeof pcm); memset(&pcm, 0, sizeof pcm);
newly_started = true;
last_back_pos = buf1;
rb->pcm_play_stop();
}
void get_more(unsigned char** start, long* size)
{
int length;
unsigned int sar = (unsigned int)SAR0;
length = ((unsigned int)buf1) + BUF_SIZE - sar;
if(turns > 0)
{
newly_started = true;
last_back_pos = buf1;
turns = 0;
return;
} /* sound will stop if no one feeds data*/
if(length <= 0)
{
*start = (unsigned char*)buf1;
*size = DMA_PORTION;
turns++;
}
else
{
*start = (unsigned char*)sar;
if(length > DMA_PORTION)
*size = DMA_PORTION;
else
*size = length;
}
} }
int pcm_submit(void) int pcm_submit(void)
{ {
#ifdef RBSOUND #ifdef RBSOUND
rb->pcm_play_data(pcm.buf,pcm.pos,NULL); while( (turns < 0) && ((((unsigned int)last_back_pos) + pcm.pos * sizeof(short)) > ((unsigned int)SAR0)) && !newly_started) rb->yield(); /* wait until data is passed through DAC or until exit*/
while(rb->pcm_is_playing()); /* spinlock */ int shorts_left = ((((unsigned int)buf1) + BUF_SIZE) - ((unsigned int)last_back_pos)) / sizeof(short);
pcm.pos = 0; if( shorts_left >= pcm.pos )
return 1; {
memcpy(last_back_pos,pcm.buf,pcm.pos * sizeof(short));
last_back_pos = &last_back_pos[pcm.pos];
}
else
{
int last_pos = shorts_left;
memcpy(last_back_pos,pcm.buf,shorts_left * sizeof(short));
last_back_pos = buf1;
shorts_left = pcm.pos - shorts_left;
memcpy(last_back_pos,&pcm.buf[last_pos],shorts_left * sizeof(short));
last_back_pos = &buf1[shorts_left];
turns--;
}
if(newly_started)
{
rb->pcm_play_data((unsigned char*)buf1,pcm.pos * sizeof(short),&get_more);
newly_started = false;
}
pcm.pos = 0;
return 1;
#else #else
pcm.pos = 0; pcm.pos = 0;
return 0; return 0;
#endif #endif
} }

View file

@ -51,6 +51,7 @@ struct plugin_api* rb;
int shut,cleanshut; int shut,cleanshut;
char *errormsg; char *errormsg;
int gnuboy_main(char *rom); int gnuboy_main(char *rom);
void pcm_close(void);
void die(char *message, ...) void die(char *message, ...)
{ {
@ -124,10 +125,11 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
rb->splash(HZ*2, true, errormsg); rb->splash(HZ*2, true, errormsg);
return PLUGIN_ERROR; return PLUGIN_ERROR;
} }
pcm_close();
rb->splash(HZ*2, true, "Shutting down.. byebye ^^"); rb->splash(HZ*2, true, "Shutting down.. byebye ^^");
cleanup(); cleanup();
return PLUGIN_OK; return PLUGIN_OK;
} }

View file

@ -60,9 +60,9 @@ int pcm_submit(void);
#define S4 (snd.ch[3]) #define S4 (snd.ch[3])
rcvar_t sound_exports[] = rcvar_t sound_exports[] =
{ {
RCV_END RCV_END
}; };
static void s1_freq_d(int d) static void s1_freq_d(int d)
@ -275,10 +275,10 @@ void sound_mix(void)
pcm_submit(); pcm_submit();
if (pcm.stereo) if (pcm.stereo)
{ {
pcm.buf[pcm.pos++] = l+128; pcm.buf[pcm.pos++] = (signed short)(l * 256);
pcm.buf[pcm.pos++] = r+128; pcm.buf[pcm.pos++] = (signed short)(r * 256);
} }
else pcm.buf[pcm.pos++] = ((l+r)>>1)+128; else pcm.buf[pcm.pos++] = (signed short)((r+l) * 128);
} }
} }
R_NR52 = (R_NR52&0xf0) | S1.on | (S2.on<<1) | (S3.on<<2) | (S4.on<<3); R_NR52 = (R_NR52&0xf0) | S1.on | (S2.on<<1) | (S3.on<<2) | (S4.on<<3);

View file

@ -49,7 +49,7 @@ unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] =
REG_I2S, I2S_IFMT_IIS, REG_I2S, I2S_IFMT_IIS,
REG_PWR, PON_PLL | PON_HP | PON_DAC | EN_AVC | PON_AVC | PON_BIAS, REG_PWR, PON_PLL | PON_HP | PON_DAC | EN_AVC | PON_AVC | PON_BIAS,
REG_AMIX, AMIX_RIGHT(0x10) | AMIX_LEFT(0x10), /* 00=max, 3f=mute */ REG_AMIX, AMIX_RIGHT(0x10) | AMIX_LEFT(0x10), /* 00=max, 3f=mute */
REG_MASTER_VOL, MASTER_VOL_LEFT(0x7f) | MASTER_VOL_RIGHT(0x7f), /* 00=max, ff=mute */ REG_MASTER_VOL, MASTER_VOL_LEFT(0x20) | MASTER_VOL_RIGHT(0x20), /* 00=max, ff=mute */
REG_MIX_VOL, MIX_VOL_CHANNEL_1(0) | MIX_VOL_CHANNEL_2(0xff), /* 00=max, ff=mute */ REG_MIX_VOL, MIX_VOL_CHANNEL_1(0) | MIX_VOL_CHANNEL_2(0xff), /* 00=max, ff=mute */
REG_EQ, 0, REG_EQ, 0,
REG_MUTE, MUTE_CH2, /* Mute channel 2 (digital decimation filter) */ REG_MUTE, MUTE_CH2, /* Mute channel 2 (digital decimation filter) */
@ -131,6 +131,8 @@ int uda1380_set_regs(void)
/* Initialize UDA1380 codec with default register values (uda1380_defaults) */ /* Initialize UDA1380 codec with default register values (uda1380_defaults) */
int uda1380_init(void) int uda1380_init(void)
{ {
PLLCR &= ~(1 << 22); /* Set AudioClk = FXTAL/2*/
if (uda1380_set_regs() == -1) if (uda1380_set_regs() == -1)
return -1; return -1;

View file

@ -19,9 +19,11 @@
#ifndef PCM_PLAYBACK_H #ifndef PCM_PLAYBACK_H
#define PCM_PLAYBACK_H #define PCM_PLAYBACK_H
void pcm_set_frequency(unsigned int frequency);
void pcm_play_data(const unsigned char* start, int size, void pcm_play_data(const unsigned char* start, int size,
void (*get_more)(unsigned char** start, long* size)); void (*get_more)(unsigned char** start, long* size));
void pcm_play_stop(void); void pcm_play_stop(void);
bool pcm_is_playing(void); bool pcm_is_playing(void);
void pcm_set_volume(int volume);
#endif #endif

View file

@ -37,20 +37,32 @@
#include "file.h" #include "file.h"
#include "buffer.h" #include "buffer.h"
bool pcm_playing; #include "sprintf.h"
#include "button.h"
#include <string.h>
static bool pcm_playing;
static int pcm_freq = 0x6; // 44.1 in default
/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
static void dma_start(const void *addr, long size) static void dma_start(const void *addr_r, long size)
{ {
pcm_playing = 1; pcm_playing = 1;
int i;
int align;
align = 4;
void* addr = (void*)((((unsigned int)addr_r) >> 2) << 2); // always align data, never pass unaligned data
size = (size >> 2) << 2; // size shoudl also be always multiple of 4
BUSMASTER_CTRL = 0x81; /* PARK[1,0]=10 + BCR24BIT */ BUSMASTER_CTRL = 0x81; /* PARK[1,0]=10 + BCR24BIT */
/* Set up DMA transfer */ /* Set up DMA transfer */
DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */ DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
SAR0 = (unsigned long)addr; /* Source address */ SAR0 = ((unsigned long)addr) + align*4; /* Source address */
DAR0 = (unsigned long)&PDOR3; /* Destination address */ DAR0 = (unsigned long)&PDOR3; /* Destination address */
BCR0 = size; /* Bytes to transfer */ BCR0 = size-(align*4); /* Bytes to transfer */
DMAROUTE = (DMAROUTE & 0xffffff00) | DMA0_REQ_AUDIO_1; DMAROUTE = (DMAROUTE & 0xffffff00) | DMA0_REQ_AUDIO_1;
DMACONFIG = 1; /* Enable DMA0Req => set DMAROUTE |= DMA0_REQ_AUDIO_1 */ DMACONFIG = 1; /* Enable DMA0Req => set DMAROUTE |= DMA0_REQ_AUDIO_1 */
@ -61,14 +73,10 @@ static void dma_start(const void *addr, long size)
ICR4 = (ICR4 & 0xffff00ff) | 0x00001c00; ICR4 = (ICR4 & 0xffff00ff) | 0x00001c00;
IMR &= ~(1<<14); /* bit 14 is DMA0 */ IMR &= ~(1<<14); /* bit 14 is DMA0 */
IIS2CONFIG = 0x4300; /* CLOCKSEL = AudioClk/8 (44.1kHz), IIS2CONFIG = (pcm_freq << 12) | 0x300; /* CLOCKSEL for right frequency + data source = PDOR3 */
data source = PDOR3 */
PDOR3 = 0; /* These are needed to generate FIFO empty request to DMA.. */ for(i = 0; i < align; i++)
PDOR3 = 0; PDOR3 = ((unsigned int*)(addr))[i]; /* These are needed to generate FIFO empty request to DMA.. */
PDOR3 = 0;
PDOR3 = 0;
PDOR3 = 0;
} }
/* Stops the DMA transfer and interrupt */ /* Stops the DMA transfer and interrupt */
@ -77,11 +85,50 @@ static void dma_stop(void)
pcm_playing = 0; pcm_playing = 0;
DCR0 = 0; DCR0 = 0;
/* DMAROUTE &= 0xffffff00;
DMACONFIG = 0;*/
IIS2CONFIG = 0x800;
/* Disable DMA0 interrupt */ /* Disable DMA0 interrupt */
IMR |= (1<<14); IMR |= (1<<14);
ICR4 &= 0xffff00ff; ICR4 &= 0xffff00ff;
} }
/* set volume of the main channel */
void pcm_set_volume(int volume)
{
if(volume > 0)
{
uda1380_mute(0);
uda1380_setvol(0xff - volume);
}
else
{
uda1380_mute(1);
}
}
/* sets frequency of input to DAC */
void pcm_set_frequency(unsigned int frequency)
{
switch(frequency)
{
case 11025:
pcm_freq = 0x2;
break;
case 22050:
pcm_freq = 0x4;
break;
case 44100:
pcm_freq = 0x6;
break;
default:
pcm_freq = 0x6;
}
}
/* the registered callback function to ask for more mp3 data */ /* the registered callback function to ask for more mp3 data */
static void (*callback_for_more)(unsigned char**, long*) = NULL; static void (*callback_for_more)(unsigned char**, long*) = NULL;
@ -110,8 +157,15 @@ void DMA0(void)
unsigned char* start; unsigned char* start;
long size = 0; long size = 0;
int res = DSR0;
DSR0 = 1; /* Clear interrupt */ DSR0 = 1; /* Clear interrupt */
if(res == 0x41)
{
dma_stop();
}
if (callback_for_more) if (callback_for_more)
{ {
callback_for_more(&start, &size); callback_for_more(&start, &size);