thestk / rtaudio

A set of C++ classes that provide a common API for realtime audio input/output across Linux (native ALSA, JACK, PulseAudio and OSS), Macintosh OS X (CoreAudio and JACK), and Windows (DirectSound, ASIO, and WASAPI) operating systems.
Other
1.49k stars 317 forks source link

Example request - Mono to Stereo #390

Closed X1l10on88 closed 1 year ago

X1l10on88 commented 1 year ago

Hello,

I have found myself embarked in the "issue" that mono is played only on the left channel, for then finding out it is by design: https://github.com/thestk/rtaudio/issues/243.

In the comment of the previous issue, there is a generic indication that I should open the stream with 2 channels and copy the mono audio in both, but there is no code example or really mention of how.

Here is my attempt which almost works, but it distorts the audio:

//audio_format_size is 2 for signed shorts
int amount_of_data_to_play_now = audio_format_size * nBufferFrames; 

if(channels == 1){

        //Works 100% fine
        memcpy(outputBuffer, oData->data, amount_of_data_to_play_now);

    //Device open with 2 channels in RtAudio::StreamParameters
    } else if(channels == 2){

        char* data_array_stereo_simulated = (char*)malloc( amount_of_data_to_play_now*2 );
        memcpy(data_array_stereo_simulated, oData->data, amount_of_data_to_play_now);
        memcpy(data_array_stereo_simulated+amount_of_data_to_play_now, oData->data, amount_of_data_to_play_now);
        memcpy(outputBuffer, data_array_stereo_simulated, amount_of_data_to_play_now*2);
        free(data_array_stereo_simulated);

    }
radarsat1 commented 1 year ago

The original version of your issue had the following code:

        char *out = (char*)outputBuffer;
        for (int i = 0; i < amount_of_data_to_play_now; i++)
        {
            *out++ = ((char*)oData->data)[i]; // left channel
            *out++ = ((char*)oData->data)[i]; // right channel
        }

Can you try like this, but replace char with short? Assuming your audio buffer format is RTAUDIO_SINT16. If you're using RTAUDIO_FLOAT32 then you should use float, etc.

You can see an example of this in the playback tutorial where a double is used because the audio format is RTAUDIO_FLOAT64.

X1l10on88 commented 1 year ago

Thank you for your answer, the solution was even more straightforward, I had to set the flag for non-interleaved play:

   // In the constructor
    if(fake_stereo == true && channels == 1){
        options.flags = RTAUDIO_NONINTERLEAVED;
        oParams.nChannels = 2;
    }

and now my callback function looks like this:

        //Play modes
        if(fake_stereo == false && channels == 1){

            memcpy(outputBuffer, oData->data, amount_of_data_to_play_now);

        } else if( fake_stereo == true && channels == 1 ){

            memcpy(outputBuffer, oData->data, amount_of_data_to_play_now);
            memcpy((char*)outputBuffer+amount_of_data_to_play_now, oData->data, amount_of_data_to_play_now);

        }