Rockbox Technical Forums

Rockbox Development => Starting Development and Compiling => Topic started by: gama on May 14, 2012, 09:47:29 AM

Title: [HELP] How to use rockbox dsp in audio plugin?
Post by: gama on May 14, 2012, 09:47:29 AM
Hi, i'm working on a new rockbox plugin based on vgmstream (http://sourceforge.net/projects/vgmstream/),
the plugin is based on the mikmod and midi plugins, and uses the pcm_play_data api.   

Some videogame streams has has some weird sampling rates, like 37800 Hz.  I am calling pcm_set_frequency, but it seems it only supports some sampling rates.  So i was wondering if i can use the dsp resampler to get the closest sampling rate possible.  But i'm not sure if i can use the dsp in combination with the pcm api, and how to setup the required dsp buffers for dsp_process.  Anyone can help, please?

Post Merge: May 14, 2012, 09:43:27 PM
Ok, made some progress, the code is very dirty, i'm only doing some tests with the dsp.  This is the get_more callbak used by pcm_play_data:

Code: [Select]
unsigned char dspbuffer[BUF_SIZE * 2 * 2];
static int dspbuffer_count = BUF_SIZE ;
static void get_more(const void** start, size_t* size)
{
#ifndef SYNC
    if (lastswap != swap)
    {
        //DEBUGF("Buffer miss!");
    }

#else
    synthbuf();
#endif

    /* process dsp */
    src.remcount = BUF_SIZE;
    src.pin[0] = gmbuf;
    src.pin[1] = gmbuf;
    src.proc_mask = 0;

    struct dsp_buffer dst;
    dst.remcount = 0;
    dst.p16out = (int16_t *)dspbuffer;
    dst.bufcount = dspbuffer_count;

while (1)
    {
        int old_remcount = dst.remcount;
        rb->dsp_process(dsp, &src, &dst);
       
        if (dst.bufcount <= 0 ||
            (src.remcount <= 0 && dst.remcount <= old_remcount))
        {
            /* Dest is full or no input left and DSP purged */
            break;
        }
    }

    //*size = BUF_SIZE;
*size = dst.remcount >> 1;
#ifndef SYNC
    *start = swap ? gmbuf : gmbuf + BUF_SIZE;
    swap = !swap;
#else
    //*start = gmbuf;
*start = dspbuffer;
#endif
}

The dsp is configured like this:

Code: [Select]
/* configure dsp */
dsp = rb->dsp_get_config(CODEC_IDX_AUDIO);
    rb->dsp_configure(dsp, DSP_RESET, 0);
    rb->dsp_configure(dsp, DSP_FLUSH, 0);
rb->dsp_configure(dsp, DSP_SWITCH_FREQUENCY, streamfile->sample_rate);
rb->dsp_configure(dsp, DSP_SET_STEREO_MODE,
                           streamfile->channels == 1 ? STEREO_MONO : STEREO_NONINTERLEAVED);

streamfile is an VGMSTREAM object from the vgmstream api, and the samples are rendered here:

Code: [Select]
static inline void synthbuf(void)
{
    char *outptr;

#ifndef SYNC
    if (lastswap == swap) return;
    lastswap = swap;

    outptr = (swap ? gmbuf : gmbuf + BUF_SIZE);
#else
    outptr = gmbuf;
#endif

    /* have we finished decoding? */
    current_sample += BUF_SIZE / (channels << 1);
    if( current_sample >= total_samples ) {
        exit_flag = 1;
        return;
    }
   
render_vgmstream((sample *)gmbuf, BUF_SIZE / (channels << 1), streamfile);

// playingtime += (BUF_SIZE / (channels << 1)) / 44.1;
}

The results, i can hear the music, but is sounds very noise and laggy.  Whithout the dsp code, the plugin works fine, except that the sampling frequency is set to 44100, and the song plays too fast.  My first question is, how do i setup the src buffer correctly?, i need to pass a pointer to each channel, but i only have an stereo samples buffer.

Well hope someone can take a look at the code and point me into the right direction. 
Title: Re: [HELP] How to use rockbox dsp in audio plugin?
Post by: jhMikeS on May 14, 2012, 10:02:20 PM
Yes, you can use DSP along with the PCM api, with the mixer (if you want voice and keyclick to work too) or without.

For DSP:
Will resmample to 44100 Hz (NATIVE_FREQUENCY) so set the raw PCM sample rate to that.
Use only p32[0] for interleaved stereo or mono. Set p32[1] to NULL. Look in apps/codec_thread.c or plugins/mpegplayer/audio_thread.c to see how it's done.
Any reasonable codec sample rate should work just fine no matter how "odd" it is.
DSP output is in hardware format.

For RAW PCM you must mind the hardware requirements explicitly:
Your plugin must resample to the closest rate the hardware supports that also suits your needs (try to upsample to not lose higher frequencies). The sample size is 16 bits, interleaved stereo. For mono at the codec, duplicate it into both channels. Basically, your plugin must now do what the DSP normally does.

RAW PCM with mixer:
Always NATIVE_FREQUENCY at this point but otherwise the same as raw PCM. Just take over the playback channel after stopping the core playback engine (steal the audio and talk buffer).

DSP with mixer:
Same as what the core and MPEGPlayer do.
Title: Re: [HELP] How to use rockbox dsp in audio plugin?
Post by: saratoga on May 14, 2012, 10:04:59 PM
You may also want to hang out in the IRC channel while you work so that you can ask questions in real time.
Title: Re: [HELP] How to use rockbox dsp in audio plugin?
Post by: jhMikeS on May 14, 2012, 10:08:35 PM
Crap, are you pushing through the DSP within the PCM callback? No! Not safe. You must create a buffer and in thread context process with the DSP and pull with the PCM callback (get_more) since it directly used by interrupts.
Title: Re: [HELP] How to use rockbox dsp in audio plugin?
Post by: gama on May 15, 2012, 01:37:23 PM
Thanks a lot jhMikeS for your advice, that's exactly what i was looking for ;).  Will test it ASAP.  By the way, yes i was planning to use a separate thread for the DSP process, i just wanted to get the resampler working first ;P.


Post Merge: May 15, 2012, 08:51:11 PM
[UPDATE] Ok, followed jhMikeS instructions, and got the resampler working, i still hear some clicking noise though, and i still have to figure out how to calculate the src.remcount, dst.bufcount and the *size values correctly in the get_more callback.

But most importantly i need to use a separate thread for the dsp process and thought about implementing a circular buffer to store the processed samples.  And use the resampler only in the necessary cases.  Will let you know about the results.