float AudioTransport::ticksToMillis(float t_ticks) const {
    return samplesToMillis(ticksToSamples(t_ticks));
}
示例#2
0
int AudioSource::mixWith( struct timespec ticks, uint8_t* outSamples, int outBytes, int outBitDepth, int outNbChannels, int outFrequency, float outVolume)
{
    if (state != SOURCE_PLAYING)
        return -1;

    if (buffer_queue.empty())
        return -1;

    debuglog(LCF_SOUND | LCF_FRAME, "Start mixing source ", id);

    AudioBuffer* curBuf = buffer_queue[queue_index];

#if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK)
    /* Get the sample format */
    AVSampleFormat inFormat, outFormat;
    switch (curBuf->format) {
        case SAMPLE_FMT_U8:
            inFormat = AV_SAMPLE_FMT_U8;
            break;
        case SAMPLE_FMT_S16:
        case SAMPLE_FMT_MSADPCM:
            inFormat = AV_SAMPLE_FMT_S16;
            break;
        case SAMPLE_FMT_S32:
            inFormat = AV_SAMPLE_FMT_S32;
            break;
        case SAMPLE_FMT_FLT:
            inFormat = AV_SAMPLE_FMT_FLT;
            break;
        case SAMPLE_FMT_DBL:
            inFormat = AV_SAMPLE_FMT_DBL;
            break;
        default:
            debuglog(LCF_SOUND | LCF_FRAME | LCF_ERROR, "Unknown sample format");
            break;
    }
    if (outBitDepth == 8)
        outFormat = AV_SAMPLE_FMT_U8;
    if (outBitDepth == 16)
        outFormat = AV_SAMPLE_FMT_S16;

    /* Check if SWR context is initialized.
     * If not, set parameters and init it
     */
    if (! swr_is_initialized(swr)) {
        /* Set channel layout */
        if (curBuf->nbChannels == 1)
            av_opt_set_int(swr, "in_channel_layout", AV_CH_LAYOUT_MONO, 0);
        if (curBuf->nbChannels == 2)
            av_opt_set_int(swr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
        if (outNbChannels == 1)
            av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_MONO, 0);
        if (outNbChannels == 2)
            av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);

        /* Set sample format */
        av_opt_set_sample_fmt(swr, "in_sample_fmt", inFormat, 0);
        av_opt_set_sample_fmt(swr, "out_sample_fmt", outFormat, 0);

        /* Set sampling frequency */
        av_opt_set_int(swr, "in_sample_rate", curBuf->frequency, 0);
        av_opt_set_int(swr, "out_sample_rate", outFrequency, 0);

        /* Open the context */
        if (swr_init(swr) < 0) {
            debuglog(LCF_SOUND | LCF_FRAME | LCF_ERROR, "Error initializing swr context");
            return 0;
        }
    }
#endif

    /* Mixing source volume and master volume.
     * Taken from openAL doc:
     * "The implementation is free to clamp the total gain (effective gain
     * per-source multiplied by the listener gain) to one to prevent overflow."
     *
     * TODO: This is where we can support panning.
     */
    float resultVolume = (volume * outVolume) > 1.0?1.0:(volume*outVolume);
    int lvas = (int)(resultVolume * 65536.0f);
    int rvas = (int)(resultVolume * 65536.0f);

    /* Number of samples to advance in the buffer. */
    int inNbSamples = ticksToSamples(ticks, curBuf->frequency);

    int oldPosition = position;
    int newPosition = position + inNbSamples;

    /* Allocate the mixed audio array */
#if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK)
    int outNbSamples = outBytes / (outNbChannels * outBitDepth / 8);
    mixedSamples.resize(outBytes);
    uint8_t* begMixed = &mixedSamples[0];
#endif

    int convOutSamples = 0;
    uint8_t* begSamples;
    int availableSamples = curBuf->getSamples(begSamples, inNbSamples, oldPosition);

    if (availableSamples == inNbSamples) {
        /* We did not reach the end of the buffer, easy case */

        position = newPosition;
        debuglog(LCF_SOUND | LCF_FRAME, "  Buffer ", curBuf->id, " in read in range ", oldPosition, " - ", position);
#if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK)
        convOutSamples = swr_convert(swr, &begMixed, outNbSamples, (const uint8_t**)&begSamples, inNbSamples);
#endif
    }
    else {
        /* We reached the end of the buffer */
        debuglog(LCF_SOUND | LCF_FRAME, "  Buffer ", curBuf->id, " is read from ", oldPosition, " to its end ", curBuf->sampleSize);
#if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK)
        if (availableSamples > 0)
            swr_convert(swr, nullptr, 0, (const uint8_t**)&begSamples, availableSamples);
#endif

        int remainingSamples = inNbSamples - availableSamples;
        if (source == SOURCE_CALLBACK) {
            /* We refill our buffer using the callback function,
             * until we got enough bytes for this frame
             */
            while (remainingSamples > 0) {
                /* Before doing the callback, we must fake that the timer has
                 * advanced by the number of samples already read
                 */
                int64_t extraTicks = ((int64_t) 1000000000) * (-remainingSamples);
                extraTicks /= curBuf->frequency;
                detTimer.fakeAdvanceTimer({extraTicks / 1000000000, extraTicks % 1000000000});
                callback(curBuf);
                detTimer.fakeAdvanceTimer({0, 0});
                availableSamples = curBuf->getSamples(begSamples, remainingSamples, 0);
#if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK)
                    swr_convert(swr, nullptr, 0, (const uint8_t**)&begSamples, availableSamples);
#endif
                debuglog(LCF_SOUND | LCF_FRAME, "  Buffer ", curBuf->id, " is read again from 0 to ", availableSamples);
                if (remainingSamples == availableSamples)
                    position = availableSamples;
                remainingSamples -= availableSamples;
            }

#if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK)
            /* Get the mixed samples */
            convOutSamples = swr_convert(swr, &begMixed, outNbSamples, nullptr, 0);
#endif
        }
        else {
            int queue_size = buffer_queue.size();
            int finalIndex;
            int finalPos;

            /* Our for loop conditions are different if we are looping or not */
            if (looping) {
                for (int i=(queue_index+1)%queue_size; remainingSamples>0; i=(i+1)%queue_size) {
                    AudioBuffer* loopbuf = buffer_queue[i];
                    availableSamples = loopbuf->getSamples(begSamples, remainingSamples, 0);
                    debuglog(LCF_SOUND | LCF_FRAME, "  Buffer ", loopbuf->id, " in read in range 0 - ", availableSamples);
#if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK)
                    swr_convert(swr, nullptr, 0, (const uint8_t**)&begSamples, availableSamples);
#endif
                    if (remainingSamples == availableSamples) {
                        finalIndex = i;
                        finalPos = availableSamples;
                    }
                    remainingSamples -= availableSamples;
                }
            }
            else {
                for (int i=queue_index+1; (remainingSamples>0) && (i<queue_size); i++) {
                    AudioBuffer* loopbuf = buffer_queue[i];
                    availableSamples = loopbuf->getSamples(begSamples, remainingSamples, 0);
                    debuglog(LCF_SOUND | LCF_FRAME, "  Buffer ", loopbuf->id, " in read in range 0 - ", availableSamples);
#if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK)
                    swr_convert(swr, nullptr, 0, (const uint8_t**)&begSamples, availableSamples);
#endif
                    if (remainingSamples == availableSamples) {
                        finalIndex = i;
                        finalPos = availableSamples;
                    }
                    remainingSamples -= availableSamples;
                }
            }

#if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK)
            /* Get the mixed samples */
            convOutSamples = swr_convert(swr, &begMixed, outNbSamples, nullptr, 0);
#endif

            if (remainingSamples > 0) {
                /* We reached the end of the buffer queue */
                init();
                state = SOURCE_STOPPED;
                debuglog(LCF_SOUND | LCF_FRAME, "  End of the queue reached");
            }
            else {
                /* Update the position in the buffer */
                queue_index = finalIndex;
                position = finalPos;
            }
        }

    }

#if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK)

#define clamptofullsignedrange(x,lo,hi) (((unsigned int)((x)-(lo))<=(unsigned int)((hi)-(lo)))?(x):(((x)<0)?(lo):(hi)))

    /* Add mixed source to the output buffer */
    if (outBitDepth == 8) {
        for (int s=0; s<convOutSamples*outNbChannels; s+=outNbChannels) {
            int myL = ((uint8_t*)&mixedSamples[0])[s];
            int otherL = ((uint8_t*)outSamples)[s];
            int sumL = otherL + ((myL * lvas) >> 16) - 256;
            ((uint8_t*)outSamples)[s] = clamptofullsignedrange(sumL, 0, (1<<8)-1);

            if (outNbChannels == 2) {
                int myR = ((uint8_t*)&mixedSamples[0])[s+1];
                int otherR = ((uint8_t*)outSamples)[s+1];
                int sumR = otherR + ((myR * rvas) >> 16);
                ((uint8_t*)outSamples)[s+1] = clamptofullsignedrange(sumR, 0, (1<<8)-1);
            }
        }
    }