Add the RTOS processing. for the Network radio streaming receiver.

Fork of VS1053b by Christian Schmiljun

VS1053.cpp

Committer:
ban4jp
Date:
2015-02-22
Revision:
10:114ac02a3875
Parent:
8:5e4a21202223

File content as of revision 10:114ac02a3875:

/* mbed VLSI VS1053b library
 * Copyright (c) 2010 Christian Schmiljun
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
 
/* This code based on:
 *  mbeduino_MP3_Shield_MP3Player
 *  http://mbed.org/users/xshige/programs/mbeduino_MP3_Shield_MP3Player/lgcx63
 *  2010-10-16
 */
 
#include "VS1053.h"
#include "mbed.h"

// patch binarys
#include "Patches/VS1053b_patch_1_5.c"
#include "Patches/VS1053b_patch_1_5_flac.c"
#include "Patches/VS1053b_patch_1_4_flac.c"
#include "Patches/VS1053b_specana_0_9.c"
#include "Patches/VS1053b_pcm_recorder_0_9.c"

const char VS1053::_sampleRateTable[4][4] = {
    11, 12, 8, 0,
    11, 12, 8, 0,
    22, 24, 16, 0,
    44, 48, 32, 0
};

/* ==================================================================
 * Constructor
 * =================================================================*/
VS1053::VS1053(
    PinName mosi, PinName miso, PinName sck, PinName cs, PinName rst,
    PinName dreq, PinName dcs, char* buffer, int buffer_size)
        :
        _spi(mosi, miso, sck),
        _CS(cs),
        _RST(rst),
        _DCS(dcs),
        _DREQ(dreq),        
#ifdef DEBUG
        _led(D8),
#endif
#ifdef VS1053_RTOS
        _thread(VS1053::dataRequestHandler_start, this, osPriorityNormal, 1024)
#else
        _DREQ_INTERUPT_IN(dreq) 
#endif
{           
        cs_high();
        dcs_high();

        _volume = DEFAULT_VOLUME;
        _balance = DEFAULT_BALANCE_DIFERENCE_LEFT_RIGHT;
        _sb_amplitude = DEFAULT_BASS_AMPLITUDE;
        _sb_freqlimit = DEFAULT_BASS_FREQUENCY;
        _st_amplitude = DEFAULT_TREBLE_AMPLITUDE;
        _st_freqlimit = DEFAULT_TREBLE_FREQUENCY;   
        _buffer = buffer;
        BUFFER_SIZE = buffer_size;
#ifndef VS1053_RTOS
        _DREQ_INTERUPT_IN.mode(PullDown);
#endif
        INTERRUPT_HANDLER_DISABLE;
        bufferReset();
        
#ifdef VS1053_RTOS
        _thread.signal_set(START_THREAD);
#endif
}


/*===================================================================
 * Functions
 *==================================================================*/

void VS1053::cs_low(void) {
    _CS = 0;
}
void VS1053::cs_high(void) {
    _CS = 1;
}
void VS1053::dcs_low(void) {
    _DCS = 0;

}
void VS1053::dcs_high(void) {
    _DCS = 1;
}
void VS1053::sci_en(void) {                  //SCI enable
    cs_high();
    dcs_high();
    cs_low();
}
void VS1053::sci_dis(void) {                  //SCI disable
    cs_high();
}
void VS1053::sdi_en(void) {                  //SDI enable
    dcs_high();
    cs_high();
    dcs_low();
}
void VS1053::sdi_dis(void) {                  //SDI disable
    dcs_high();
}
void VS1053::reset(void) {                  //hardware reset
    INTERRUPT_HANDLER_DISABLE;
    wait_ms(10);
    _RST = 0;
    wait_ms(5);
    _RST = 1;
    wait_ms(10);
}
void VS1053::power_down(void) {              //hardware and software reset
    cs_low();
    reset();
//    sci_write(0x00, SM_PDOWN);
    sci_write(0x00, 0x10); // tempo
    wait(0.01);
    reset();
}
void VS1053::spi_initialise(void) {
    _RST = 1;                                //no reset
    _spi.format(8,0);                        //spi 8bit interface, steady state low
//   _spi.frequency(1000000);                //rising edge data record, freq. 1Mhz
    _spi.frequency(2000000);                //rising edge data record, freq. 2Mhz


    cs_low();
    for (int i=0; i<4; i++) {
        _spi.write(0xFF);                        //clock the chip a bit
    }
    cs_high();
    dcs_high();
    wait_us(5);
}
void VS1053::sdi_initialise(void) {
    _spi.frequency(8000000);                //set to 8 MHz to make fast transfer
    cs_high();
    dcs_high();
}
void VS1053::sci_write(unsigned char address, unsigned short int data) {
    // TODO disable all interrupts
    __disable_irq();
    sci_en();                                //enables SCI/disables SDI

    while (!_DREQ);                           //wait unitl data request is high
    _spi.write(0x02);                        //SCI write
    _spi.write(address);                    //register address
    _spi.write((data >> 8) & 0xFF);            //write out first half of data word
    _spi.write(data & 0xFF);                //write out second half of data word

    sci_dis();                                //enables SDI/disables SCI
    wait_us(5);
    
    // TODO enable all interrupts
    __enable_irq();
}
void VS1053::sdi_write(unsigned char datum) {    
    
    sdi_en();

    while (!_DREQ);
    _spi.write(datum);

    sdi_dis();    
}
unsigned short VS1053::sci_read(unsigned short int address) {
    // TODO disable all interrupts
    __disable_irq();
    
    cs_low();                                //enables SCI/disables SDI

    while (!_DREQ);                           //wait unitl data request is high
    _spi.write(0x03);                        //SCI write
    _spi.write(address);                    //register address
    unsigned short int received = _spi.write(0x00);    //write out dummy byte
    received <<= 8;
    received |= _spi.write(0x00);            //write out dummy byte

    cs_high();                                //enables SDI/disables SCI

    // TODO enable all interrupts
    __enable_irq();
    return received;                        //return received word
}
void VS1053::sine_test_activate(unsigned char wave) {
    cs_high();                                //enables SDI/disables SCI

    while (!_DREQ);                           //wait unitl data request is high
    _spi.write(0x53);                        //SDI write
    _spi.write(0xEF);                        //SDI write
    _spi.write(0x6E);                        //SDI write
    _spi.write(wave);                        //SDI write
    _spi.write(0x00);                        //filler byte
    _spi.write(0x00);                        //filler byte
    _spi.write(0x00);                        //filler byte
    _spi.write(0x00);                        //filler byte

    cs_low();                                //enables SCI/disables SDI
}
void VS1053::sine_test_deactivate(void) {
    cs_high();

    while (!_DREQ);
    _spi.write(0x45);                        //SDI write
    _spi.write(0x78);                        //SDI write
    _spi.write(0x69);                        //SDI write
    _spi.write(0x74);                        //SDI write
    _spi.write(0x00);                        //filler byte
    _spi.write(0x00);                        //filler byte
    _spi.write(0x00);                        //filler byte
    _spi.write(0x00);                        //filler byte
}

unsigned short int VS1053::wram_read(unsigned short int address) {
    unsigned short int tmp1,tmp2;
    sci_write(SCI_WRAMADDR,address);
    tmp1=sci_read(SCI_WRAM);
    sci_write(SCI_WRAMADDR,address);
    tmp2=sci_read(SCI_WRAM);
    if (tmp1==tmp2) return tmp1;
    sci_write(SCI_WRAMADDR,address);
    tmp1=sci_read(SCI_WRAM);
    if (tmp1==tmp2) return tmp1;
    sci_write(SCI_WRAMADDR,address);
    tmp1=sci_read(SCI_WRAM);
    if (tmp1==tmp2) return tmp1;
    return tmp1;
}

void VS1053::wram_write(unsigned short int address, unsigned short int data) {
    sci_write(SCI_WRAMADDR,address);
    sci_write(SCI_WRAM,data);
    return;
}

void VS1053::setPlaySpeed(unsigned short speed)
{
    wram_write(para_playSpeed, speed);
    DEBUGOUT("VS1053b: Change speed. New speed: %d\r\n", speed);
}

void VS1053::terminateStream(void) {
    while(bufferCount() > 0) 
        ;
    DEBUGOUT("VS1053b: Song terminating..\r\n");
    // send at least 2052 bytes of endFillByte[7:0].
    // read endFillByte  (0 .. 15) from wram 
    unsigned short endFillByte=wram_read(para_endFillByte);
    // clear endFillByte (8 .. 15)
    endFillByte = endFillByte ^0x00FF;                          
    for (int n = 0; n < 2052; n++) 
        sdi_write(endFillByte);
    
    // set SCI MODE bit SM CANCEL    
    unsigned short sciModeByte = sci_read(SCI_MODE);        
    sciModeByte |= SM_CANCEL;    
    sci_write(SCI_MODE, sciModeByte);
           
    // send up 2048 bytes of endFillByte[7:0]. 
    for (int i = 0; i < 64; i++) 
    { 
        // send at least 32 bytes of endFillByte[7:0]
        for (int n = 0; n < 32; n++) 
            sdi_write(endFillByte);
        // read SCI MODE; if SM CANCEL is still set, repeat
        sciModeByte = sci_read(SCI_MODE);    
        if ((sciModeByte & SM_CANCEL) == 0x0000)
        {
            break;
        }
    }
    
    if ((sciModeByte & SM_CANCEL) == 0x0000)
    {    
        DEBUGOUT("VS1053b: Song sucessfully sent. Terminating OK\r\n");
        DEBUGOUT("VS1053b: SCI MODE = %#x, SM_CANCEL = %#x\r\n", sciModeByte, sciModeByte & SM_CANCEL);
        sci_write(SCI_DECODE_TIME, 0x0000);
    }        
    else
    {
        DEBUGOUT("VS1053b: SM CANCEL hasn't cleared after sending 2048 bytes, do software reset\r\n");
        DEBUGOUT("VS1053b: SCI MODE = %#x, SM_CANCEL = %#x\r\n", sciModeByte, sciModeByte & SM_CANCEL);                
        initialize();
    }    
}

void VS1053::write_plugin(const unsigned short *plugin, unsigned int len) {
    unsigned int i;
    unsigned short addr, n, val;

    for (i=0; i<len;) {
        addr = plugin[i++];
        n    = plugin[i++];
        if (n & 0x8000U) { //RLE run, replicate n samples
            n  &= 0x7FFF;
            val = plugin[i++];
            while (n--) {
                sci_write(addr,val);
            }
        } else { //copy run, copy n sample
            while (n--) {
                val = plugin[i++];
                sci_write(addr,val);
            }
        }
    }

    return;
}


bool VS1053::initialize(void) {
    _RST = 1;
    cs_high();                           //chip disabled
    spi_initialise();                    //initialise MBED
        
    sci_write(SCI_MODE, (SM_SDINEW+SM_RESET)); //  set mode reg.    
    wait_ms(10);
    
#ifdef DEBUG    
    unsigned int info = wram_read(para_chipID_0);
    DEBUGOUT("VS1053b: ChipID_0:%04X\r\n", info);
    info = wram_read(para_chipID_1);
    DEBUGOUT("VS1053b: ChipID_1:%04X\r\n", info);
    info = wram_read(para_version);
    DEBUGOUT("VS1053b: Structure version:%04X\r\n", info);
#endif

    //get chip version, set clock multiplier and load patch
    int i = (sci_read(SCI_STATUS) & 0xF0) >> 4;
    if (i == 4) {
    
        DEBUGOUT("VS1053b: Installed Chip is: VS1053\r\n");
  
        sci_write(SCI_CLOCKF, (SC_MULT_XTALIx50));
        wait_ms(10);
#ifdef VS_PATCH
        // loading patch
        write_plugin(vs1053b_patch, sizeof(vs1053b_patch)/2);        
    
        DEBUGOUT("VS1053b: Patch is loaded.\r\n");
        DEBUGOUT("VS1053b: Patch size:%d bytes\r\n",sizeof(vs1053b_patch));
        
#endif // VS_PATCH
    } 
    else 
    {
        DEBUGOUT("VS1053b: Not Supported Chip\r\n");
        return false;
    }
    
    // change spi to higher speed 
    sdi_initialise();                
    changeVolume();
    changeBass();    
    _isIdle = true;
    _isPlay = false;
    return true;
}

void VS1053::setVolume(float vol) 
{    
    if (vol > -0.5)
        _volume = -0.5;
    else
        _volume = vol;

    changeVolume();
}

float VS1053::getVolume(void) 
{
    return _volume;
}

void VS1053::setBalance(float balance) 
{    
    _balance = balance;
            
    changeVolume();
}

float VS1053::getBalance(void)
{
    return _balance;    
}

void VS1053::changeVolume(void) 
{
    // volume calculation        
    unsigned short volCalced = (((char)(_volume / -0.5f)) << 8) + (char)((_volume - _balance) / -0.5f);
   
    sci_write(SCI_VOL, volCalced);
    
    DEBUGOUT("VS1053b: Change volume to %#x (%f, Balance = %f)\r\n", volCalced, _volume, _balance);        
}

int VS1053::getTrebleFrequency(void)
{
    return _st_freqlimit * 1000;
}


void VS1053::setTrebleFrequency(int frequency)
{
    frequency /= 1000;
    
    if(frequency < 1)
    {
        frequency = 1;
    }
    else if(frequency > 15)
    {
        frequency = 15;
    }
    _st_freqlimit = frequency;
    changeBass();
}
    
int VS1053::getTrebleAmplitude(void)
{
    return _st_amplitude;
}

void VS1053::setTrebleAmplitude(int amplitude)
{
    if(amplitude < -8)
    {
        amplitude = -8;
    }
    else if(amplitude > 7)
    {
        amplitude = 7;
    }
    _st_amplitude = amplitude;
    changeBass();
}   
    
int VS1053::getBassFrequency(void)
{
    return _sb_freqlimit * 10;
}

void VS1053::setBassFrequency(int frequency)
{
    frequency /= 10;
    
    if(frequency < 2)
    {
        frequency = 2;
    }
    else if(frequency > 15)
    {
        frequency = 15;
    }
    _sb_freqlimit = frequency;
    changeBass();
}  
    
int VS1053::getBassAmplitude(void)
{
    return _sb_amplitude;
}

void VS1053::setBassAmplitude(int amplitude)
{
    if(amplitude < -15)
    {
        amplitude = -15;
    }
    else if(amplitude > 0)
    {
        amplitude = 0;
    }
    _sb_amplitude = amplitude;
    changeBass();
}

void VS1053::changeBass(void)
{
    unsigned short bassCalced = ((_st_amplitude  & 0x0f) << 12) 
                              | ((_st_freqlimit  & 0x0f) <<  8) 
                              | ((_sb_amplitude  & 0x0f) <<  4) 
                              | ((_sb_freqlimit  & 0x0f) <<  0);
                            
    sci_write(SCI_BASS, bassCalced);    
    
    DEBUGOUT("VS1053b: Change bass settings to:\r\n")
    DEBUGOUT("VS1053b: --Treble: Amplitude=%i, Frequency=%i\r\n", getTrebleAmplitude(), getTrebleFrequency());
    DEBUGOUT("VS1053b: --Bass:   Amplitude=%i, Frequency=%i\r\n", getBassAmplitude(), getBassFrequency());
}

/*===================================================================
 * Buffer handling
 *==================================================================*/
 
unsigned int VS1053::bufferLength(void)
{
    return BUFFER_SIZE; 
} 

unsigned char VS1053::bufferGetByte(void)
{    
    unsigned char retVal = 0x00;
    if (bufferCount() > 0x00)
    {        
        retVal = *_bufferReadPointer++;         
        if (_bufferReadPointer >= _buffer + BUFFER_SIZE)
        {
            _bufferReadPointer = _buffer;
        }     
    }
    return retVal;
}

bool VS1053::bufferSetByte(char c)
{
    if (bufferFree() > 0x00)
    {        
        *_bufferWritePointer++ = c;        
        if (_bufferWritePointer >= _buffer + BUFFER_SIZE)
        {
            _bufferWritePointer = _buffer;
        }        
        return true;
    }
    return false;
}

bool VS1053::bufferPutStream(const char *s, unsigned int length)
{
    if (bufferFree() >= length)
    {
        while (length--)
        {
            *_bufferWritePointer++ = *s++;                        
            if (_bufferWritePointer >= _buffer + BUFFER_SIZE)
            {
                _bufferWritePointer = _buffer;
            }
        }
        return true;
    }
    return false;
}
    
unsigned int VS1053::bufferFree(void)
{
    if(_bufferReadPointer > _bufferWritePointer)
    {
        return _bufferReadPointer - _bufferWritePointer - 1;
    }
    else if(_bufferReadPointer < _bufferWritePointer)
    {
        return BUFFER_SIZE - (_bufferWritePointer - _bufferReadPointer) - 1;
    }        
    return BUFFER_SIZE - 1;
}

unsigned int VS1053::bufferCount(void)
{    
    return BUFFER_SIZE - bufferFree() - 1;
}

void VS1053::bufferReset(void)
{
    _bufferReadPointer = _buffer;
    _bufferWritePointer = _buffer;            
}

#ifdef VS1053_RTOS
void VS1053::dataRequestHandler_start(const void *args)
{
    VS1053 *instance = (VS1053*)args;
    instance->dataRequestHandler();
}
#endif

void VS1053::dataRequestHandler(void)
{    
#ifdef VS1053_RTOS
    _thread.signal_wait(START_THREAD);
    
    while(1)
    {
        if (!_DREQ || !_isPlay) {
            Thread::wait(10);
            continue;
        }
#else
    if (_isIdle && _DREQ) 
    {
#endif
        _isIdle = false;

#ifdef DEBUG
        _led = 0;
#endif

        // write buffer to vs1053b
        unsigned length = bufferCount();        
        int i = 0;   
        sdi_en();
          
        while (length > 0)
        {
            int l2 = (length > 32) ? 32 : length;        
            //DEBUGOUT("L2: %i\r\n", l2);    
            for( ; l2 != 0; l2--)
            {
                _spi.write(bufferGetByte());            
            }
            
            length -= l2;
            
            //wait_us(50);
    
            if (!_DREQ || i > 4)
                break;    
            i++;
        }
        
        sdi_dis();   

#ifdef DEBUG
        _led = 1;
#endif
        
        _isIdle = true;

#ifdef VS1053_RTOS
        //Thread::wait(10);
        Thread::yield();
#endif
    }               
}

void VS1053::play(void)
{
    INTERRUPT_HANDLER_ENABLE;
    DEBUGOUT("VS1053b: Play.\r\n");
}

void VS1053::pause(void)
{
    INTERRUPT_HANDLER_DISABLE;
    DEBUGOUT("VS1053b: Pause.\r\n");
#ifdef DEBUG
    _led = 1;
#endif
}

void VS1053::stop(void)
{
    INTERRUPT_HANDLER_DISABLE;
#ifndef VS1053_RTOS
    __disable_irq();
#endif
    DEBUGOUT("VS1053b: Song stoping..\r\n");
    while(!_isIdle) 
        ;
        
    // set SCI MODE bit SM CANCEL    
    unsigned short sciModeByte = sci_read(SCI_MODE);        
    sciModeByte |= SM_CANCEL;    
    sci_write(SCI_MODE, sciModeByte);
    
    // send up 2048 bytes of audio data. 
    for (int i = 0; i < 64; i++) 
    { 
        // send at least 32 bytes of audio data
        int z = bufferCount();
        if (z > 32)
            z = 32;
        for (int n = 0; n < z; n++) 
        {            
            _spi.write(bufferGetByte()); 
        }
        // read SCI MODE; if SM CANCEL is still set, repeat
        sciModeByte = sci_read(SCI_MODE);    
        if ((sciModeByte & SM_CANCEL) == 0x0000)
        {
            break;
        }
    }
    
    if ((sciModeByte & SM_CANCEL) == 0x0000)
    {    
        // send at least 2052 bytes of endFillByte[7:0].
        // read endFillByte  (0 .. 15) from wram 
        unsigned short endFillByte=wram_read(para_endFillByte);
        // clear endFillByte (8 .. 15)
        endFillByte = endFillByte ^0x00FF;                          
        for (int n = 0; n < 2052; n++) 
            sdi_write(endFillByte); 
        DEBUGOUT("VS1053b: Song sucessfully stopped.\r\n");
        DEBUGOUT("VS1053b: SCI MODE = %#x, SM_CANCEL = %#x\r\n", sciModeByte, sciModeByte & SM_CANCEL);
        sci_write(SCI_DECODE_TIME, 0x0000);
    }
    else
    {
        DEBUGOUT("VS1053b: SM CANCEL hasn't cleared after sending 2048 bytes, do software reset\r\n");
        DEBUGOUT("VS1053b: SCI MODE = %#x, SM_CANCEL = %#x\r\n", sciModeByte, sciModeByte & SM_CANCEL);                
        initialize();
    }
            
    bufferReset();  
#ifndef VS1053_RTOS
    __enable_irq();  
#endif
}

void VS1053::getAudioInfo(AudioInfo* aInfo)
{
    // volume calculation        
    unsigned short hdat0 = sci_read(SCI_HDAT0);
    unsigned short hdat1 = sci_read(SCI_HDAT1);
    
    DEBUGOUT("VS1053b: Audio info\r\n");        
    
    AudioInfo* retVal = aInfo;
    retVal->type = UNKNOWN;        
    
    if (hdat1 == 0x7665)
    {
        // audio is WAV
        retVal->type = WAV;
    }  
    else if (hdat1 == 0x4154 || hdat1 == 0x4144 || hdat1 == 0x4D34 )
    {
        // audio  is AAC
        retVal->type = AAC;
    }
    else if (hdat1 == 0x574D )
    {
        // audio  is WMA
        retVal->type = WMA;
    }
    else if (hdat1 == 0x4D54 )
    {
        // audio  is MIDI
        retVal->type = MIDI;
    }
    else if (hdat1 == 0x4F76 )
    {
        // audio  is OGG VORBIS
        retVal->type = OGG_VORBIS;
    }
    else if (hdat1 >= 0xFFE0 &&  hdat1 <= 0xFFFF)
    {
        // audio  is mp3
        retVal->type = MP3;
        
        DEBUGOUT("VS1053b:   Audio is mp3\r\n");        
        retVal->ext.mp3.id =      (MP3_ID)((hdat1 >>  3) & 0x0003);
        switch((hdat1 >>  1) & 0x0003)
        {
        case 3:
            retVal->ext.mp3.layer = 1;    
            break;
        case 2:
            retVal->ext.mp3.layer = 2;    
            break;
        case 1:
            retVal->ext.mp3.layer = 3;    
            break;            
        default:
            retVal->ext.mp3.layer = 0;
            break;            
        }        
        retVal->ext.mp3.protrectBit =    (hdat1 >>  0) & 0x0001;                
        
        char srate =    (hdat0 >> 10) & 0x0003;       
        retVal->ext.mp3.kSampleRate = _sampleRateTable[retVal->ext.mp3.id][srate];
        
        retVal->ext.mp3.padBit =         (hdat0 >>  9) & 0x0001;
        retVal->ext.mp3.mode =(MP3_MODE)((hdat0 >>  6) & 0x0003);
        retVal->ext.mp3.extension =      (hdat0 >>  4) & 0x0003;
        retVal->ext.mp3.copyright =      (hdat0 >>  3) & 0x0001;
        retVal->ext.mp3.original =       (hdat0 >>  2) & 0x0001;
        retVal->ext.mp3.emphasis =       (hdat0 >>  0) & 0x0003;
        
        DEBUGOUT("VS1053b:  ID: %i, Layer: %i, Samplerate: %i, Mode: %i\r\n", retVal->ext.mp3.id, retVal->ext.mp3.layer, retVal->ext.mp3.kSampleRate, retVal->ext.mp3.mode);        
    }
    
    // read byteRate
    unsigned short byteRate = wram_read(para_byteRate);
    retVal->kBitRate = (byteRate * 8) / 1000;
    DEBUGOUT("VS1053b:  BitRate: %i kBit/s\r\n", retVal->kBitRate);
    
    // decode time
    retVal->decodeTime = sci_read(SCI_DECODE_TIME);    
    DEBUGOUT("VS1053b:  Decodetime: %i s\r\n", retVal->decodeTime);
                  
}