コード例 #1
0
SoundSource::OpenResult SoundSourceOpus::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) {
    // From opus/opusfile.h
    // On Windows, this string must be UTF-8 (to allow access to
    // files whose names cannot be represented in the current
    // MBCS code page).
    // All other systems use the native character encoding.
#ifdef _WIN32
    QByteArray qBAFilename = getLocalFileName().toUtf8();
#else
    QByteArray qBAFilename = getLocalFileName().toLocal8Bit();
#endif

    int errorCode = 0;

    DEBUG_ASSERT(!m_pOggOpusFile);
    m_pOggOpusFile = op_open_file(qBAFilename.constData(), &errorCode);
    if (!m_pOggOpusFile) {
        qWarning() << "Failed to open OggOpus file:" << getUrlString()
                << "errorCode" << errorCode;
        return OpenResult::FAILED;
    }

    if (!op_seekable(m_pOggOpusFile)) {
        qWarning() << "SoundSourceOpus:"
                << "Stream in"
                << getUrlString()
                << "is not seekable";
        return OpenResult::UNSUPPORTED_FORMAT;
    }

    const int channelCount = op_channel_count(m_pOggOpusFile, kCurrentStreamLink);
    if (0 < channelCount) {
        setChannelCount(channelCount);
    } else {
        qWarning() << "Failed to read channel configuration of OggOpus file:" << getUrlString();
        return OpenResult::FAILED;
    }

    const ogg_int64_t pcmTotal = op_pcm_total(m_pOggOpusFile, kEntireStreamLink);
    if (0 <= pcmTotal) {
        setFrameCount(pcmTotal);
    } else {
        qWarning() << "Failed to read total length of OggOpus file:" << getUrlString();
        return OpenResult::FAILED;
    }

    const opus_int32 bitrate = op_bitrate(m_pOggOpusFile, kEntireStreamLink);
    if (0 < bitrate) {
        setBitrate(bitrate / 1000);
    } else {
        qWarning() << "Failed to determine bitrate of OggOpus file:" << getUrlString();
        return OpenResult::FAILED;
    }

    setSamplingRate(kSamplingRate);

    m_curFrameIndex = getMinFrameIndex();

    return OpenResult::SUCCEEDED;
}
コード例 #2
0
ファイル: soundsourcewv.cpp プロジェクト: priestd09/mixxx
Result SoundSourceWV::tryOpen(const AudioSourceConfig& audioSrcCfg) {
    DEBUG_ASSERT(!m_wpc);
    char msg[80]; // hold possible error message
    int openFlags = OPEN_WVC | OPEN_NORMALIZE;
    if ((kChannelCountMono == audioSrcCfg.channelCountHint) ||
            (kChannelCountStereo == audioSrcCfg.channelCountHint)) {
        openFlags |= OPEN_2CH_MAX;
    }
    m_wpc = WavpackOpenFileInput(
            getLocalFileNameBytes().constData(), msg, openFlags, 0);
    if (!m_wpc) {
        qDebug() << "SSWV::open: failed to open file : " << msg;
        return ERR;
    }

    setChannelCount(WavpackGetReducedChannels(m_wpc));
    setFrameRate(WavpackGetSampleRate(m_wpc));
    setFrameCount(WavpackGetNumSamples(m_wpc));

    if (WavpackGetMode(m_wpc) & MODE_FLOAT) {
        m_sampleScaleFactor = CSAMPLE_PEAK;
    } else {
        const int bitsPerSample = WavpackGetBitsPerSample(m_wpc);
        const uint32_t wavpackPeakSampleValue = uint32_t(1)
                << (bitsPerSample - 1);
        m_sampleScaleFactor = CSAMPLE_PEAK / CSAMPLE(wavpackPeakSampleValue);
    }

    return OK;
}
コード例 #3
0
ファイル: VolumeFader.cpp プロジェクト: artcom/asl
VolumeFader::VolumeFader(SampleFormat theSampleFormat, unsigned int theChannelCount)
    : Effect(createEffectFunctor<VolumeFaderFunctor>(theSampleFormat))
{
    setChannelCount(theChannelCount);
    // _myCurrentVolume = _myBeginVolume = _myEndVolume = 0.0;
    _myCurrentFrame = _myFadeBeginFrame = _myFadeEndFrame = 0;
}
コード例 #4
0
ファイル: MultiChannelBuffer.cpp プロジェクト: EQ4/minim-cpp
	MultiChannelBuffer::MultiChannelBuffer( int numChannels, int bufferSize )
	: mBufferSize(bufferSize)
	, mChannels(NULL)
	, mChannelCount(0)
	{
		setChannelCount( numChannels );
	}
コード例 #5
0
Result SoundSourceSndFile::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) {
    DEBUG_ASSERT(!m_pSndFile);
    SF_INFO sfInfo;
#ifdef __WINDOWS__
    // Pointer valid until string changed
    const QString fileName(getLocalFileName());
    LPCWSTR lpcwFilename = (LPCWSTR) fileName.utf16();
    m_pSndFile = sf_wchar_open(lpcwFilename, SFM_READ, &sfInfo);
#else
    memset(&sfInfo, 0, sizeof(sfInfo));
    m_pSndFile = sf_open(getLocalFileNameBytes().constData(), SFM_READ, &sfInfo);
#endif

    if (!m_pSndFile) {   // sf_format_check is only for writes
        qWarning() << "Error opening libsndfile file:" << getUrlString()
                << sf_strerror(m_pSndFile);
        return ERR;
    }

    if (sf_error(m_pSndFile) > 0) {
        qWarning() << "Error opening libsndfile file:" << getUrlString()
                << sf_strerror(m_pSndFile);
        return ERR;
    }

    setChannelCount(sfInfo.channels);
    setFrameRate(sfInfo.samplerate);
    setFrameCount(sfInfo.frames);

    return OK;
}
コード例 #6
0
ファイル: player.cpp プロジェクト: rdpoor/mu
 Player& Player::init() {
   setChannelCount(kDefaultChannelCount);
   setFrameRate(kDefaultFrameRate);
   setFrameSize(kDefaultFrameSize);
   setSource(NULL);
   setTick(0);
   return *this;
 }
コード例 #7
0
ファイル: soundsourcewv.cpp プロジェクト: MK-42/mixxx
SoundSource::OpenResult SoundSourceWV::tryOpen(
        OpenMode /*mode*/,
        const OpenParams& params) {
    DEBUG_ASSERT(!m_wpc);
    char msg[80]; // hold possible error message
    int openFlags = OPEN_WVC | OPEN_NORMALIZE;
    if ((params.channelCount() == 1) ||
            (params.channelCount() == 2)) {
        openFlags |= OPEN_2CH_MAX;
    }

    // We use WavpackOpenFileInputEx to support Unicode paths on windows
    // http://www.wavpack.com/lib_use.txt
    QString wavPackFileName = getLocalFileName();
    m_pWVFile = new QFile(wavPackFileName);
    m_pWVFile->open(QFile::ReadOnly);
    QString correctionFileName(wavPackFileName + "c");
    if (QFile::exists(correctionFileName)) {
        // If there is a correction file, open it as well
        m_pWVCFile = new QFile(correctionFileName);
        m_pWVCFile->open(QFile::ReadOnly);
    }
    m_wpc = WavpackOpenFileInputEx(&s_streamReader, m_pWVFile, m_pWVCFile,
            msg, openFlags, 0);
    if (!m_wpc) {
        kLogger.warning() << "failed to open file : " << msg;
        return OpenResult::Failed;
    }

    setChannelCount(WavpackGetReducedChannels(m_wpc));
    setSampleRate(WavpackGetSampleRate(m_wpc));
    initFrameIndexRangeOnce(
            mixxx::IndexRange::forward(
                    0,
                    WavpackGetNumSamples(m_wpc)));

    if (WavpackGetMode(m_wpc) & MODE_FLOAT) {
        m_sampleScaleFactor = CSAMPLE_PEAK;
    } else {
        const int bitsPerSample = WavpackGetBitsPerSample(m_wpc);
        if ((bitsPerSample >= 8) && (bitsPerSample <= 32)) {
            // Range of signed sample values: [-2 ^ (bitsPerSample - 1), 2 ^ (bitsPerSample - 1) - 1]
            const uint32_t absSamplePeak = 1u << (bitsPerSample - 1);
            DEBUG_ASSERT(absSamplePeak > 0);
            // Scaled range of sample values: [-CSAMPLE_PEAK, CSAMPLE_PEAK)
            m_sampleScaleFactor = CSAMPLE_PEAK / absSamplePeak;
        } else {
            kLogger.warning()
                    << "Invalid bits per sample:"
                    << bitsPerSample;
            return OpenResult::Aborted;
        }
    }

    m_curFrameIndex = frameIndexMin();

    return OpenResult::Succeeded;
}
コード例 #8
0
ファイル: MultiChannelBuffer.cpp プロジェクト: EQ4/minim-cpp
	MultiChannelBuffer::MultiChannelBuffer( const MultiChannelBuffer & other )
	: mBufferSize(other.mBufferSize)
	, mChannels(NULL)
	, mChannelCount(0)
	{
		setChannelCount( other.mChannelCount );
		for(int i = 0; i < mChannelCount; i++)
		{
			memcpy(mChannels[i], other.mChannels[i], sizeof(float)*mBufferSize);
		}
	}
コード例 #9
0
void FloatLatch::menuExecuted()
{
	Component::menuExecuted();
	
	// Delayed connector count setting.
	if (tempConnCountOwner == this)
	{
		tempConnCountOwner = (FloatLatch *)0;
		if (tempConnCount != getChannelCount())
		{
			setChannelCount(tempConnCount);
		}
	}
}
コード例 #10
0
ファイル: soundsourceflac.cpp プロジェクト: mixxxdj/mixxx
void SoundSourceFLAC::flacMetadata(const FLAC__StreamMetadata* metadata) {
    // https://xiph.org/flac/api/group__flac__stream__decoder.html#ga43e2329c15731c002ac4182a47990f85
    // "...one STREAMINFO block, followed by zero or more other metadata blocks."
    // "...by default the decoder only calls the metadata callback for the STREAMINFO block..."
    // "...always before the first audio frame (i.e. write callback)."
    switch (metadata->type) {
    case FLAC__METADATA_TYPE_STREAMINFO: {
        setChannelCount(metadata->data.stream_info.channels);
        setSampleRate(metadata->data.stream_info.sample_rate);
        initFrameIndexRangeOnce(
                IndexRange::forward(
                        0,
                        metadata->data.stream_info.total_samples));

        const unsigned bitsPerSample = metadata->data.stream_info.bits_per_sample;
        DEBUG_ASSERT(kBitsPerSampleDefault != bitsPerSample);
        if (kBitsPerSampleDefault == m_bitsPerSample) {
            // not set before
            if ((bitsPerSample >= 4) && (bitsPerSample <= 32)) {
                m_bitsPerSample = bitsPerSample;
            } else {
                kLogger.warning()
                        << "Invalid bits per sample:"
                        << bitsPerSample;
            }
        } else {
            // already set before -> check for consistency
            if (bitsPerSample != m_bitsPerSample) {
                kLogger.warning()
                        << "Unexpected bits per sample:"
                        << bitsPerSample << " <> " << m_bitsPerSample;
            }
        }
        m_maxBlocksize = metadata->data.stream_info.max_blocksize;
        if (0 >= m_maxBlocksize) {
            kLogger.warning()
                    << "Invalid max. blocksize" << m_maxBlocksize;
        }
        const SINT sampleBufferCapacity =
                m_maxBlocksize * channelCount();
        if (m_sampleBuffer.capacity() < sampleBufferCapacity) {
            m_sampleBuffer.adjustCapacity(sampleBufferCapacity);
        }
        break;
    }
    default:
        // Ignore all other metadata types
        break;
    }
}
コード例 #11
0
SoundSource::OpenResult SoundSourceSndFile::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) {
    DEBUG_ASSERT(!m_pSndFile);
    SF_INFO sfInfo;
    memset(&sfInfo, 0, sizeof(sfInfo));
#ifdef __WINDOWS__
    // Note: we cannot use QString::toStdWString since QT 4 is compiled with
    // '/Zc:wchar_t-' flag and QT 5 not
    const QString localFileName(QDir::toNativeSeparators(getLocalFileName()));
    const ushort* const fileNameUtf16 = localFileName.utf16();
    static_assert(sizeof(wchar_t) == sizeof(ushort), "QString::utf16(): wchar_t and ushort have different sizes");
    m_pSndFile = sf_wchar_open(
		reinterpret_cast<wchar_t*>(const_cast<ushort*>(fileNameUtf16)),
		SFM_READ,
		&sfInfo);
#else
    m_pSndFile = sf_open(getLocalFileName().toLocal8Bit(), SFM_READ, &sfInfo);
#endif

    switch (sf_error(m_pSndFile)) {
    case SF_ERR_NO_ERROR:
        DEBUG_ASSERT(m_pSndFile != nullptr);
        break; // continue
    case SF_ERR_UNRECOGNISED_FORMAT:
        return OpenResult::UNSUPPORTED_FORMAT;
    default:
        const QString errorMsg(sf_strerror(m_pSndFile));
        if (errorMsg.toLower().indexOf("unknown format") != -1) {
            // NOTE(uklotzde 2016-05-11): This actually happens when
            // trying to open a file with a supported file extension
            // that contains data in an unsupported format!
            return OpenResult::UNSUPPORTED_FORMAT;
        } else {
            qWarning() << "Error opening libsndfile file:"
                    << getUrlString()
                    << errorMsg;
            return OpenResult::FAILED;
        }
    }

    setChannelCount(sfInfo.channels);
    setSamplingRate(sfInfo.samplerate);
    setFrameCount(sfInfo.frames);

    return OpenResult::SUCCEEDED;
}
コード例 #12
0
ファイル: MultiChannelBuffer.cpp プロジェクト: EQ4/minim-cpp
	MultiChannelBuffer & MultiChannelBuffer::operator=( const MultiChannelBuffer & other )
	{
		if ( mBufferSize != other.mBufferSize )
		{
			setBufferSize(other.mBufferSize);
		}
		
		if ( mChannelCount != other.mChannelCount ) 
		{
			setChannelCount(other.mChannelCount);
		}
		
		for(int i = 0; i < mChannelCount; i++)
		{
			memcpy(mChannels[i], other.mChannels[i], sizeof(float)*mBufferSize);
		}
		
		return *this;
	}
コード例 #13
0
ファイル: soundsourcewv.cpp プロジェクト: chegestar/mixxx
SoundSource::OpenResult SoundSourceWV::tryOpen(const AudioSourceConfig& audioSrcCfg) {
    DEBUG_ASSERT(!m_wpc);
    char msg[80]; // hold possible error message
    int openFlags = OPEN_WVC | OPEN_NORMALIZE;
    if ((kChannelCountMono == audioSrcCfg.getChannelCount()) ||
            (kChannelCountStereo == audioSrcCfg.getChannelCount())) {
        openFlags |= OPEN_2CH_MAX;
    }

    // We use WavpackOpenFileInputEx to support Unicode paths on windows
    // http://www.wavpack.com/lib_use.txt
    QString wavPackFileName = getLocalFileName();
    m_pWVFile = new QFile(wavPackFileName);
    m_pWVFile->open(QFile::ReadOnly);
    QString correctionFileName(wavPackFileName + "c");
    if (QFile::exists(correctionFileName)) {
        // If there is a correction file, open it as well
        m_pWVCFile = new QFile(correctionFileName);
        m_pWVCFile->open(QFile::ReadOnly);
    }
    m_wpc = WavpackOpenFileInputEx(&s_streamReader, m_pWVFile, m_pWVCFile,
            msg, openFlags, 0);
    if (!m_wpc) {
        qDebug() << "SSWV::open: failed to open file : " << msg;
        return OpenResult::FAILED;
    }

    setChannelCount(WavpackGetReducedChannels(m_wpc));
    setSamplingRate(WavpackGetSampleRate(m_wpc));
    setFrameCount(WavpackGetNumSamples(m_wpc));

    if (WavpackGetMode(m_wpc) & MODE_FLOAT) {
        m_sampleScaleFactor = CSAMPLE_PEAK;
    } else {
        const int bitsPerSample = WavpackGetBitsPerSample(m_wpc);
        const uint32_t wavpackPeakSampleValue = 1u
                << (bitsPerSample - 1);
        m_sampleScaleFactor = CSAMPLE_PEAK / wavpackPeakSampleValue;
    }

    return OpenResult::SUCCEEDED;
}
コード例 #14
0
Result SoundSourceOggVorbis::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) {
    m_pFile = new QFile(getLocalFileName());
    if(!m_pFile->open(QFile::ReadOnly)) {
        qWarning() << "Failed to open OggVorbis file:" << getUrlString();
        return ERR;
    }
    if (ov_open_callbacks(m_pFile, &m_vf, NULL, 0, s_callbacks) < 0) {
        qDebug() << "oggvorbis: Input does not appear to be an Ogg bitstream.";
        return ERR;
    }

    if (!ov_seekable(&m_vf)) {
        qWarning() << "OggVorbis file is not seekable:" << getUrlString();
        return ERR;
    }

    // lookup the ogg's channels and sample rate
    const vorbis_info* vi = ov_info(&m_vf, kCurrentBitstreamLink);
    if (!vi) {
        qWarning() << "Failed to read OggVorbis file:" << getUrlString();
        return ERR;
    }
    setChannelCount(vi->channels);
    setSamplingRate(vi->rate);
    if (0 < vi->bitrate_nominal) {
        setBitrate(vi->bitrate_nominal / 1000);
    } else {
        if ((0 < vi->bitrate_lower) && (vi->bitrate_lower == vi->bitrate_upper)) {
            setBitrate(vi->bitrate_lower / 1000);
        }
    }

    ogg_int64_t pcmTotal = ov_pcm_total(&m_vf, kEntireBitstreamLink);
    if (0 <= pcmTotal) {
        setFrameCount(pcmTotal);
    } else {
        qWarning() << "Failed to read total length of OggVorbis file:" << getUrlString();
        return ERR;
    }

    return OK;
}
コード例 #15
0
Result SoundSourceOggVorbis::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) {
    const QByteArray qbaFilename(getLocalFileNameBytes());
    if (0 != ov_fopen(qbaFilename.constData(), &m_vf)) {
        qWarning() << "Failed to open OggVorbis file:" << getUrlString();
        return ERR;
    }

    if (!ov_seekable(&m_vf)) {
        qWarning() << "OggVorbis file is not seekable:" << getUrlString();
        return ERR;
    }

    // lookup the ogg's channels and sample rate
    const vorbis_info* vi = ov_info(&m_vf, kCurrentBitstreamLink);
    if (!vi) {
        qWarning() << "Failed to read OggVorbis file:" << getUrlString();
        return ERR;
    }
    setChannelCount(vi->channels);
    setFrameRate(vi->rate);
    if (0 < vi->bitrate_nominal) {
        setBitrate(vi->bitrate_nominal / 1000);
    } else {
        if ((0 < vi->bitrate_lower) && (vi->bitrate_lower == vi->bitrate_upper)) {
            setBitrate(vi->bitrate_lower / 1000);
        }
    }

    ogg_int64_t pcmTotal = ov_pcm_total(&m_vf, kEntireBitstreamLink);
    if (0 <= pcmTotal) {
        setFrameCount(pcmTotal);
    } else {
        qWarning() << "Failed to read total length of OggVorbis file:" << getUrlString();
        return ERR;
    }

    return OK;
}
コード例 #16
0
bool MzSpectrogramFFTW::initialise(size_t channels, size_t stepsize, 
      size_t blocksize) {

   if (channels < getMinChannelCount() || channels > getMaxChannelCount()) {
      return false;
   }

   // step size and block size should never be zero
   if (stepsize <= 0 || blocksize <= 0) {
      return false;
   }

   setChannelCount(channels);
   setBlockSize(blocksize);
   setStepSize(stepsize);

   mz_minbin = getParameterInt("minbin");
   mz_maxbin = getParameterInt("maxbin");

   if (mz_minbin >= getBlockSize()/2) { mz_minbin = getBlockSize()/2-1; }
   if (mz_maxbin >= getBlockSize()/2) { mz_maxbin = getBlockSize()/2-1; }
   if (mz_maxbin <  0)                { mz_maxbin = getBlockSize()/2-1; }
   if (mz_maxbin <  mz_minbin)        { std::swap(mz_minbin, mz_maxbin); }

   // The signal size/transform size are equivalent for this
   // plugin but the FFTW can handle any size transform.
   // If the size of the transform is a multiple of small
   // prime numbers the FFT will be used, otherwise it will
   // be slow (when block size=1021 for example).

   mz_transformer.setSize(getBlockSize());
   delete [] mz_wind_buff;
   mz_wind_buff = new double[getBlockSize()];
   makeHannWindow(mz_wind_buff, getBlockSize());

   return true;
}
コード例 #17
0
ファイル: soundsourcesndfile.cpp プロジェクト: MLudgate/mixxx
Result SoundSourceSndFile::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) {
    DEBUG_ASSERT(!m_pSndFile);
    SF_INFO sfInfo;
    memset(&sfInfo, 0, sizeof(sfInfo));
#ifdef __WINDOWS__
    // Note: we cannot use QString::toStdWString since QT 4 is compiled with
    // '/Zc:wchar_t-' flag and QT 5 not
    const QString localFileName(QDir::toNativeSeparators(getLocalFileName()));
    const ushort* const fileNameUtf16 = localFileName.utf16();
    static_assert(sizeof(wchar_t) == sizeof(ushort), "QString::utf16(): wchar_t and ushort have different sizes");
    m_pSndFile = sf_wchar_open(
		reinterpret_cast<wchar_t*>(const_cast<ushort*>(fileNameUtf16)),
		SFM_READ,
		&sfInfo);
#else
    m_pSndFile = sf_open(getLocalFileName().toLocal8Bit(), SFM_READ, &sfInfo);
#endif

    if (!m_pSndFile) {   // sf_format_check is only for writes
        qWarning() << "Error opening libsndfile file:" << getUrlString()
                << sf_strerror(m_pSndFile);
        return ERR;
    }

    if (sf_error(m_pSndFile) > 0) {
        qWarning() << "Error opening libsndfile file:" << getUrlString()
                << sf_strerror(m_pSndFile);
        return ERR;
    }

    setChannelCount(sfInfo.channels);
    setSamplingRate(sfInfo.samplerate);
    setFrameCount(sfInfo.frames);

    return OK;
}
コード例 #18
0
ファイル: soundsourceffmpeg.cpp プロジェクト: 22degrees/mixxx
SoundSource::OpenResult SoundSourceFFmpeg::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) {
    AVDictionary *l_iFormatOpts = nullptr;

    const QString localFileName(getLocalFileName());
    qDebug() << "New SoundSourceFFmpeg :" << localFileName;

    DEBUG_ASSERT(!m_pFormatCtx);
    m_pFormatCtx = avformat_alloc_context();

    if (m_pFormatCtx == nullptr) {
        qDebug() << "SoundSourceFFmpeg::tryOpen: Can't allocate memory";
        return OpenResult::FAILED;
    }

    // TODO() why is this required, should't it be a runtime check
#if LIBAVCODEC_VERSION_INT < 3622144 // 55.69.0
    m_pFormatCtx->max_analyze_duration = 999999999;
#endif

    // libav replaces open() with ff_win32_open() which accepts a
    // Utf8 path
    // see: avformat/os_support.h
    // The old method defining an URL_PROTOCOL is deprecated
#if defined(_WIN32) && !defined(__MINGW32CE__)
    const QByteArray qBAFilename(
            avformat_version() >= ((52<<16)+(0<<8)+0) ?
            getLocalFileName().toUtf8() :
            getLocalFileName().toLocal8Bit());
#else
    const QByteArray qBAFilename(getLocalFileName().toLocal8Bit());
#endif

    // Open file and make m_pFormatCtx
    if (avformat_open_input(&m_pFormatCtx, qBAFilename.constData(), nullptr,
                            &l_iFormatOpts) != 0) {
        qDebug() << "SoundSourceFFmpeg::tryOpen: cannot open" << localFileName;
        return OpenResult::FAILED;
    }

    // TODO() why is this required, should't it be a runtime check
#if LIBAVCODEC_VERSION_INT > 3544932 // 54.23.100
    av_dict_free(&l_iFormatOpts);
#endif

    // Retrieve stream information
    if (avformat_find_stream_info(m_pFormatCtx, nullptr) < 0) {
        qDebug() << "SoundSourceFFmpeg::tryOpen: cannot open" << localFileName;
        return OpenResult::FAILED;
    }

    //debug only (Enable if needed)
    //av_dump_format(m_pFormatCtx, 0, qBAFilename.constData(), false);

    // Find the first audio stream
    m_iAudioStream = -1;

    for (unsigned int i = 0; i < m_pFormatCtx->nb_streams; i++)
        if (m_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
            m_iAudioStream = i;
            break;
        }

    if (m_iAudioStream == -1) {
        qDebug() <<
                 "SoundSourceFFmpeg::tryOpen: cannot find an audio stream: cannot open"
                 << localFileName;
        return OpenResult::FAILED;
    }

    // Get a pointer to the codec context for the audio stream
    m_pCodecCtx = m_pFormatCtx->streams[m_iAudioStream]->codec;

    // Find the decoder for the audio stream
    if (!(m_pCodec = avcodec_find_decoder(m_pCodecCtx->codec_id))) {
        qDebug() << "SoundSourceFFmpeg::tryOpen: cannot find a decoder for" <<
                localFileName;
        return OpenResult::UNSUPPORTED_FORMAT;
    }

    if (avcodec_open2(m_pCodecCtx, m_pCodec, nullptr)<0) {
        qDebug() << "SoundSourceFFmpeg::tryOpen: cannot open" << localFileName;
        return OpenResult::FAILED;
    }

    m_pResample = std::make_unique<EncoderFfmpegResample>(m_pCodecCtx);
    m_pResample->openMixxx(m_pCodecCtx->sample_fmt, AV_SAMPLE_FMT_FLT);

    setChannelCount(m_pCodecCtx->channels);
    setSamplingRate(m_pCodecCtx->sample_rate);
    setFrameCount((qint64)round((double)((double)m_pFormatCtx->duration *
                                         (double)m_pCodecCtx->sample_rate) / (double)AV_TIME_BASE));

    qDebug() << "SoundSourceFFmpeg::tryOpen: Sampling rate: " << getSamplingRate() <<
             ", Channels: " <<
             getChannelCount() << "\n";
    if (getChannelCount() > 2) {
        qDebug() << "ffmpeg: No support for more than 2 channels!";
        return OpenResult::FAILED;
    }

    return OpenResult::SUCCEEDED;
}
コード例 #19
0
ファイル: soundsourcemp3.cpp プロジェクト: PetrBarborka/mixxx
SoundSource::OpenResult SoundSourceMp3::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) {
    DEBUG_ASSERT(!hasValidChannelCount());
    DEBUG_ASSERT(!hasValidSamplingRate());

    DEBUG_ASSERT(!m_file.isOpen());
    if (!m_file.open(QIODevice::ReadOnly)) {
        qWarning() << "Failed to open file:" << m_file.fileName();
        return OpenResult::FAILED;
    }

    // Get a pointer to the file using memory mapped IO
    m_fileSize = m_file.size();
    m_pFileData = m_file.map(0, m_fileSize);
    // NOTE(uklotzde): If the file disappears unexpectedly while mapped
    // a SIGBUS error might occur that is not handled and will terminate
    // Mixxx immediately. This behavior is documented in the manpage of
    // mmap(). It has already appeared due to hardware errors and is
    // described in the following bug report:
    // https://bugs.launchpad.net/mixxx/+bug/1452005

    // Transfer it to the mad stream-buffer:
    mad_stream_options(&m_madStream, MAD_OPTION_IGNORECRC);
    mad_stream_buffer(&m_madStream, m_pFileData, m_fileSize);
    DEBUG_ASSERT(m_pFileData == m_madStream.this_frame);

    DEBUG_ASSERT(m_seekFrameList.empty());
    m_avgSeekFrameCount = 0;
    m_curFrameIndex = getMinFrameIndex();
    int headerPerSamplingRate[kSamplingRateCount];
    for (int i = 0; i < kSamplingRateCount; ++i) {
        headerPerSamplingRate[i] = 0;
    }

    // Decode all the headers and calculate audio properties

    unsigned long sumBitrate = 0;

    mad_header madHeader;
    mad_header_init(&madHeader);

    SINT maxChannelCount = getChannelCount();
    do {
        if (!decodeFrameHeader(&madHeader, &m_madStream, true)) {
            if (isStreamValid(m_madStream)) {
                // Skip frame
                continue;
            } else {
                // Abort decoding
                break;
            }
        }

        // Grab data from madHeader
        const unsigned int madSampleRate = madHeader.samplerate;

        // TODO(XXX): Replace DEBUG_ASSERT with static_assert
        // MAD must not change its enum values!
        DEBUG_ASSERT(MAD_UNITS_8000_HZ == 8000);
        const mad_units madUnits = static_cast<mad_units>(madSampleRate);

        const long madFrameLength = mad_timer_count(madHeader.duration, madUnits);
        if (0 >= madFrameLength) {
            qWarning() << "Skipping MP3 frame with invalid length"
                    << madFrameLength
                    << "in:" << m_file.fileName();
            // Skip frame
            continue;
        }

        const SINT madChannelCount = MAD_NCHANNELS(&madHeader);
        if (isValidChannelCount(maxChannelCount) && (madChannelCount != maxChannelCount)) {
            qWarning() << "Differing number of channels"
                    << madChannelCount << "<>" << maxChannelCount
                    << "in some MP3 frame headers:"
                    << m_file.fileName();
        }
        maxChannelCount = math_max(madChannelCount, maxChannelCount);

        const int samplingRateIndex = getIndexBySamplingRate(madSampleRate);
        if (samplingRateIndex >= kSamplingRateCount) {
            qWarning() << "Invalid sample rate:" << m_file.fileName()
                    << madSampleRate;
            // Abort
            mad_header_finish(&madHeader);
            return OpenResult::FAILED;
        }
        // Count valid frames separated by its sampling rate
        headerPerSamplingRate[samplingRateIndex]++;

        addSeekFrame(m_curFrameIndex, m_madStream.this_frame);

        // Accumulate data from the header
        sumBitrate += madHeader.bitrate;

        // Update current stream position
        m_curFrameIndex += madFrameLength;

        DEBUG_ASSERT(m_madStream.this_frame);
        DEBUG_ASSERT(0 <= (m_madStream.this_frame - m_pFileData));
    } while (quint64(m_madStream.this_frame - m_pFileData) < m_fileSize);

    mad_header_finish(&madHeader);

    if (MAD_ERROR_NONE != m_madStream.error) {
        // Unreachable code for recoverable errors
        DEBUG_ASSERT(!MAD_RECOVERABLE(m_madStream.error));
        if (MAD_ERROR_BUFLEN != m_madStream.error) {
            qWarning() << "Unrecoverable MP3 header error:"
                    << mad_stream_errorstr(&m_madStream);
            // Abort
            return OpenResult::FAILED;
        }
    }

    if (m_seekFrameList.empty()) {
        // This is not a working MP3 file.
        qWarning() << "SSMP3: This is not a working MP3 file:"
                << m_file.fileName();
        // Abort
        return OpenResult::FAILED;
    }

    int mostCommonSamplingRateIndex = kSamplingRateCount; // invalid
    int mostCommonSamplingRateCount = 0;
    int differentRates = 0;
    for (int i = 0; i < kSamplingRateCount; ++i) {
        // Find most common sampling rate
        if (mostCommonSamplingRateCount < headerPerSamplingRate[i]) {
            mostCommonSamplingRateCount = headerPerSamplingRate[i];
            mostCommonSamplingRateIndex = i;
            differentRates++;
        }
    }

    if (differentRates > 1) {
        qWarning() << "Differing sampling rate in some headers:"
                   << m_file.fileName();
        for (int i = 0; i < kSamplingRateCount; ++i) {
            if (0 < headerPerSamplingRate[i]) {
                qWarning() << headerPerSamplingRate[i] << "MP3 headers with sampling rate" << getSamplingRateByIndex(i);
            }
        }

        qWarning() << "MP3 files with varying sample rate are not supported!";
        qWarning() << "Since this happens most likely due to a corrupt file";
        qWarning() << "Mixxx tries to plays it with the most common sample rate for this file";
    }

    if (mostCommonSamplingRateIndex < kSamplingRateCount) {
        setSamplingRate(getSamplingRateByIndex(mostCommonSamplingRateIndex));
    } else {
        qWarning() << "No single valid sampling rate in header";
        // Abort
        return OpenResult::FAILED;
    }

    // Initialize the AudioSource
    setChannelCount(maxChannelCount);
    setFrameCount(m_curFrameIndex);

    // Calculate average values
    m_avgSeekFrameCount = getFrameCount() / m_seekFrameList.size();
    const unsigned long avgBitrate = sumBitrate / m_seekFrameList.size();
    setBitrate(avgBitrate / 1000);

    // Terminate m_seekFrameList
    addSeekFrame(m_curFrameIndex, 0);

    // Reset positions
    m_curFrameIndex = getMinFrameIndex();

    // Restart decoding at the beginning of the audio stream
    m_curFrameIndex = restartDecoding(m_seekFrameList.front());
    if (m_curFrameIndex != m_seekFrameList.front().frameIndex) {
        qWarning() << "Failed to start decoding:" << m_file.fileName();
        // Abort
        return OpenResult::FAILED;
    }

    return OpenResult::SUCCEEDED;
}
コード例 #20
0
ファイル: soundsourcem4a.cpp プロジェクト: djsteph/mixxx
bool SoundSourceM4A::openDecoder() {
    DEBUG_ASSERT(m_hDecoder == nullptr); // not already opened

    m_hDecoder = NeAACDecOpen();
    if (m_hDecoder == nullptr) {
        qWarning() << "Failed to open the AAC decoder!";
        return false;
    }
    NeAACDecConfigurationPtr pDecoderConfig = NeAACDecGetCurrentConfiguration(
            m_hDecoder);
    pDecoderConfig->outputFormat = FAAD_FMT_FLOAT;
    if ((kChannelCountMono == m_audioSrcCfg.getChannelCount()) ||
            (kChannelCountStereo == m_audioSrcCfg.getChannelCount())) {
        pDecoderConfig->downMatrix = 1;
    } else {
        pDecoderConfig->downMatrix = 0;
    }

    pDecoderConfig->defObjectType = LC;
    if (!NeAACDecSetConfiguration(m_hDecoder, pDecoderConfig)) {
        qWarning() << "Failed to configure AAC decoder!";
        return false;
    }

    u_int8_t* configBuffer = nullptr;
    u_int32_t configBufferSize = 0;
    if (!MP4GetTrackESConfiguration(m_hFile, m_trackId, &configBuffer,
            &configBufferSize)) {
        // Failed to get mpeg-4 audio config... this is ok.
        // NeAACDecInit2() will simply use default values instead.
        qWarning() << "Failed to read the MP4 audio configuration."
                << "Continuing with default values.";
    }

    SAMPLERATE_TYPE samplingRate;
    unsigned char channelCount;
    if (0 > NeAACDecInit2(m_hDecoder, configBuffer, configBufferSize,
                    &samplingRate, &channelCount)) {
        free(configBuffer);
        qWarning() << "Failed to initialize the AAC decoder!";
        return false;
    } else {
        free(configBuffer);
    }

    // Calculate how many sample blocks we need to decode in advance
    // of a random seek in order to get the recommended number of
    // prefetch frames
    m_numberOfPrefetchSampleBlocks =
            (kNumberOfPrefetchFrames + (m_framesPerSampleBlock - 1)) /
            m_framesPerSampleBlock;

    setChannelCount(channelCount);
    setSamplingRate(samplingRate);
    setFrameCount(((m_maxSampleBlockId - kSampleBlockIdMin) + 1) * m_framesPerSampleBlock);

    // Resize temporary buffer for decoded sample data
    const SINT sampleBufferCapacity =
            frames2samples(m_framesPerSampleBlock);
    m_sampleBuffer.resetCapacity(sampleBufferCapacity);

    // Discard all buffered samples
    m_inputBufferLength = 0;

    // Invalidate current position(s) for the following seek operation
    m_curSampleBlockId = MP4_INVALID_SAMPLE_ID;
    m_curFrameIndex = getMaxFrameIndex();

    // (Re-)Start decoding at the beginning of the file
    seekSampleFrame(getMinFrameIndex());

    return m_curFrameIndex == getMinFrameIndex();
}
コード例 #21
0
// soundsource overrides
Result SoundSourceCoreAudio::tryOpen(const AudioSourceConfig& audioSrcCfg) {
    const QString fileName(getLocalFileName());

    //Open the audio file.
    OSStatus err;

    /** This code blocks works with OS X 10.5+ only. DO NOT DELETE IT for now. */
    CFStringRef urlStr = CFStringCreateWithCharacters(0,
            reinterpret_cast<const UniChar *>(fileName.unicode()),
            fileName.size());
    CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, urlStr,
            kCFURLPOSIXPathStyle, false);
    err = ExtAudioFileOpenURL(urlRef, &m_audioFile);
    CFRelease(urlStr);
    CFRelease(urlRef);

    /** TODO: Use FSRef for compatibility with 10.4 Tiger.
     Note that ExtAudioFileOpen() is deprecated above Tiger, so we must maintain
     both code paths if someone finishes this part of the code.
     FSRef fsRef;
     CFURLGetFSRef(reinterpret_cast<CFURLRef>(url.get()), &fsRef);
     err = ExtAudioFileOpen(&fsRef, &m_audioFile);
     */

    if (err != noErr) {
        qDebug() << "SSCA: Error opening file " << fileName;
        return ERR;
    }

    // get the input file format
    UInt32 inputFormatSize = sizeof(m_inputFormat);
    err = ExtAudioFileGetProperty(m_audioFile,
            kExtAudioFileProperty_FileDataFormat, &inputFormatSize,
            &m_inputFormat);
    if (err != noErr) {
        qDebug() << "SSCA: Error getting file format (" << fileName << ")";
        return ERR;
    }
    m_bFileIsMp3 = m_inputFormat.mFormatID == kAudioFormatMPEGLayer3;

    // create the output format
    const UInt32 numChannels =
            (kChannelCountZero < audioSrcCfg.channelCountHint) ? audioSrcCfg.channelCountHint : 2;
    m_outputFormat = CAStreamBasicDescription(m_inputFormat.mSampleRate,
            numChannels, CAStreamBasicDescription::kPCMFormatFloat32, true);

    // set the client format
    err = ExtAudioFileSetProperty(m_audioFile,
            kExtAudioFileProperty_ClientDataFormat, sizeof(m_outputFormat),
            &m_outputFormat);
    if (err != noErr) {
        qDebug() << "SSCA: Error setting file property";
        return ERR;
    }

    //get the total length in frames of the audio file - copypasta: http://discussions.apple.com/thread.jspa?threadID=2364583&tstart=47
    SInt64 totalFrameCount;
    UInt32 totalFrameCountSize = sizeof(totalFrameCount);
    err = ExtAudioFileGetProperty(m_audioFile,
            kExtAudioFileProperty_FileLengthFrames, &totalFrameCountSize,
            &totalFrameCount);
    if (err != noErr) {
        qDebug() << "SSCA: Error getting number of frames";
        return ERR;
    }

    //
    // WORKAROUND for bug in ExtFileAudio
    //

    AudioConverterRef acRef;
    UInt32 acrsize = sizeof(AudioConverterRef);
    err = ExtAudioFileGetProperty(m_audioFile,
            kExtAudioFileProperty_AudioConverter, &acrsize, &acRef);
    //_ThrowExceptionIfErr(@"kExtAudioFileProperty_AudioConverter", err);

    AudioConverterPrimeInfo primeInfo;
    UInt32 piSize = sizeof(AudioConverterPrimeInfo);
    memset(&primeInfo, 0, piSize);
    err = AudioConverterGetProperty(acRef, kAudioConverterPrimeInfo, &piSize,
            &primeInfo);
    if (err != kAudioConverterErr_PropertyNotSupported) { // Only if decompressing
        //_ThrowExceptionIfErr(@"kAudioConverterPrimeInfo", err);
        m_headerFrames = primeInfo.leadingFrames;
    } else {
        m_headerFrames = 0;
    }

    setChannelCount(m_outputFormat.NumberChannels());
    setFrameRate(m_inputFormat.mSampleRate);
    // NOTE(uklotzde): This is what I found when migrating
    // the code from SoundSource (sample-oriented) to the new
    // AudioSource (frame-oriented) API. It is not documented
    // when m_headerFrames > 0 and what the consequences are.
    setFrameCount(totalFrameCount/* - m_headerFrames*/);

    //Seek to position 0, which forces us to skip over all the header frames.
    //This makes sure we're ready to just let the Analyser rip and it'll
    //get the number of samples it expects (ie. no header frames).
    seekSampleFrame(0);

    return OK;
}
コード例 #22
0
ファイル: soundsourcem4a.cpp プロジェクト: Kindamba/mixxx
Result SoundSourceM4A::tryOpen(const AudioSourceConfig& audioSrcCfg) {
    DEBUG_ASSERT(MP4_INVALID_FILE_HANDLE == m_hFile);
    /* open MP4 file, check for >= ver 1.9.1 */
#if MP4V2_PROJECT_version_hex <= 0x00010901
    m_hFile = MP4Read(getLocalFileNameBytes().constData(), 0);
#else
    m_hFile = MP4Read(getLocalFileNameBytes().constData());
#endif
    if (MP4_INVALID_FILE_HANDLE == m_hFile) {
        qWarning() << "Failed to open file for reading:" << getUrlString();
        return ERR;
    }

    m_trackId = findFirstAudioTrackId(m_hFile);
    if (MP4_INVALID_TRACK_ID == m_trackId) {
        qWarning() << "No AAC track found:" << getUrlString();
        return ERR;
    }

    const MP4SampleId numberOfSamples =
            MP4GetTrackNumberOfSamples(m_hFile, m_trackId);
    if (0 >= numberOfSamples) {
        qWarning() << "Failed to read number of samples from file:" << getUrlString();
        return ERR;
    }
    m_maxSampleBlockId = kSampleBlockIdMin + (numberOfSamples - 1);

    // Determine the maximum input size (in bytes) of a
    // sample block for the selected track.
    const u_int32_t maxSampleBlockInputSize = MP4GetTrackMaxSampleSize(m_hFile,
            m_trackId);
    m_inputBuffer.resize(maxSampleBlockInputSize, 0);

    DEBUG_ASSERT(NULL == m_hDecoder); // not already opened
    m_hDecoder = NeAACDecOpen();
    if (!m_hDecoder) {
        qWarning() << "Failed to open the AAC decoder!";
        return ERR;
    }
    NeAACDecConfigurationPtr pDecoderConfig = NeAACDecGetCurrentConfiguration(
            m_hDecoder);
    pDecoderConfig->outputFormat = FAAD_FMT_FLOAT;
    if ((kChannelCountMono == audioSrcCfg.channelCountHint) ||
            (kChannelCountStereo == audioSrcCfg.channelCountHint)) {
        pDecoderConfig->downMatrix = 1;
    } else {
        pDecoderConfig->downMatrix = 0;
    }

    pDecoderConfig->defObjectType = LC;
    if (!NeAACDecSetConfiguration(m_hDecoder, pDecoderConfig)) {
        qWarning() << "Failed to configure AAC decoder!";
        return ERR;
    }

    u_int8_t* configBuffer = NULL;
    u_int32_t configBufferSize = 0;
    if (!MP4GetTrackESConfiguration(m_hFile, m_trackId, &configBuffer,
            &configBufferSize)) {
        /* failed to get mpeg-4 audio config... this is ok.
         * NeAACDecInit2() will simply use default values instead.
         */
        qWarning() << "Failed to read the MP4 audio configuration."
                << "Continuing with default values.";
    }

    SAMPLERATE_TYPE sampleRate;
    unsigned char channelCount;
    if (0 > NeAACDecInit2(m_hDecoder, configBuffer, configBufferSize,
                    &sampleRate, &channelCount)) {
        free(configBuffer);
        qWarning() << "Failed to initialize the AAC decoder!";
        return ERR;
    } else {
        free(configBuffer);
    }

    setChannelCount(channelCount);
    setFrameRate(sampleRate);
    setFrameCount(getFrameCountForSampleBlockId(m_maxSampleBlockId));

    // Resize temporary buffer for decoded sample data
    const SINT sampleBufferCapacity =
            frames2samples(kFramesPerSampleBlock);
    m_sampleBuffer.resetCapacity(sampleBufferCapacity);

    // Invalidate current position to enforce the following
    // seek operation
    m_curFrameIndex = getMaxFrameIndex();

    // (Re-)Start decoding at the beginning of the file
    seekSampleFrame(getMinFrameIndex());

    return OK;
}
コード例 #23
0
ファイル: soundsourceoggvorbis.cpp プロジェクト: MK-42/mixxx
SoundSource::OpenResult SoundSourceOggVorbis::tryOpen(
        OpenMode /*mode*/,
        const OpenParams& /*config*/) {
    m_pFile = std::make_unique<QFile>(getLocalFileName());
    if (!m_pFile->open(QFile::ReadOnly)) {
        kLogger.warning()
                << "Failed to open file for"
                << getUrlString();
        return OpenResult::Failed;
    }

    const int initDecoderResult = ov_open_callbacks(m_pFile.get(), &m_vf, nullptr, 0, s_callbacks);
    switch (initDecoderResult) {
    case 0:
        // success -> continue
        break;
    case OV_ENOTVORBIS:
    case OV_EVERSION:
        kLogger.warning()
            << "Unsupported format in"
            << getUrlString();
        return OpenResult::Aborted;
    default:
        kLogger.warning()
            << "Failed to initialize decoder for"
            << getUrlString();
        return OpenResult::Failed;
    }

    if (!ov_seekable(&m_vf)) {
        kLogger.warning()
                << "Stream in"
                << getUrlString()
                << "is not seekable";
        return OpenResult::Aborted;
    }

    // lookup the ogg's channels and sample rate
    const vorbis_info* vi = ov_info(&m_vf, kCurrentBitstreamLink);
    if (!vi) {
        kLogger.warning()
                << "Failed to read stream info from"
                << getUrlString();
        return OpenResult::Failed;
    }
    setChannelCount(vi->channels);
    setSampleRate(vi->rate);
    if (0 < vi->bitrate_nominal) {
        initBitrateOnce(vi->bitrate_nominal / 1000);
    } else {
        if ((0 < vi->bitrate_lower) && (vi->bitrate_lower == vi->bitrate_upper)) {
            initBitrateOnce(vi->bitrate_lower / 1000);
        }
    }

    ogg_int64_t pcmTotal = ov_pcm_total(&m_vf, kEntireBitstreamLink);
    if (0 <= pcmTotal) {
        initFrameIndexRangeOnce(IndexRange::forward(0, pcmTotal));
    } else {
        kLogger.warning()
                << "Failed to read read total length of"
                << getUrlString();
        return OpenResult::Failed;
    }

    return OpenResult::Succeeded;
}
コード例 #24
0
/** Cobbled together from:
 http://msdn.microsoft.com/en-us/library/dd757929(v=vs.85).aspx
 and http://msdn.microsoft.com/en-us/library/dd317928(VS.85).aspx
 -- Albert
 If anything in here fails, just bail. I'm not going to decode HRESULTS.
 -- Bill
 */
bool SoundSourceMediaFoundation::configureAudioStream(const AudioSourceConfig& audioSrcCfg) {
    HRESULT hr;

    // deselect all streams, we only want the first
    hr = m_pSourceReader->SetStreamSelection(
            MF_SOURCE_READER_ALL_STREAMS, false);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to deselect all streams";
        return false;
    }

    hr = m_pSourceReader->SetStreamSelection(
            kStreamIndex, true);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to select first audio stream";
        return false;
    }

    IMFMediaType* pAudioType = nullptr;

    hr = m_pSourceReader->GetCurrentMediaType(
            kStreamIndex, &pAudioType);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to get current media type from stream";
        return false;
    }

    //------ Get bitrate from the file, before we change it to get uncompressed audio
    UINT32 avgBytesPerSecond;

    hr = pAudioType->GetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &avgBytesPerSecond);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "error getting MF_MT_AUDIO_AVG_BYTES_PER_SECOND";
        return false;
    }

    setBitrate( (avgBytesPerSecond * 8) / 1000);
    //------

    hr = pAudioType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to set major type to audio";
        safeRelease(&pAudioType);
        return false;
    }

    hr = pAudioType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to set subtype format to float";
        safeRelease(&pAudioType);
        return false;
    }

    hr = pAudioType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, true);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to set all samples independent";
        safeRelease(&pAudioType);
        return false;
    }

    hr = pAudioType->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, true);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to set fixed size samples";
        safeRelease(&pAudioType);
        return false;
    }

    hr = pAudioType->SetUINT32(
            MF_MT_AUDIO_BITS_PER_SAMPLE, kBitsPerSample);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to set bits per sample:"
                << kBitsPerSample;
        safeRelease(&pAudioType);
        return false;
    }

    const UINT sampleSize = kLeftoverSize * kBytesPerSample;
    hr = pAudioType->SetUINT32(
            MF_MT_SAMPLE_SIZE, sampleSize);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to set sample size:"
                << sampleSize;
        safeRelease(&pAudioType);
        return false;
    }

    UINT32 numChannels;
    hr = pAudioType->GetUINT32(
            MF_MT_AUDIO_NUM_CHANNELS, &numChannels);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to get actual number of channels";
        return false;
    } else {
        qDebug() << "Number of channels in input stream" << numChannels;
    }
    if (audioSrcCfg.hasValidChannelCount()) {
        numChannels = audioSrcCfg.getChannelCount();
        hr = pAudioType->SetUINT32(
                MF_MT_AUDIO_NUM_CHANNELS, numChannels);
        if (FAILED(hr)) {
            qWarning() << kLogPreamble << hr
                    << "failed to set number of channels:"
                    << numChannels;
            safeRelease(&pAudioType);
            return false;
        }
        qDebug() << "Requested number of channels" << numChannels;
    }

    UINT32 samplesPerSecond;
    hr = pAudioType->GetUINT32(
            MF_MT_AUDIO_SAMPLES_PER_SECOND, &samplesPerSecond);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to get samples per second";
        return false;
    } else {
        qDebug() << "Samples per second in input stream" << samplesPerSecond;
    }
    if (audioSrcCfg.hasValidSamplingRate()) {
        samplesPerSecond = audioSrcCfg.getSamplingRate();
        hr = pAudioType->SetUINT32(
                MF_MT_AUDIO_SAMPLES_PER_SECOND, samplesPerSecond);
        if (FAILED(hr)) {
            qWarning() << kLogPreamble << hr
                    << "failed to set samples per second:"
                    << samplesPerSecond;
            safeRelease(&pAudioType);
            return false;
        }
        qDebug() << "Requested samples per second" << samplesPerSecond;
    }

    // Set this type on the source reader. The source reader will
    // load the necessary decoder.
    hr = m_pSourceReader->SetCurrentMediaType(
            kStreamIndex, nullptr, pAudioType);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to set media type";
        safeRelease(&pAudioType);
        return false;
    }

    // Finally release the reference before reusing the pointer
    safeRelease(&pAudioType);

    // Get the resulting output format.
    hr = m_pSourceReader->GetCurrentMediaType(
            kStreamIndex, &pAudioType);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to retrieve completed media type";
        return false;
    }

    // Ensure the stream is selected.
    hr = m_pSourceReader->SetStreamSelection(
            kStreamIndex, true);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to select first audio stream (again)";
        return false;
    }

    hr = pAudioType->GetUINT32(
            MF_MT_AUDIO_NUM_CHANNELS, &numChannels);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to get actual number of channels";
        return false;
    }
    setChannelCount(numChannels);

    hr = pAudioType->GetUINT32(
            MF_MT_AUDIO_SAMPLES_PER_SECOND, &samplesPerSecond);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to get the actual sample rate";
        return false;
    }
    setSamplingRate(samplesPerSecond);

    UINT32 leftoverBufferSizeInBytes = 0;
    hr = pAudioType->GetUINT32(MF_MT_SAMPLE_SIZE, &leftoverBufferSizeInBytes);
    if (FAILED(hr)) {
        qWarning() << kLogPreamble << hr
                << "failed to get sample buffer size (in bytes)";
        return false;
    }
    DEBUG_ASSERT((leftoverBufferSizeInBytes % kBytesPerSample) == 0);
    m_sampleBuffer.resetCapacity(leftoverBufferSizeInBytes / kBytesPerSample);
    DEBUG_ASSERT(m_sampleBuffer.getCapacity() > 0);
    qDebug() << kLogPreamble
            << "Sample buffer capacity"
            << m_sampleBuffer.getCapacity();

            
    // Finally release the reference
    safeRelease(&pAudioType);

    return true;
}
コード例 #25
0
ファイル: soundsourcem4a.cpp プロジェクト: EQ4/mixxx
Result SoundSourceM4A::tryOpen(const AudioSourceConfig& audioSrcCfg) {
    DEBUG_ASSERT(MP4_INVALID_FILE_HANDLE == m_hFile);
    // open MP4 file, check for >= ver 1.9.1
    // From mp4v2/file.h:
    //  * On Windows, this should be a UTF-8 encoded string.
    //  * On other platforms, it should be an 8-bit encoding that is
    //  * appropriate for the platform, locale, file system, etc.
    //  * (prefer to use UTF-8 when possible).
#if MP4V2_PROJECT_version_hex <= 0x00010901
    m_hFile = MP4Read(getLocalFileName().toUtf8().constData(), 0);
#else
    m_hFile = MP4Read(getLocalFileName().toUtf8().constData());
#endif
    if (MP4_INVALID_FILE_HANDLE == m_hFile) {
        qWarning() << "Failed to open file for reading:" << getUrlString();
        return ERR;
    }

    m_trackId = findFirstAudioTrackId(m_hFile);
    if (MP4_INVALID_TRACK_ID == m_trackId) {
        qWarning() << "No AAC track found:" << getUrlString();
        return ERR;
    }

    // Read fixed sample duration.  If the sample duration is not
    // fixed (that is, if the number of frames per sample block varies
    // through the file), the call returns MP4_INVALID_DURATION. We
    // can't currently handle these.
    m_framesPerSampleBlock = MP4GetTrackFixedSampleDuration(m_hFile, m_trackId);
    if (MP4_INVALID_DURATION == m_framesPerSampleBlock) {
      qWarning() << "Unable to decode tracks with non-fixed sample durations: " << getUrlString();
      return ERR;
    }

    const MP4SampleId numberOfSamples =
            MP4GetTrackNumberOfSamples(m_hFile, m_trackId);
    if (0 >= numberOfSamples) {
        qWarning() << "Failed to read number of samples from file:" << getUrlString();
        return ERR;
    }
    m_maxSampleBlockId = kSampleBlockIdMin + (numberOfSamples - 1);

    // Determine the maximum input size (in bytes) of a
    // sample block for the selected track.
    const u_int32_t maxSampleBlockInputSize = MP4GetTrackMaxSampleSize(m_hFile,
            m_trackId);
    m_inputBuffer.resize(maxSampleBlockInputSize, 0);

    DEBUG_ASSERT(nullptr == m_hDecoder); // not already opened
    m_hDecoder = NeAACDecOpen();
    if (!m_hDecoder) {
        qWarning() << "Failed to open the AAC decoder!";
        return ERR;
    }
    NeAACDecConfigurationPtr pDecoderConfig = NeAACDecGetCurrentConfiguration(
            m_hDecoder);
    pDecoderConfig->outputFormat = FAAD_FMT_FLOAT;
    if ((kChannelCountMono == audioSrcCfg.channelCountHint) ||
            (kChannelCountStereo == audioSrcCfg.channelCountHint)) {
        pDecoderConfig->downMatrix = 1;
    } else {
        pDecoderConfig->downMatrix = 0;
    }

    pDecoderConfig->defObjectType = LC;
    if (!NeAACDecSetConfiguration(m_hDecoder, pDecoderConfig)) {
        qWarning() << "Failed to configure AAC decoder!";
        return ERR;
    }

    u_int8_t* configBuffer = nullptr;
    u_int32_t configBufferSize = 0;
    if (!MP4GetTrackESConfiguration(m_hFile, m_trackId, &configBuffer,
            &configBufferSize)) {
        /* failed to get mpeg-4 audio config... this is ok.
         * NeAACDecInit2() will simply use default values instead.
         */
        qWarning() << "Failed to read the MP4 audio configuration."
                << "Continuing with default values.";
    }

    SAMPLERATE_TYPE sampleRate;
    unsigned char channelCount;
    if (0 > NeAACDecInit2(m_hDecoder, configBuffer, configBufferSize,
                    &sampleRate, &channelCount)) {
        free(configBuffer);
        qWarning() << "Failed to initialize the AAC decoder!";
        return ERR;
    } else {
        free(configBuffer);
    }

    // Calculate how many sample blocks we need to decode in advance
    // of a random seek in order to get the recommended number of
    // prefetch frames
    m_numberOfPrefetchSampleBlocks  = (kNumberOfPrefetchFrames +
                                      (m_framesPerSampleBlock - 1)) / m_framesPerSampleBlock;

    setChannelCount(channelCount);
    setFrameRate(sampleRate);
    setFrameCount(((m_maxSampleBlockId - kSampleBlockIdMin) + 1) * m_framesPerSampleBlock);

    // Resize temporary buffer for decoded sample data
    const SINT sampleBufferCapacity =
            frames2samples(m_framesPerSampleBlock);
    m_sampleBuffer.resetCapacity(sampleBufferCapacity);

    // Invalidate current position to enforce the following
    // seek operation
    m_curFrameIndex = getMaxFrameIndex();

    // (Re-)Start decoding at the beginning of the file
    seekSampleFrame(getMinFrameIndex());

    return OK;
}
コード例 #26
0
Result SoundSourceFFmpeg::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) {
    unsigned int i;
    AVDictionary *l_iFormatOpts = NULL;

    const QByteArray qBAFilename(getLocalFileNameBytes());
    qDebug() << "New SoundSourceFFmpeg :" << qBAFilename;

    DEBUG_ASSERT(!m_pFormatCtx);
    m_pFormatCtx = avformat_alloc_context();

#if LIBAVCODEC_VERSION_INT < 3622144
    m_pFormatCtx->max_analyze_duration = 999999999;
#endif

    // Open file and make m_pFormatCtx
    if (avformat_open_input(&m_pFormatCtx, qBAFilename.constData(), NULL,
                            &l_iFormatOpts)!=0) {
        qDebug() << "av_open_input_file: cannot open" << qBAFilename;
        return ERR;
    }

#if LIBAVCODEC_VERSION_INT > 3544932
    av_dict_free(&l_iFormatOpts);
#endif

    // Retrieve stream information
    if (avformat_find_stream_info(m_pFormatCtx, NULL)<0) {
        qDebug() << "av_find_stream_info: cannot open" << qBAFilename;
        return ERR;
    }

    //debug only (Enable if needed)
    //av_dump_format(m_pFormatCtx, 0, qBAFilename.constData(), false);

    // Find the first audio stream
    m_iAudioStream=-1;

    for (i=0; i<m_pFormatCtx->nb_streams; i++)
        if (m_pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO) {
            m_iAudioStream=i;
            break;
        }
    if (m_iAudioStream == -1) {
        qDebug() << "ffmpeg: cannot find an audio stream: cannot open"
                 << qBAFilename;
        return ERR;
    }

    // Get a pointer to the codec context for the audio stream
    m_pCodecCtx=m_pFormatCtx->streams[m_iAudioStream]->codec;

    // Find the decoder for the audio stream
    if (!(m_pCodec=avcodec_find_decoder(m_pCodecCtx->codec_id))) {
        qDebug() << "ffmpeg: cannot find a decoder for" << qBAFilename;
        return ERR;
    }

    if (avcodec_open2(m_pCodecCtx, m_pCodec, NULL)<0) {
        qDebug() << "ffmpeg:  cannot open" << qBAFilename;
        return ERR;
    }

    m_pResample = new EncoderFfmpegResample(m_pCodecCtx);
    m_pResample->open(m_pCodecCtx->sample_fmt, AV_SAMPLE_FMT_FLT);

    setChannelCount(m_pCodecCtx->channels);
    setFrameRate(m_pCodecCtx->sample_rate);
    setFrameCount((m_pFormatCtx->duration * m_pCodecCtx->sample_rate) / AV_TIME_BASE);

    qDebug() << "ffmpeg: Samplerate: " << getFrameRate() << ", Channels: " <<
             getChannelCount() << "\n";
    if (getChannelCount() > 2) {
        qDebug() << "ffmpeg: No support for more than 2 channels!";
        return ERR;
    }

    return OK;
}
コード例 #27
0
ファイル: soundsourcemodplug.cpp プロジェクト: raulbehl/mixxx
Result SoundSourceModPlug::tryOpen(const AudioSourceConfig& /*audioSrcCfg*/) {
    ScopedTimer t("SoundSourceModPlug::open()");

    // read module file to byte array
    const QString fileName(getLocalFileName());
    QFile modFile(fileName);
    qDebug() << "[ModPlug] Loading ModPlug module " << modFile.fileName();
    modFile.open(QIODevice::ReadOnly);
    m_fileBuf = modFile.readAll();
    modFile.close();

    // get ModPlugFile descriptor for later access
    m_pModFile = ModPlug::ModPlug_Load(m_fileBuf.constData(),
            m_fileBuf.length());
    if (m_pModFile == NULL) {
        // an error occured
        t.cancel();
        qDebug() << "[ModPlug] Could not load module file: " << fileName;
        return ERR;
    }

    DEBUG_ASSERT(0 == (kChunkSizeInBytes % sizeof(m_sampleBuf[0])));
    const SINT chunkSizeInSamples = kChunkSizeInBytes / sizeof(m_sampleBuf[0]);

    const SampleBuffer::size_type bufferSizeLimitInSamples = s_bufferSizeLimit / sizeof(m_sampleBuf[0]);

    // Estimate size of sample buffer (for better performance) aligned
    // with the chunk size. Beware: Module length estimation is unreliable
    // due to loops!
    const SampleBuffer::size_type estimateMilliseconds =
            ModPlug::ModPlug_GetLength(m_pModFile);
    const SampleBuffer::size_type estimateSamples =
            estimateMilliseconds * kChannelCount * kSamplingRate;
    const SampleBuffer::size_type estimateChunks =
            (estimateSamples + (chunkSizeInSamples - 1)) / chunkSizeInSamples;
    const SampleBuffer::size_type sampleBufferCapacity = math_min(
            estimateChunks * chunkSizeInSamples, bufferSizeLimitInSamples);
    m_sampleBuf.reserve(sampleBufferCapacity);
    qDebug() << "[ModPlug] Reserved " << m_sampleBuf.capacity() << " #samples";

    // decode samples into sample buffer
    while (m_sampleBuf.size() < bufferSizeLimitInSamples) {
        // reserve enough space in sample buffer
        const SampleBuffer::size_type currentSize = m_sampleBuf.size();
        m_sampleBuf.resize(currentSize + chunkSizeInSamples);
        const int bytesRead = ModPlug::ModPlug_Read(m_pModFile,
                &m_sampleBuf[currentSize],
                kChunkSizeInBytes);
        // adjust size of sample buffer after reading
        if (0 < bytesRead) {
            DEBUG_ASSERT(0 == (bytesRead % sizeof(m_sampleBuf[0])));
            const SampleBuffer::size_type samplesRead = bytesRead / sizeof(m_sampleBuf[0]);
            m_sampleBuf.resize(currentSize + samplesRead);
        } else {
            // nothing read -> EOF
            m_sampleBuf.resize(currentSize);
            break; // exit loop
        }
    }
    qDebug() << "[ModPlug] Filled Sample buffer with " << m_sampleBuf.size()
            << " samples.";
    qDebug() << "[ModPlug] Sample buffer has "
            << m_sampleBuf.capacity() - m_sampleBuf.size()
            << " samples unused capacity.";

    setChannelCount(kChannelCount);
    setSamplingRate(kSamplingRate);
    setFrameCount(samples2frames(m_sampleBuf.size()));
    m_seekPos = 0;

    return OK;
}
コード例 #28
0
/** Cobbled together from:
 http://msdn.microsoft.com/en-us/library/dd757929(v=vs.85).aspx
 and http://msdn.microsoft.com/en-us/library/dd317928(VS.85).aspx
 -- Albert
 If anything in here fails, just bail. I'm not going to decode HRESULTS.
 -- Bill
 */
bool SoundSourceMediaFoundation::configureAudioStream(const Mixxx::AudioSourceConfig& audioSrcCfg) {
    HRESULT hr(S_OK);

    // deselect all streams, we only want the first
    hr = m_pReader->SetStreamSelection(MF_SOURCE_READER_ALL_STREAMS, false);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to deselect all streams";
        return false;
    }

    hr = m_pReader->SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM,
            true);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to select first audio stream";
        return false;
    }

    hr = MFCreateMediaType(&m_pAudioType);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to create media type";
        return false;
    }

    hr = m_pAudioType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to set major type";
        return false;
    }

    hr = m_pAudioType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to set subtype";
        return false;
    }

    hr = m_pAudioType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, true);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to set samples independent";
        return false;
    }

    hr = m_pAudioType->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, true);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to set fixed size samples";
        return false;
    }

    hr = m_pAudioType->SetUINT32(MF_MT_SAMPLE_SIZE, kLeftoverSize);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to set sample size";
        return false;
    }

    hr = m_pAudioType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, kSampleRate);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to set sample rate";
        return false;
    }

    // "Number of bits per audio sample in an audio media type."
    hr = m_pAudioType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, kBitsPerSample);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to set bits per sample";
        return false;
    }

    if (isValidChannelCount(audioSrcCfg.channelCountHint)) {
        hr = m_pAudioType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, audioSrcCfg.channelCountHint);
        if (FAILED(hr)) {
            qWarning() << "SSMF: failed to set number of channels";
            return false;
        }
        setChannelCount(audioSrcCfg.channelCountHint);
    } else {
        UINT32 numChannels = 0;
        hr = m_pAudioType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &numChannels);
        if (FAILED(hr) || (0 >= numChannels)) {
            qWarning() << "SSMF: failed to get number of channels";
            return false;
        }
        setChannelCount(numChannels);
    }

    // "...the block alignment is equal to the number of audio channels
    // multiplied by the number of bytes per audio sample."
    hr = m_pAudioType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT,
            frames2samples(sizeof(m_leftoverBuffer[0])));
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to set block alignment";
        return false;
    }

    // Set this type on the source reader. The source reader will
    // load the necessary decoder.
    hr = m_pReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM,
    NULL, m_pAudioType);

    // the reader has the media type now, free our reference so we can use our
    // pointer for other purposes. Do this before checking for failure so we
    // don't dangle.
    safeRelease(&m_pAudioType);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to set media type";
        return false;
    }

    // Get the complete uncompressed format.
    hr = m_pReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM,
            &m_pAudioType);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to retrieve completed media type";
        return false;
    }

    // Ensure the stream is selected.
    hr = m_pReader->SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM,
            true);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to select first audio stream (again)";
        return false;
    }

    UINT32 leftoverBufferSize = 0;
    hr = m_pAudioType->GetUINT32(MF_MT_SAMPLE_SIZE, &leftoverBufferSize);
    if (FAILED(hr)) {
        qWarning() << "SSMF: failed to get buffer size";
        return false;
    }
    m_leftoverBufferSize = leftoverBufferSize;
    m_leftoverBufferSize /= sizeof(CSAMPLE); // convert size in bytes to sizeof(CSAMPLE)
    m_leftoverBuffer = new CSAMPLE[m_leftoverBufferSize];

    return true;
}
コード例 #29
0
ファイル: soundsourceflac.cpp プロジェクト: demos/mixxx
void SoundSourceFLAC::flacMetadata(const FLAC__StreamMetadata* metadata) {
    // https://xiph.org/flac/api/group__flac__stream__decoder.html#ga43e2329c15731c002ac4182a47990f85
    // "...one STREAMINFO block, followed by zero or more other metadata blocks."
    // "...by default the decoder only calls the metadata callback for the STREAMINFO block..."
    // "...always before the first audio frame (i.e. write callback)."
    switch (metadata->type) {
    case FLAC__METADATA_TYPE_STREAMINFO:
    {
        const SINT channelCount = metadata->data.stream_info.channels;
        if (isValidChannelCount(channelCount)) {
            if (hasChannelCount()) {
                // already set before -> check for consistency
                if (getChannelCount() != channelCount) {
                    qWarning() << "Unexpected channel count:"
                            << channelCount << " <> " << getChannelCount();
                }
            } else {
                // not set before
                setChannelCount(channelCount);
            }
        } else {
            qWarning() << "Invalid channel count:"
                    << channelCount;
        }
        const SINT samplingRate = metadata->data.stream_info.sample_rate;
        if (isValidSamplingRate(samplingRate)) {
            if (hasSamplingRate()) {
                // already set before -> check for consistency
                if (getSamplingRate() != samplingRate) {
                    qWarning() << "Unexpected sampling rate:"
                            << samplingRate << " <> " << getSamplingRate();
                }
            } else {
                // not set before
                setSamplingRate(samplingRate);
            }
        } else {
            qWarning() << "Invalid sampling rate:"
                    << samplingRate;
        }
        const SINT frameCount = metadata->data.stream_info.total_samples;
        DEBUG_ASSERT(isValidFrameCount(frameCount));
        if (isEmpty()) {
            // not set before
            setFrameCount(frameCount);
        } else {
            // already set before -> check for consistency
            if (getFrameCount() != frameCount) {
                qWarning() << "Unexpected frame count:"
                        << frameCount << " <> " << getFrameCount();
            }
        }
        const unsigned bitsPerSample = metadata->data.stream_info.bits_per_sample;
        DEBUG_ASSERT(kBitsPerSampleDefault != bitsPerSample);
        if (kBitsPerSampleDefault == m_bitsPerSample) {
            // not set before
            m_bitsPerSample = bitsPerSample;
            m_sampleScaleFactor = CSAMPLE_PEAK
                    / CSAMPLE(FLAC__int32(1) << bitsPerSample);
        } else {
            // already set before -> check for consistency
            if (bitsPerSample != m_bitsPerSample) {
                qWarning() << "Unexpected bits per sample:"
                        << bitsPerSample << " <> " << m_bitsPerSample;
            }
        }
        m_maxBlocksize = metadata->data.stream_info.max_blocksize;
        if (0 >= m_maxBlocksize) {
            qWarning() << "Invalid max. blocksize" << m_maxBlocksize;
        }
        const SINT sampleBufferCapacity =
                m_maxBlocksize * getChannelCount();
        m_sampleBuffer.resetCapacity(sampleBufferCapacity);
        break;
    }
    default:
        // Ignore all other metadata types
        break;
    }
}