From 451dd48adc2ef29fd2f900693393cc9b9b4a849b Mon Sep 17 00:00:00 2001 From: Michiel Van Der Kolk Date: Mon, 28 Mar 2005 00:00:24 +0000 Subject: 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 --- apps/debug_menu.c | 35 ++++++------- apps/main.c | 7 +++ apps/plugin.c | 8 +-- apps/plugin.h | 7 ++- apps/plugins/rockboy/pcm.h | 2 +- apps/plugins/rockboy/rbsound.c | 111 ++++++++++++++++++++++++++++++++++------- apps/plugins/rockboy/rockboy.c | 4 +- apps/plugins/rockboy/sound.c | 12 ++--- firmware/drivers/uda1380.c | 4 +- firmware/export/pcm_playback.h | 2 + firmware/pcm_playback.c | 78 ++++++++++++++++++++++++----- 11 files changed, 208 insertions(+), 62 deletions(-) diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 9d5028af7c..74d1cb94fb 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -169,27 +169,29 @@ static void test_get_more(unsigned char **ptr, long *size) bool uda1380_test(void) { long button; - int vol = 0x7f; + int vol = 0x50; bool done = false; lcd_setmargins(0, 0); lcd_clear_display(); lcd_update(); + cpu_boost(true); if (load_wave("/sample.wav") == -1) goto exit; audio_pos = 0; + puts("Playing.."); puts("uda1380_init"); if (uda1380_init() == -1) { - puts("Init failed.."); - goto exit; + puts("UDA1380 init failed"); } - puts("Playing.."); audio_pos = 0; + pcm_set_frequency(44100); + pcm_set_volume(0xff - vol); pcm_play_data(audio_buffer, CHUNK_SIZE, test_get_more); @@ -224,6 +226,7 @@ bool uda1380_test(void) exit: sleep(HZ >> 1); /* Sleep 1/2 second to fade out sound */ + cpu_boost(false); return false; } @@ -1247,10 +1250,9 @@ bool view_battery(void) lcd_puts(0, 3, buf); #endif #ifdef HAVE_CHARGE_CTRL - snprintf(buf, 30, "Chgr: %s %s", - charger_inserted() ? "present" : "absent", - charger_enabled ? "on" : "off"); - lcd_puts(0, 3, buf); + snprintf(buf, 30, "Charging: %s", + charger_enabled ? "yes" : "no"); + lcd_puts(0, 4, buf); snprintf(buf, 30, "short delta: %d", short_delta); lcd_puts(0, 5, buf); snprintf(buf, 30, "long delta: %d", long_delta); @@ -1272,7 +1274,7 @@ bool view_battery(void) } break; - case 3: /* remaining time estimation: */ + case 3: /* remeining time estimation: */ lcd_clear_display(); #ifdef HAVE_CHARGE_CTRL @@ -1284,24 +1286,23 @@ bool view_battery(void) snprintf(buf, 30, "Lvl@cyc st: %d%%", powermgmt_last_cycle_level); 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 snprintf(buf, 30, "Last PwrHist: %d.%02d V", 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()); - lcd_puts(0, 6, buf); + lcd_puts(0, 5, buf); 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); +#endif break; } diff --git a/apps/main.c b/apps/main.c index c5e5492337..36f26c9154 100644 --- a/apps/main.c +++ b/apps/main.c @@ -58,6 +58,10 @@ #include "power.h" #include "talk.h" #include "plugin.h" + + +#include "uda1380.h" + #ifdef CONFIG_TUNER #include "radio.h" #endif @@ -261,6 +265,9 @@ void init(void) } } #endif /* #ifdef AUTOROCK */ + + uda1380_init(); + } int main(void) diff --git a/apps/plugin.c b/apps/plugin.c index b4239bb8d9..ecd5025e2c 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -44,7 +44,7 @@ #include "mp3data.h" #include "powermgmt.h" #include "system.h" -#if (CONFIG_HWCODEC == MASNONE) && !defined(SIMULATOR) +#if (CONFIG_HWCODEC == MASNONE) #include "pcm_playback.h" #endif @@ -271,10 +271,12 @@ static const struct plugin_api rockbox_api = { #if CONFIG_KEYPAD == IRIVER_H100_PAD button_hold, #endif -#if (CONFIG_HWCODEC == MASNONE) && !defined(SIMULATOR) - pcm_play_data, +#if (CONFIG_HWCODEC == MASNONE) + pcm_play_data, pcm_play_stop, + pcm_set_frequency, pcm_is_playing, + pcm_set_volume #endif }; diff --git a/apps/plugin.h b/apps/plugin.h index 3755018d6d..30ecfc7963 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -43,6 +43,7 @@ #include "id3.h" #include "mpeg.h" #include "mp3_playback.h" +#include "pcm_playback.h" #include "settings.h" #include "thread.h" #include "playlist.h" @@ -317,11 +318,13 @@ struct plugin_api { #if CONFIG_KEYPAD == IRIVER_H100_PAD bool (*button_hold)(void); #endif -#if (CONFIG_HWCODEC == MASNONE) && !defined(SIMULATOR) +#if (CONFIG_HWCODEC == MASNONE) void (*pcm_play_data)(const unsigned char *start, int 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); + void (*pcm_set_volume)(int volume); #endif }; diff --git a/apps/plugins/rockboy/pcm.h b/apps/plugins/rockboy/pcm.h index 3719933520..742f0e5a95 100644 --- a/apps/plugins/rockboy/pcm.h +++ b/apps/plugins/rockboy/pcm.h @@ -9,7 +9,7 @@ struct pcm { int hz, len; int stereo; - byte *buf; + short *buf; int pos; }; diff --git a/apps/plugins/rockboy/rbsound.c b/apps/plugins/rockboy/rbsound.c index 6d1b24fd9a..92f824aa3b 100644 --- a/apps/plugins/rockboy/rbsound.c +++ b/apps/plugins/rockboy/rbsound.c @@ -1,47 +1,120 @@ - - - #include "rockmacros.h" #include "defs.h" #include "pcm.h" #include "rc.h" +#define RBSOUND 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[] = { - RCV_END + RCV_END }; - void pcm_init(void) { - pcm.hz = 44100; - pcm.stereo = 1; - pcm.buf = buf; - pcm.len = sizeof buf; - pcm.pos = 0; + buf1 = (signed short*)((((unsigned int)buf1_unal) >> 2) << 2); /* here i just make sure that buffer is aligned to 4 bytes*/ + newly_started = true; + last_back_pos = buf1; + turns = 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) { - 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) { -#ifdef RBSOUND - rb->pcm_play_data(pcm.buf,pcm.pos,NULL); - while(rb->pcm_is_playing()); /* spinlock */ - pcm.pos = 0; - return 1; +#ifdef RBSOUND + 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*/ + int shorts_left = ((((unsigned int)buf1) + BUF_SIZE) - ((unsigned int)last_back_pos)) / sizeof(short); + if( shorts_left >= pcm.pos ) + { + 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 - pcm.pos = 0; - return 0; + pcm.pos = 0; + return 0; #endif } diff --git a/apps/plugins/rockboy/rockboy.c b/apps/plugins/rockboy/rockboy.c index a34fd7bf69..c6d006a131 100644 --- a/apps/plugins/rockboy/rockboy.c +++ b/apps/plugins/rockboy/rockboy.c @@ -51,6 +51,7 @@ struct plugin_api* rb; int shut,cleanshut; char *errormsg; int gnuboy_main(char *rom); +void pcm_close(void); 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); return PLUGIN_ERROR; } - + pcm_close(); rb->splash(HZ*2, true, "Shutting down.. byebye ^^"); cleanup(); + return PLUGIN_OK; } diff --git a/apps/plugins/rockboy/sound.c b/apps/plugins/rockboy/sound.c index edf31d81b7..10fc504063 100644 --- a/apps/plugins/rockboy/sound.c +++ b/apps/plugins/rockboy/sound.c @@ -60,9 +60,9 @@ int pcm_submit(void); #define S4 (snd.ch[3]) rcvar_t sound_exports[] = - { - RCV_END - }; +{ + RCV_END +}; static void s1_freq_d(int d) @@ -275,10 +275,10 @@ void sound_mix(void) pcm_submit(); if (pcm.stereo) { - pcm.buf[pcm.pos++] = l+128; - pcm.buf[pcm.pos++] = r+128; + pcm.buf[pcm.pos++] = (signed short)(l * 256); + 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); diff --git a/firmware/drivers/uda1380.c b/firmware/drivers/uda1380.c index e8b8c14399..8c3cf61eae 100644 --- a/firmware/drivers/uda1380.c +++ b/firmware/drivers/uda1380.c @@ -49,7 +49,7 @@ unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = REG_I2S, I2S_IFMT_IIS, 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_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_EQ, 0, 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) */ int uda1380_init(void) { + PLLCR &= ~(1 << 22); /* Set AudioClk = FXTAL/2*/ + if (uda1380_set_regs() == -1) return -1; diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h index c44fb283ec..6010293bbd 100644 --- a/firmware/export/pcm_playback.h +++ b/firmware/export/pcm_playback.h @@ -19,9 +19,11 @@ #ifndef 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 (*get_more)(unsigned char** start, long* size)); void pcm_play_stop(void); bool pcm_is_playing(void); +void pcm_set_volume(int volume); #endif diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index fba85f083b..bc2218be69 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c @@ -37,20 +37,32 @@ #include "file.h" #include "buffer.h" -bool pcm_playing; +#include "sprintf.h" +#include "button.h" +#include + +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 */ -static void dma_start(const void *addr, long size) -{ +static void dma_start(const void *addr_r, long size) +{ 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 */ /* Set up DMA transfer */ 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 */ - BCR0 = size; /* Bytes to transfer */ + BCR0 = size-(align*4); /* Bytes to transfer */ DMAROUTE = (DMAROUTE & 0xffffff00) | 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; IMR &= ~(1<<14); /* bit 14 is DMA0 */ - IIS2CONFIG = 0x4300; /* CLOCKSEL = AudioClk/8 (44.1kHz), - data source = PDOR3 */ + IIS2CONFIG = (pcm_freq << 12) | 0x300; /* CLOCKSEL for right frequency + data source = PDOR3 */ - PDOR3 = 0; /* These are needed to generate FIFO empty request to DMA.. */ - PDOR3 = 0; - PDOR3 = 0; - PDOR3 = 0; - PDOR3 = 0; + for(i = 0; i < align; i++) + PDOR3 = ((unsigned int*)(addr))[i]; /* These are needed to generate FIFO empty request to DMA.. */ } /* Stops the DMA transfer and interrupt */ @@ -76,12 +84,51 @@ static void dma_stop(void) { pcm_playing = 0; DCR0 = 0; + +/* DMAROUTE &= 0xffffff00; + DMACONFIG = 0;*/ + + IIS2CONFIG = 0x800; /* Disable DMA0 interrupt */ IMR |= (1<<14); 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 */ static void (*callback_for_more)(unsigned char**, long*) = NULL; @@ -110,8 +157,15 @@ void DMA0(void) unsigned char* start; long size = 0; + int res = DSR0; + DSR0 = 1; /* Clear interrupt */ + if(res == 0x41) + { + dma_stop(); + } + if (callback_for_more) { callback_for_more(&start, &size); -- cgit v1.2.3