📄 mp3_playback.c
字号:
/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: mp3_playback.c,v 1.6 2004/03/02 11:32:59 linusnielsen Exp $ * * Code that has been in mpeg.c before, now creating an encapsulated play * data module, to be used by other sources than file playback as well. * * Copyright (C) 2004 by Linus Nielsen Feltzing * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/#include <stdbool.h>#include "config.h"#include "debug.h"#include "panic.h"#include <kernel.h>#include "mpeg.h" /* ToDo: remove crosslinks */#include "mp3_playback.h"#ifndef SIMULATOR#include "i2c.h"#include "mas.h"#include "dac.h"#include "system.h"#include "hwcompat.h"#endif/* hacking into mpeg.c, recording is still there */#ifdef HAVE_MAS3587Fenum{ MPEG_DECODER, MPEG_ENCODER} mpeg_mode;#endif /* #ifdef HAVE_MAS3587F *//**** globals ****//* own version, independent of mpeg.c */static bool paused; /* playback is paused */static bool playing; /* We are playing an MP3 stream */#ifndef SIMULATOR/* for measuring the play time */static long playstart_tick;static long cumulative_ticks;/* the registered callback function to ask for more mp3 data */static void (*callback_for_more)(unsigned char**, int*);#endif /* #ifndef SIMULATOR */static char *units[] ={ "%", /* Volume */ "dB", /* Bass */ "dB", /* Treble */ "%", /* Balance */ "dB", /* Loudness */ "%", /* Bass boost */ "", /* AVC */ "", /* Channels */ "dB", /* Left gain */ "dB", /* Right gain */ "dB", /* Mic gain */};static int numdecimals[] ={ 0, /* Volume */ 0, /* Bass */ 0, /* Treble */ 0, /* Balance */ 0, /* Loudness */ 0, /* Bass boost */ 0, /* AVC */ 0, /* Channels */ 1, /* Left gain */ 1, /* Right gain */ 1, /* Mic gain */};static int minval[] ={ 0, /* Volume */ 0, /* Bass */ 0, /* Treble */ -50, /* Balance */ 0, /* Loudness */ 0, /* Bass boost */ -1, /* AVC */ 0, /* Channels */ 0, /* Left gain */ 0, /* Right gain */ 0, /* Mic gain */};static int maxval[] ={ 100, /* Volume */#ifdef HAVE_MAS3587F 24, /* Bass */ 24, /* Treble */#else 30, /* Bass */ 30, /* Treble */#endif 50, /* Balance */ 17, /* Loudness */ 10, /* Bass boost */ 3, /* AVC */ 6, /* Channels */ 15, /* Left gain */ 15, /* Right gain */ 15, /* Mic gain */};static int defaultval[] ={ 70, /* Volume */#ifdef HAVE_MAS3587F 12+6, /* Bass */ 12+6, /* Treble */#else 15+7, /* Bass */ 15+7, /* Treble */#endif 0, /* Balance */ 0, /* Loudness */ 0, /* Bass boost */ 0, /* AVC */ 0, /* Channels */ 8, /* Left gain */ 8, /* Right gain */ 2, /* Mic gain */};char *mpeg_sound_unit(int setting){ return units[setting];}int mpeg_sound_numdecimals(int setting){ return numdecimals[setting];}int mpeg_sound_min(int setting){ return minval[setting];}int mpeg_sound_max(int setting){ return maxval[setting];}int mpeg_sound_default(int setting){ return defaultval[setting];}/* list of tracks in memory */#define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */#define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1)#ifndef SIMULATORstatic bool mpeg_is_initialized = false;#endif#ifndef SIMULATORunsigned long mas_version_code;#ifdef HAVE_MAS3507Dstatic unsigned int bass_table[] ={ 0x9e400, /* -15dB */ 0xa2800, /* -14dB */ 0xa7400, /* -13dB */ 0xac400, /* -12dB */ 0xb1800, /* -11dB */ 0xb7400, /* -10dB */ 0xbd400, /* -9dB */ 0xc3c00, /* -8dB */ 0xca400, /* -7dB */ 0xd1800, /* -6dB */ 0xd8c00, /* -5dB */ 0xe0400, /* -4dB */ 0xe8000, /* -3dB */ 0xefc00, /* -2dB */ 0xf7c00, /* -1dB */ 0, 0x800, /* 1dB */ 0x10000, /* 2dB */ 0x17c00, /* 3dB */ 0x1f800, /* 4dB */ 0x27000, /* 5dB */ 0x2e400, /* 6dB */ 0x35800, /* 7dB */ 0x3c000, /* 8dB */ 0x42800, /* 9dB */ 0x48800, /* 10dB */ 0x4e400, /* 11dB */ 0x53800, /* 12dB */ 0x58800, /* 13dB */ 0x5d400, /* 14dB */ 0x61800 /* 15dB */};static unsigned int treble_table[] ={ 0xb2c00, /* -15dB */ 0xbb400, /* -14dB */ 0xc1800, /* -13dB */ 0xc6c00, /* -12dB */ 0xcbc00, /* -11dB */ 0xd0400, /* -10dB */ 0xd5000, /* -9dB */ 0xd9800, /* -8dB */ 0xde000, /* -7dB */ 0xe2800, /* -6dB */ 0xe7e00, /* -5dB */ 0xec000, /* -4dB */ 0xf0c00, /* -3dB */ 0xf5c00, /* -2dB */ 0xfac00, /* -1dB */ 0, 0x5400, /* 1dB */ 0xac00, /* 2dB */ 0x10400, /* 3dB */ 0x16000, /* 4dB */ 0x1c000, /* 5dB */ 0x22400, /* 6dB */ 0x28400, /* 7dB */ 0x2ec00, /* 8dB */ 0x35400, /* 9dB */ 0x3c000, /* 10dB */ 0x42c00, /* 11dB */ 0x49c00, /* 12dB */ 0x51800, /* 13dB */ 0x58400, /* 14dB */ 0x5f800 /* 15dB */};static unsigned int prescale_table[] ={ 0x80000, /* 0db */ 0x8e000, /* 1dB */ 0x9a400, /* 2dB */ 0xa5800, /* 3dB */ 0xaf400, /* 4dB */ 0xb8000, /* 5dB */ 0xbfc00, /* 6dB */ 0xc6c00, /* 7dB */ 0xcd000, /* 8dB */ 0xd25c0, /* 9dB */ 0xd7800, /* 10dB */ 0xdc000, /* 11dB */ 0xdfc00, /* 12dB */ 0xe3400, /* 13dB */ 0xe6800, /* 14dB */ 0xe9400 /* 15dB */};#endifbool dma_on; /* The DMA is active */#ifdef HAVE_MAS3507Dstatic void mas_poll_start(int interval_in_ms){ unsigned int count; count = (FREQ * interval_in_ms) / 1000 / 8; if(count > 0xffff) { panicf("Error! The MAS poll interval is too long (%d ms)\n", interval_in_ms); return; } /* We are using timer 1 */ TSTR &= ~0x02; /* Stop the timer */ TSNC &= ~0x02; /* No synchronization */ TMDR &= ~0x02; /* Operate normally */ TCNT1 = 0; /* Start counting at 0 */ GRA1 = count; TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */ /* Enable interrupt on level 5 */ IPRC = (IPRC & ~0x000f) | 0x0005; TSR1 &= ~0x02; TIER1 = 0xf9; /* Enable GRA match interrupt */ TSTR |= 0x02; /* Start timer 1 */}#elsestatic void postpone_dma_tick(void){ unsigned int count; count = FREQ / 1000 / 8; /* We are using timer 1 */ TSTR &= ~0x02; /* Stop the timer */ TSNC &= ~0x02; /* No synchronization */ TMDR &= ~0x02; /* Operate normally */ TCNT1 = 0; /* Start counting at 0 */ GRA1 = count; TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */ /* Enable interrupt on level 5 */ IPRC = (IPRC & ~0x000f) | 0x0005; TSR1 &= ~0x02; TIER1 = 0xf9; /* Enable GRA match interrupt */ TSTR |= 0x02; /* Start timer 1 */}#endif#ifdef HAVE_MAS3587Fvoid demand_irq_enable(bool on){ int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); if(on) { IPRA = (IPRA & 0xfff0) | 0x000b; ICR &= ~0x0010; /* IRQ3 level sensitive */ } else IPRA &= 0xfff0; set_irq_level(oldlevel);}#endif /* #ifdef HAVE_MAS3587F */void play_tick(void){ if(playing && !paused) { /* Start DMA if it is disabled and the DEMAND pin is high */ if(!(SCR0 & 0x80) && (PBDR & 0x4000)) { SCR0 |= 0x80; } playback_tick(); /* dirty call to mpeg.c */ }}#pragma interruptvoid DEI3(void){ unsigned char* start; int size = 0; if (callback_for_more != NULL) { callback_for_more(&start, &size); } if (size > 0) { DTCR3 = size & 0xffff; SAR3 = (unsigned int) start; } else { CHCR3 &= ~0x0001; /* Disable the DMA interrupt */ } CHCR3 &= ~0x0002; /* Clear DMA interrupt */}#pragma interruptvoid IMIA1(void) /* Timer 1 interrupt */{ if(playing) play_tick(); TSR1 &= ~0x01;#ifdef HAVE_MAS3587F /* Disable interrupt */ IPRC &= ~0x000f;#endif /* #ifdef HAVE_MAS3587F */}#pragma interruptvoid IRQ6(void) /* PB14: MAS stop demand IRQ */{ SCR0 &= ~0x80;}#ifdef HAVE_MAS3587F#pragma interruptvoid IRQ3(void) /* PA15: MAS demand IRQ */{ /* Begin with setting the IRQ to edge sensitive */ ICR |= 0x0010; if(mpeg_mode == MPEG_ENCODER) rec_tick(); else postpone_dma_tick();}#endif /* #ifdef HAVE_MAS3587F */static void setup_sci0(void){ /* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0, PB9 is TxD0 */ PBCR1 = (PBCR1 & 0x0cff) | 0x1208; /* Set PB12 to output */ or_b(0x10, &PBIORH); /* Disable serial port */ SCR0 = 0x00; /* Synchronous, no prescale */ SMR0 = 0x80; /* Set baudrate 1Mbit/s */ BRR0 = 0x03; /* use SCK as serial clock output */ SCR0 = 0x01; /* Clear FER and PER */ SSR0 &= 0xe7; /* Set interrupt ITU2 and SCI0 priority to 0 */ IPRD &= 0x0ff0; /* set PB15 and PB14 to inputs */ and_b(~0x80, &PBIORH); and_b(~0x40, &PBIORH); /* Enable End of DMA interrupt at prio 8 */ IPRC = (IPRC & 0xf0ff) | 0x0800; /* Enable Tx (only!) */ SCR0 |= 0x20;}#endif /* SIMULATOR */#ifdef HAVE_MAS3587Fstatic void init_playback(void){ unsigned long val; int rc; mp3_play_pause(false); mas_reset(); /* Enable the audio CODEC and the DSP core, max analog voltage range */ rc = mas_direct_config_write(MAS_CONTROL, 0x8c00); if(rc < 0) panicf("mas_ctrl_w: %d", rc); /* Stop the current application */ val = 0; mas_writemem(MAS_BANK_D0,0x7f6,&val,1); do { mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1); } while(val); /* Enable the D/A Converter */ mas_codec_writereg(0x0, 0x0001); /* ADC scale 0%, DSP scale 100% */ mas_codec_writereg(6, 0x0000); mas_codec_writereg(7, 0x4000); /* Disable SDO and SDI */ val = 0x0d; mas_writemem(MAS_BANK_D0,0x7f2,&val,1); /* Set Demand mode and validate all settings */ val = 0x25; mas_writemem(MAS_BANK_D0,0x7f1,&val,1); /* Start the Layer2/3 decoder applications */ val = 0x0c; mas_writemem(MAS_BANK_D0,0x7f6,&val,1); do { mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1); } while((val & 0x0c) != 0x0c); mpeg_sound_channel_config(MPEG_SOUND_STEREO); mpeg_mode = MPEG_DECODER; /* set IRQ6 to edge detect */ ICR |= 0x02; /* set IRQ6 prio 8 */ IPRB = ( IPRB & 0xff0f ) | 0x0080; DEBUGF("MAS Decoding application started\n");}#endif /* #ifdef HAVE_MAS3587F */#ifndef SIMULATOR#ifdef HAVE_MAS3507Dint current_left_volume = 0; /* all values in tenth of dB */int current_right_volume = 0; /* all values in tenth of dB */int current_treble = 0;int current_bass = 0;int current_balance = 0;/* convert tenth of dB volume to register value */static int tenthdb2reg(int db) { if (db < -540) return (db + 780) / 30; else return (db + 660) / 15;}void set_prescaled_volume(void){ int prescale; int l, r; prescale = MAX(current_bass, current_treble); if (prescale < 0) prescale = 0; /* no need to prescale if we don't boost bass or treble */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -