Exemple #1
0
int
OpusDecoder_init(decoders_OpusDecoder *self,
                 PyObject *args, PyObject *kwds)
{
    char *filename;
    int error;

    self->opus_file = NULL;
    self->audiotools_pcm = NULL;
    self->closed = 0;

    if (!PyArg_ParseTuple(args, "s", &filename))
        return -1;

    if ((self->opus_file = op_open_file(filename, &error)) == NULL) {
        PyErr_SetString(PyExc_ValueError, "error opening Opus file");
        return -1;
    }

    self->channel_count = op_channel_count(self->opus_file, -1);

    if ((self->audiotools_pcm = open_audiotools_pcm()) == NULL)
        return -1;

    return 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;
}
OpusDynamicLoader::OpusDynamicLoader(const std::string &path)
		:
		DynamicLoader{path} {
	// open opus file
	auto op_file = open_opus_file();

	// read channels from the opus file
	channels = op_channel_count(op_file.get(), -1);

	length = op_pcm_total(op_file.get(), -1) * 2;
	log::msg("Create dynamic opus loader: len=%d, chan=%d", length, channels);
}
Exemple #4
0
int CSound::DecodeOpus(int SampleID, const void *pData, unsigned DataSize)
{
	if(SampleID == -1 || SampleID >= NUM_SAMPLES)
		return -1;

	CSample *pSample = &m_aSamples[SampleID];

	OggOpusFile *OpusFile = op_open_memory((const unsigned char *) pData, DataSize, NULL);
	if (OpusFile)
	{
		int NumChannels = op_channel_count(OpusFile, -1);
		int NumSamples = op_pcm_total(OpusFile, -1); // per channel!

		pSample->m_Channels = NumChannels;

		if(pSample->m_Channels > 2)
		{
			dbg_msg("sound/opus", "file is not mono or stereo.");
			return -1;
		}

		pSample->m_pData = (short *)mem_alloc(NumSamples * sizeof(short) * NumChannels, 1);

		int Read;
		int Pos = 0;
		while (Pos < NumSamples)
		{
			Read = op_read(OpusFile, pSample->m_pData + Pos*NumChannels, NumSamples*NumChannels, NULL);
			Pos += Read;
		}

		pSample->m_NumFrames = NumSamples; // ?
		pSample->m_Rate = 48000;
		pSample->m_LoopStart = -1;
		pSample->m_LoopEnd = -1;
		pSample->m_PausedAt = 0;
	}
	else
	{
		dbg_msg("sound/opus", "failed to decode sample");
		return -1;
	}

	return SampleID;
}
pcm_data_t OpusInMemoryLoader::get_resource() {
	int op_err;
	// open the opus file
	opus_file_t op_file{op_open_file(path.c_str(), &op_err), opus_deleter};

	if (op_err != 0) {
		throw util::Error{"Could not open: %s", path.c_str()};
	}

	// determine number of channels and number of pcm samples
	auto op_channels = op_channel_count(op_file.get(), -1);
	auto pcm_length = op_pcm_total(op_file.get(), -1);
	log::dbg("Opus channels=%d, pcm_length=%u", op_channels, static_cast<uint32_t>(pcm_length));

	// calculate pcm buffer size depending on the number of channels
	// if the opus file only had one channel, the pcm buffer size must be
	// doubled
	uint32_t length = static_cast<uint32_t>(pcm_length) * 2;
	pcm_data_t buffer(static_cast<size_t>(length), 0);

	// read data from opus file
	int position = 0;
	while (true) {
		int samples_read = op_read(op_file.get(), &buffer.front()+position,
				length-position, nullptr);
		if (samples_read < 0) {
			throw util::Error{"Failed to read from opus file: errorcode=%d", samples_read};
		} else if(samples_read == 0) {
			break;
		}

		position += samples_read * op_channels;
	}

	// convert from mono to stereo
	if (op_channels == 1) {
		for(int i = pcm_length-1; i >= 0; i--) {
			auto value = buffer[i];
			buffer[i*2+1] = value;
			buffer[i*2] = value;
		}
	}

	return std::move(buffer);
}
Exemple #6
0
static gulong
xmms_opus_op_read (OggOpusFile *of, gchar *buf, gint len, gint bigendian,
                     gint sampsize, gint signd, gint *outbuf)
{
	gulong ret;
	int channels;

	channels = op_channel_count (of, -1);

	do {								 /* FIXME buffer len / sample size */
		//ret = op_read_float (of, (float *)buf, len / sizeof(float), outbuf);
		ret = op_read (of, (opus_int16 *)buf, len / 2, outbuf);
	} while (ret == OP_HOLE);

	/* FIXME bytes from samples_read * channels * sample size */
	//ret = ret * channels * sizeof(float);
	ret = ret * channels * 2;

	return ret;
}
Exemple #7
0
static void
xmms_opus_read_metadata (xmms_xform_t *xform, xmms_opus_data_t *data)
{
	data->opushead = op_head (data->opusfile, -1);
	data->opustags = op_tags (data->opusfile, -1);
	data->channels = op_channel_count (data->opusfile, -1);

	gint i;

	if (!data->opustags)
		return;

	for (i = 0; i < data->opustags->comments; i++) {
		const gchar *ptr, *entry;
		gsize length;
		gchar key[64];

		entry = data->opustags->user_comments[i];
		length = data->opustags->comment_lengths[i];

		if (entry == NULL || *entry == '\0')
			continue;

		/* check whether it's a valid comment */
		ptr = memchr (entry, '=', length);
		if (ptr == NULL)
			continue;

		ptr++;

		g_strlcpy (key, entry, MIN (ptr - entry, sizeof (key)));

		if (!xmms_xform_metadata_mapper_match (xform, key, ptr, length - (ptr - entry))) {
			XMMS_DBG ("Unhandled tag '%s'", entry);
		}

	}
}
static prMALError 
SDKImportAudio7(
	imStdParms			*stdParms, 
	imFileRef			SDKfileRef, 
	imImportAudioRec7	*audioRec7)
{
	prMALError		result		= malNoError;

	// privateData
	ImporterLocalRec8H ldataH = reinterpret_cast<ImporterLocalRec8H>(audioRec7->privateData);
	stdParms->piSuites->memFuncs->lockHandle(reinterpret_cast<char**>(ldataH));
	ImporterLocalRec8Ptr localRecP = reinterpret_cast<ImporterLocalRec8Ptr>( *ldataH );


	if(localRecP)
	{
		assert(audioRec7->position >= 0); // Do they really want contiguous samples?
		
		// for surround channels
		// Premiere uses Left, Right, Left Rear, Right Rear, Center, LFE
		// Ogg (and Opus) uses Left, Center, Right, Left Read, Right Rear, LFE
		// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9
		static const int surround_swizzle[] = {0, 2, 3, 4, 1, 5};
		static const int stereo_swizzle[] = {0, 1, 2, 3, 4, 5}; // no swizzle, actually
		
		const int *swizzle = localRecP->numChannels > 2 ? surround_swizzle : stereo_swizzle;
		
						
		if(localRecP->fileType == Ogg_filetype && localRecP->vf != NULL)
		{
			OggVorbis_File &vf = *localRecP->vf;
			
			int seek_err = OV_OK;
			
			if(audioRec7->position >= 0) // otherwise contiguous, but we should be good at the current position
				seek_err = ov_pcm_seek(&vf, audioRec7->position);
				
			
			if(seek_err == OV_OK)
			{
				int num = 0;
				float **pcm_channels;
				
				long samples_needed = audioRec7->size;
				long pos = 0;
				
				while(samples_needed > 0 && result == malNoError)
				{
					int samples = samples_needed;
					
					if(samples > 1024)
						samples = 1024; // maximum size this call can read at once
				
					long samples_read = ov_read_float(&vf, &pcm_channels, samples, &num);
					
					if(samples_read >= 0)
					{
						if(samples_read == 0)
						{
							// EOF
							// Premiere will keep asking me for more and more samples,
							// even beyond what I told it I had in SDKFileInfo8->audDuration.
							// Just stop and everything will be fine.
							break;
						}
						
						for(int i=0; i < localRecP->numChannels; i++)
						{
							memcpy(&audioRec7->buffer[swizzle[i]][pos], pcm_channels[i], samples_read * sizeof(float));
						}
						
						samples_needed -= samples_read;
						pos += samples_read;
					}
					else
						result = imDecompressionError;
				}
			}
		}
		else if(localRecP->fileType == Opus_filetype && localRecP->opus != NULL)
		{
			const int num_channels = op_channel_count(localRecP->opus, -1);
		
			assert(localRecP->numChannels == num_channels);
			
			
			int seek_err = OV_OK;
			
			if(audioRec7->position >= 0) // otherwise contiguous, but we should be good at the current position
				seek_err = op_pcm_seek(localRecP->opus, audioRec7->position);
				
			
			if(seek_err == OV_OK)
			{
				float *pcm_buf = (float *)malloc(sizeof(float) * audioRec7->size * num_channels);
				
				if(pcm_buf != NULL)
				{
					long samples_needed = audioRec7->size;
					long pos = 0;
					
					while(samples_needed > 0 && result == malNoError)
					{
						float *_pcm = &pcm_buf[pos * num_channels];
						
						int samples_read = op_read_float(localRecP->opus, _pcm, samples_needed * num_channels, NULL);
						
						if(samples_read == 0)
						{
							// guess we're at the end of the stream
							break;
						}
						else if(samples_read < 0)
						{
							result = imDecompressionError;
						}
						else
						{
							for(int c=0; c < localRecP->numChannels; c++)
							{
								for(int i=0; i < samples_read; i++)
								{
									audioRec7->buffer[swizzle[c]][pos + i] = _pcm[(i * num_channels) + c];
								}
							}
							
							samples_needed -= samples_read;
							pos += samples_read;
						}
					}
					
					free(pcm_buf);
				}
			}
		}
		else if(localRecP->fileType == FLAC_filetype && localRecP->flac != NULL)
		{
			try
			{
				//localRecP->flac->reset();
				
				assert(audioRec7->position >= 0); // not handling Premiere's continuous reads
				
				assert(localRecP->flac->get_channels() == localRecP->numChannels);
				
				
				long samples_needed = audioRec7->size;
				
				
				localRecP->flac->set_buffers(audioRec7->buffer, samples_needed, audioRec7->position);
				
				
				// Calling seek will cause flac to "write" some audio, of course!
				bool sought = localRecP->flac->seek_absolute(audioRec7->position);
				
				
				bool eof = false;
				
				size_t buffer_position = 0;
				
				if(sought)
				{
					do{
						size_t new_buffer_position = localRecP->flac->get_pos();
						
						int samples_read = (new_buffer_position - buffer_position);
						
						if(samples_read > 0)
						{
							samples_needed -= samples_read;
						}
						else
							eof = true;
							
						buffer_position = new_buffer_position;
						
						if(samples_needed > 0 && !eof)
						{
							bool processed = localRecP->flac->process_single();
							
							if(!processed)
								samples_needed = 0;
						}
							
					}while(samples_needed > 0 && !eof);
				}
				
				localRecP->flac->set_buffers(NULL, 0, 0); // don't trust libflac not to write at inopportune times
			}
			catch(...)
			{
				result = imDecompressionError;
			}
		}
	}
	
					
	stdParms->piSuites->memFuncs->unlockHandle(reinterpret_cast<char**>(ldataH));
	
	assert(result == malNoError);
	
	return result;
}
prMALError 
SDKGetInfo8(
	imStdParms			*stdParms, 
	imFileAccessRec8	*fileAccessInfo8, 
	imFileInfoRec8		*SDKFileInfo8)
{
	prMALError					result				= malNoError;


	SDKFileInfo8->hasDataRate						= kPrFalse;


	// private data
	assert(SDKFileInfo8->privatedata);
	ImporterLocalRec8H ldataH = reinterpret_cast<ImporterLocalRec8H>(SDKFileInfo8->privatedata);
	stdParms->piSuites->memFuncs->lockHandle(reinterpret_cast<char**>(ldataH));
	ImporterLocalRec8Ptr localRecP = reinterpret_cast<ImporterLocalRec8Ptr>( *ldataH );


	SDKFileInfo8->hasVideo = kPrFalse;
	SDKFileInfo8->hasAudio = kPrFalse;
	
	
	if(localRecP)
	{
		if(localRecP->fileType == Ogg_filetype && localRecP->vf != NULL)
		{
			OggVorbis_File &vf = *localRecP->vf;
		
			vorbis_info *info = ov_info(&vf, 0);
		
			// Audio information
			SDKFileInfo8->hasAudio				= kPrTrue;
			SDKFileInfo8->audInfo.numChannels	= info->channels;
			SDKFileInfo8->audInfo.sampleRate	= info->rate;
			SDKFileInfo8->audInfo.sampleType	= kPrAudioSampleType_Compressed;
													
			SDKFileInfo8->audDuration			= ov_pcm_total(&vf, 0);
		}
		else if(localRecP->fileType == Opus_filetype && localRecP->opus != NULL)
		{
			SDKFileInfo8->hasAudio				= kPrTrue;
			SDKFileInfo8->audInfo.numChannels	= op_channel_count(localRecP->opus, -1);
			SDKFileInfo8->audInfo.sampleRate	= 48000; // Ogg Opus always uses 48 kHz
			SDKFileInfo8->audInfo.sampleType	= kPrAudioSampleType_Compressed;
													
			SDKFileInfo8->audDuration			= op_pcm_total(localRecP->opus, -1);
		}
		else if(localRecP->fileType == FLAC_filetype && localRecP->flac != NULL)
		{
			try
			{
				SDKFileInfo8->hasAudio				= kPrTrue;
				SDKFileInfo8->audInfo.numChannels	= localRecP->flac->get_channels();
				SDKFileInfo8->audInfo.sampleRate	= localRecP->flac->get_sample_rate();
				
				int bitDepth = localRecP->flac->get_bits_per_sample();
				
				SDKFileInfo8->audInfo.sampleType	= bitDepth == 8 ? kPrAudioSampleType_8BitInt :
														bitDepth == 16 ? kPrAudioSampleType_16BitInt :
														bitDepth == 24 ? kPrAudioSampleType_24BitInt :
														bitDepth == 32 ? kPrAudioSampleType_32BitInt :
														bitDepth == 64 ? kPrAudioSampleType_64BitFloat :
														kPrAudioSampleType_Compressed;
														
				SDKFileInfo8->audDuration			= localRecP->flac->get_total_samples();
			}
			catch(...)
			{
				result = imBadFile;
			}
		}

		localRecP->audioSampleRate			= SDKFileInfo8->audInfo.sampleRate;
		localRecP->numChannels				= SDKFileInfo8->audInfo.numChannels;
		
		
		if(SDKFileInfo8->audInfo.numChannels > 2 && SDKFileInfo8->audInfo.numChannels != 6)
		{
			// Premiere can't handle anything but Mono, Stereo, and 5.1
			result = imUnsupportedAudioFormat;
		}
	}
		
	stdParms->piSuites->memFuncs->unlockHandle(reinterpret_cast<char**>(ldataH));

	return result;
}
bool CSoundFile::ReadOpusSample(SAMPLEINDEX sample, FileReader &file)
{
	file.Rewind();

#if defined(MPT_WITH_OPUSFILE)

	int rate = 0;
	int channels = 0;
	std::vector<int16> raw_sample_data;

	FileReader initial = file.GetChunk(65536); // 512 is recommended by libopusfile
	if(op_test(NULL, initial.GetRawData<unsigned char>(), initial.GetLength()) != 0)
	{
		return false;
	}

	OggOpusFile *of = op_open_memory(file.GetRawData<unsigned char>(), file.GetLength(), NULL);
	if(!of)
	{
		return false;
	}

	rate = 48000;
	channels = op_channel_count(of, -1);
	if(rate <= 0 || channels <= 0)
	{
		op_free(of);
		of = NULL;
		return false;
	}
	if(channels > 2 || op_link_count(of) != 1)
	{
		// We downmix multichannel to stereo as recommended by Opus specification in
		// case we are not able to handle > 2 channels.
		// We also decode chained files as stereo even if they start with a mono
		// stream, which simplifies handling of link boundaries for us.
		channels = 2;
	}

	std::vector<int16> decodeBuf(120 * 48000 / 1000); // 120ms (max Opus packet), 48kHz
	bool eof = false;
	while(!eof)
	{
		int framesRead = 0;
		if(channels == 2)
		{
			framesRead = op_read_stereo(of, &(decodeBuf[0]), static_cast<int>(decodeBuf.size()));
		} else if(channels == 1)
		{
			framesRead = op_read(of, &(decodeBuf[0]), static_cast<int>(decodeBuf.size()), NULL);
		}
		if(framesRead > 0)
		{
			raw_sample_data.insert(raw_sample_data.end(), decodeBuf.begin(), decodeBuf.begin() + (framesRead * channels));
		} else if(framesRead == 0)
		{
			eof = true;
		} else if(framesRead == OP_HOLE)
		{
			// continue
		} else
		{
			// other errors are fatal, stop decoding
			eof = true;
		}
	}

	op_free(of);
	of = NULL;

	if(raw_sample_data.empty())
	{
		return false;
	}

	DestroySampleThreadsafe(sample);
	strcpy(m_szNames[sample], "");
	Samples[sample].Initialize();
	Samples[sample].nC5Speed = rate;
	Samples[sample].nLength = raw_sample_data.size() / channels;

	Samples[sample].uFlags.set(CHN_16BIT);
	Samples[sample].uFlags.set(CHN_STEREO, channels == 2);
	Samples[sample].AllocateSample();

	std::copy(raw_sample_data.begin(), raw_sample_data.end(), Samples[sample].pSample16);

	Samples[sample].Convert(MOD_TYPE_IT, GetType());
	Samples[sample].PrecomputeLoops(*this, false);

	return Samples[sample].pSample != nullptr;

#else // !MPT_WITH_OPUSFILE

	MPT_UNREFERENCED_PARAMETER(sample);
	MPT_UNREFERENCED_PARAMETER(file);

	return false;

#endif // MPT_WITH_OPUSFILE

}
Exemple #11
0
Result SoundSourceOpus::parseTrackMetadataAndCoverArt(
        TrackMetadata* pTrackMetadata,
        QImage* pCoverArt) const {
    if (OK == SoundSource::parseTrackMetadataAndCoverArt(
            pTrackMetadata, pCoverArt)) {
        // Done if the default implementation in the base class
        // supports Opus files.
        return OK;
    }

    // Beginning with version 1.9.0 TagLib supports the Opus format.
    // Until this becomes the minimum version required by Mixxx tags
    // in .opus files must also be parsed using opusfile. The following
    // code should removed as soon as it is no longer needed!
    //
    // NOTE(uklotzde): The following code has been found in SoundSourceOpus
    // and will not be improved. We are aware of its shortcomings like
    // the lack of proper error handling.

    // 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 error = 0;
    OggOpusFileOwner l_ptrOpusFile(
            op_open_file(qBAFilename.constData(), &error));

    int i = 0;
    const OpusTags *l_ptrOpusTags = op_tags(l_ptrOpusFile, -1);

    pTrackMetadata->setChannels(op_channel_count(l_ptrOpusFile, -1));
    pTrackMetadata->setSampleRate(Mixxx::SoundSourceOpus::kSamplingRate);
    pTrackMetadata->setBitrate(op_bitrate(l_ptrOpusFile, -1) / 1000);
    pTrackMetadata->setDuration(
            op_pcm_total(l_ptrOpusFile, -1) / pTrackMetadata->getSampleRate());

    bool hasDate = false;
    for (i = 0; i < l_ptrOpusTags->comments; ++i) {
        QString l_SWholeTag = QString(l_ptrOpusTags->user_comments[i]);
        QString l_STag = l_SWholeTag.left(l_SWholeTag.indexOf("="));
        QString l_SPayload = l_SWholeTag.right((l_SWholeTag.length() - l_SWholeTag.indexOf("=")) - 1);

        if (!l_STag.compare("ARTIST")) {
            pTrackMetadata->setArtist(l_SPayload);
        } else if (!l_STag.compare("ALBUM")) {
            pTrackMetadata->setAlbum(l_SPayload);
        } else if (!l_STag.compare("BPM")) {
            pTrackMetadata->setBpm(l_SPayload.toFloat());
        } else if (!l_STag.compare("DATE")) {
            // Prefer "DATE" over "YEAR"
            pTrackMetadata->setYear(l_SPayload.trimmed());
            // Avoid to overwrite "DATE" with "YEAR"
            hasDate |= !pTrackMetadata->getYear().isEmpty();
        } else if (!hasDate && !l_STag.compare("YEAR")) {
            pTrackMetadata->setYear(l_SPayload.trimmed());
        } else if (!l_STag.compare("GENRE")) {
            pTrackMetadata->setGenre(l_SPayload);
        } else if (!l_STag.compare("TRACKNUMBER")) {
            pTrackMetadata->setTrackNumber(l_SPayload);
        } else if (!l_STag.compare("COMPOSER")) {
            pTrackMetadata->setComposer(l_SPayload);
        } else if (!l_STag.compare("ALBUMARTIST")) {
            pTrackMetadata->setAlbumArtist(l_SPayload);
        } else if (!l_STag.compare("TITLE")) {
            pTrackMetadata->setTitle(l_SPayload);
        } else if (!l_STag.compare("REPLAYGAIN_TRACK_GAIN")) {
            bool trackGainRatioValid = false;
            double trackGainRatio = ReplayGain::parseGain2Ratio(l_SPayload, &trackGainRatioValid);
            if (trackGainRatioValid) {
                ReplayGain trackGain(pTrackMetadata->getReplayGain());
                trackGain.setRatio(trackGainRatio);
                pTrackMetadata->setReplayGain(trackGain);
            }
        }

        // This is left fot debug reasons!!
        //qDebug() << "Comment" << i << l_ptrOpusTags->comment_lengths[i] <<
        //" (" << l_ptrOpusTags->user_comments[i] << ")" << l_STag << "*" << l_SPayload;
    }

    return OK;
}