Example #1
0
OggOpusReader::OggOpusReader(Stream *fp) : fw(fp)
{
 OpusFileCallbacks cb;
 int error = 0;

 memset(&cb, 0, sizeof(cb));
 cb.read_func = iop_read_func;
 cb.seek_func = iop_seek_func;
 cb.close_func = iop_close_func;
 cb.tell_func = iop_tell_func;

 fp->seek(0, SEEK_SET);

 if(!(opfile = op_open_callbacks((void*)fp, &cb, NULL, 0, &error)))
 {
  switch(error)
  {
   default:
	throw MDFN_Error(0, _("opusfile: error code: %d(%s)", error, op_errstring(error)));
	break;

   case OP_ENOTFORMAT:
	throw(0);
	break;
  }
 }
}
Example #2
0
Error AudioStreamPlaybackOpus::set_file(const String &p_file) {
	file=p_file;
	stream_valid=false;
	Error err;
	f=FileAccess::open(file,FileAccess::READ,&err);

	if (err) {
		ERR_FAIL_COND_V( err, err );
	}

	int _err;

	opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&_err);

	switch (_err) {
		case OP_EREAD: { // - Can't read the file.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_FILE_CANT_READ );
		} break;
		case OP_EVERSION: // - Unrecognized version number.
		case OP_ENOTFORMAT: // - Stream is not Opus data.
		case OP_EIMPL : { // - Stream used non-implemented feature.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_FILE_UNRECOGNIZED );
		} break;
		case OP_EBADLINK: // - Failed to find old data after seeking.
		case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
		case OP_EBADHEADER: { // - Invalid or mising Opus bitstream header.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_FILE_CORRUPT );
		} break;
		case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_BUG );
		} break;
	}

	const OpusHead *oinfo = op_head(opus_file,-1);

	stream_channels=oinfo->channel_count;
	pre_skip=oinfo->pre_skip;
	frames_mixed=pre_skip;
	ogg_int64_t len = op_pcm_total(opus_file,-1);
	if(len < 0) {
		length = 0;
	} else {
		length=(len/osrate);
	}

	op_free(opus_file);
	memdelete(f);
	f=NULL;
	stream_valid=true;


	return OK;
}
Example #3
0
int AudioStreamPlaybackOpus::mix(int16_t* p_bufer,int p_frames) {
	if (!playing)
		return 0;

	int total=p_frames;

	while (true) {

		int todo = p_frames;

		if (todo==0 || todo<MIN_MIX) {
			break;
		}

		int ret=op_read(opus_file,(opus_int16*)p_bufer,todo*stream_channels,&current_section);
		if (ret<0) {
			playing = false;
			ERR_EXPLAIN("Error reading Opus File: "+file);
			ERR_BREAK(ret<0);
		} else if (ret==0) { // end of song, reload?
			op_free(opus_file);

			_close_file();

			f=FileAccess::open(file,FileAccess::READ);

			int errv = 0;
			opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&errv);
			if (errv!=0) {
				playing=false;
				break; // :(
			}

			if (!has_loop()) {
				playing=false;
				repeats=1;
				break;
			}

			if (loop_restart_time) {
				bool ok = op_pcm_seek(opus_file, (loop_restart_time*osrate)+pre_skip)==0;
				if (!ok) {
					playing=false;
					ERR_PRINT("loop restart time rejected")
				}

				frames_mixed=(loop_restart_time*osrate)+pre_skip;
			} else {
Example #4
0
bool OpusDecoder::Open(FILE* file) {
	finished = false;

	int res;
	OpusFileCallbacks callbacks = {custom_read, custom_seek, custom_tell, custom_close};

	oof = op_open_callbacks(file, &callbacks, nullptr, 0, &res);
	if (res != 0) {
		error_message = "Opus: Error reading file";
		op_free(oof);
		fclose(file);
		return false;
	}

	return true;
}
Example #5
0
Error AudioStreamPlaybackOpus::_load_stream() {

	ERR_FAIL_COND_V(!stream_valid,ERR_UNCONFIGURED);

	_clear_stream();
	if (file=="")
		return ERR_INVALID_DATA;

	Error err;
	f=FileAccess::open(file,FileAccess::READ,&err);

	if (err) {
		ERR_FAIL_COND_V( err, err );
	}

	int _err = 0;

	opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&_err);

	switch (_err) {
		case OP_EREAD: { // - Can't read the file.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_FILE_CANT_READ );
		} break;
		case OP_EVERSION: // - Unrecognized version number.
		case OP_ENOTFORMAT: // - Stream is not Opus data.
		case OP_EIMPL : { // - Stream used non-implemented feature.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_FILE_UNRECOGNIZED );
		} break;
		case OP_EBADLINK: // - Failed to find old data after seeking.
		case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
		case OP_EBADHEADER: { // - Invalid or mising Opus bitstream header.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_FILE_CORRUPT );
		} break;
		case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
			memdelete(f); f=NULL;
			ERR_FAIL_V( ERR_BUG );
		} break;
	}
	repeats=0;
	stream_loaded=true;


	return OK;
}
prMALError 
SDKOpenFile8(
	imStdParms		*stdParms, 
	imFileRef		*SDKfileRef, 
	imFileOpenRec8	*SDKfileOpenRec8)
{
	prMALError			result = malNoError;

	ImporterLocalRec8H	localRecH = NULL;
	ImporterLocalRec8Ptr localRecP = NULL;

	if(SDKfileOpenRec8->privatedata)
	{
		localRecH = (ImporterLocalRec8H)SDKfileOpenRec8->privatedata;

		stdParms->piSuites->memFuncs->lockHandle(reinterpret_cast<char**>(localRecH));

		localRecP = reinterpret_cast<ImporterLocalRec8Ptr>( *localRecH );
	}
	else
	{
		localRecH = (ImporterLocalRec8H)stdParms->piSuites->memFuncs->newHandle(sizeof(ImporterLocalRec8));
		SDKfileOpenRec8->privatedata = (PrivateDataPtr)localRecH;

		stdParms->piSuites->memFuncs->lockHandle(reinterpret_cast<char**>(localRecH));

		localRecP = reinterpret_cast<ImporterLocalRec8Ptr>( *localRecH );
		
		localRecP->vf = NULL;
		localRecP->opus = NULL;
		localRecP->flac = NULL;
		
		localRecP->importerID = SDKfileOpenRec8->inImporterID;
		localRecP->fileType = SDKfileOpenRec8->fileinfo.filetype;
	}


	SDKfileOpenRec8->fileinfo.fileref = *SDKfileRef = reinterpret_cast<imFileRef>(imInvalidHandleValue);


	if(localRecP)
	{
		const prUTF16Char *path = SDKfileOpenRec8->fileinfo.filepath;
	
	#ifdef PRWIN_ENV
		HANDLE fileH = CreateFileW(path,
									GENERIC_READ,
									FILE_SHARE_READ,
									NULL,
									OPEN_EXISTING,
									FILE_ATTRIBUTE_NORMAL,
									NULL);
									
		if(fileH != imInvalidHandleValue)
		{
			SDKfileOpenRec8->fileinfo.fileref = *SDKfileRef = fileH;
		}
		else
			result = imFileOpenFailed;
	#else
		FSIORefNum refNum = CAST_REFNUM(imInvalidHandleValue);
				
		CFStringRef filePathCFSR = CFStringCreateWithCharacters(NULL, path, prUTF16CharLength(path));
													
		CFURLRef filePathURL = CFURLCreateWithFileSystemPath(NULL, filePathCFSR, kCFURLPOSIXPathStyle, false);
		
		if(filePathURL != NULL)
		{
			FSRef fileRef;
			Boolean success = CFURLGetFSRef(filePathURL, &fileRef);
			
			if(success)
			{
				HFSUniStr255 dataForkName;
				FSGetDataForkName(&dataForkName);
			
				OSErr err = FSOpenFork(	&fileRef,
										dataForkName.length,
										dataForkName.unicode,
										fsRdWrPerm,
										&refNum);
			}
										
			CFRelease(filePathURL);
		}
									
		CFRelease(filePathCFSR);

		if(CAST_FILEREF(refNum) != imInvalidHandleValue)
		{
			SDKfileOpenRec8->fileinfo.fileref = *SDKfileRef = CAST_FILEREF(refNum);
		}
		else
			result = imFileOpenFailed;
	#endif

	}

	if(result == malNoError)
	{
		localRecP->fileType = SDKfileOpenRec8->fileinfo.filetype;
		
		assert(0 == ogg_tell_func(static_cast<void *>(*SDKfileRef)));
			
		if(localRecP->fileType == Ogg_filetype)
		{
			localRecP->vf = new OggVorbis_File;
		
			OggVorbis_File &vf = *localRecP->vf;
			
			int ogg_err = ov_open_callbacks(static_cast<void *>(*SDKfileRef), &vf, NULL, 0, g_ov_callbacks);
			
			if(ogg_err == OV_OK)
			{
				if( ov_streams(&vf) == 0 )
				{
					result = imFileHasNoImportableStreams;
					
					ov_clear(&vf);
				}
				else if( !ov_seekable(&vf) )
				{
					result = imBadFile;
				}
			}
			else
				result = imBadHeader;
		}
		else if(localRecP->fileType == Opus_filetype)
		{
			int _error = 0;
			
			localRecP->opus = op_open_callbacks(static_cast<void *>(*SDKfileRef), &g_opusfile_callbacks, NULL, 0, &_error);
			
			if(localRecP->opus != NULL && _error == 0)
			{
				assert(op_link_count(localRecP->opus) == 1); // we're not really handling multi-link scenarios
			}
			else
				result = imBadHeader;
		}
		else if(localRecP->fileType == FLAC_filetype)
		{
			try
			{
				localRecP->flac = new OurDecoder(*SDKfileRef);
				
				localRecP->flac->set_md5_checking(true);
				
				FLAC__StreamDecoderInitStatus init_status = localRecP->flac->init();
				
				assert(init_status == FLAC__STREAM_DECODER_INIT_STATUS_OK && localRecP->flac->is_valid());
				
				bool ok = localRecP->flac->process_until_end_of_metadata();
				
				assert(ok);
			}
			catch(...)
			{
				result = imBadHeader;
			}
		}
	}
	
	// close file and delete private data if we got a bad file
	if(result != malNoError)
	{
		if(SDKfileOpenRec8->privatedata)
		{
			stdParms->piSuites->memFuncs->disposeHandle(reinterpret_cast<PrMemoryHandle>(SDKfileOpenRec8->privatedata));
			SDKfileOpenRec8->privatedata = NULL;
		}
	}
	else
	{
		stdParms->piSuites->memFuncs->unlockHandle(reinterpret_cast<char**>(SDKfileOpenRec8->privatedata));
	}

	return result;
}
/*
=================
S_OggOpus_CodecOpenStream
=================
*/
snd_stream_t *S_OggOpus_CodecOpenStream( const char *filename )
{
	snd_stream_t *stream;

	// Opus codec control structure
	OggOpusFile *of;

	// some variables used to get informations about the file
	const OpusHead *opusInfo;
	ogg_int64_t numSamples;

	// check if input is valid
	if ( !filename )
	{
		return NULL;
	}

	// Open the stream
	stream = S_CodecUtilOpen( filename, &opus_codec );

	if ( !stream )
	{
		return NULL;
	}

	// open the codec with our callbacks and stream as the generic pointer
	of = op_open_callbacks( stream, &S_OggOpus_Callbacks, NULL, 0, NULL );

	if ( !of )
	{
		S_CodecUtilClose( &stream );

		return NULL;
	}

	// the stream must be seekable
	if ( !op_seekable( of ) )
	{
		op_free( of );

		S_CodecUtilClose( &stream );

		return NULL;
	}

	// get the info about channels and rate
	opusInfo = op_head( of, -1 );

	if ( !opusInfo )
	{
		op_free( of );

		S_CodecUtilClose( &stream );

		return NULL;
	}

	if ( opusInfo->stream_count != 1 )
	{
		op_free( of );

		S_CodecUtilClose( &stream );

		Com_Printf( "Only Ogg Opus files with one stream are support\n" );
		return NULL;
	}

	if ( opusInfo->channel_count != 1 && opusInfo->channel_count != 2 )
	{
		op_free( of );

		S_CodecUtilClose( &stream );

		Com_Printf( "Only mono and stereo Ogg Opus files are supported\n" );
		return NULL;
	}

	// get the number of sample-frames in the file
	numSamples = op_pcm_total( of, -1 );

	// fill in the info-structure in the stream
	stream->info.rate = 48000;
	stream->info.width = OPUS_SAMPLEWIDTH;
	stream->info.channels = opusInfo->channel_count;
	stream->info.samples = numSamples;
	stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
	stream->info.dataofs = 0;

	// We use stream->pos for the file pointer in the compressed ogg file
	stream->pos = 0;

	// We use the generic pointer in stream for the opus codec control structure
	stream->ptr = of;

	return stream;
}
Example #8
0
opus_file_t open_opus_file(const util::Path &path) {
	if (not path.is_file()) {
		throw audio::Error{
			ERR << "Audio file not found: " << path
		};
	}

	opus_file_t op_file;
	int op_err = 0;

	//asm("int $3");

	// check if the file can be opened directly
	auto native_path = path.resolve_native_path();
	if (false && native_path.size() > 0) {

		op_file.handle = {
			op_open_file(native_path.c_str(), &op_err),
			opus_deleter
		};
	}
	else {
		// open the file and move the handle to the heap
		op_file.file = std::make_unique<util::File>();
		*op_file.file = path.open_r();

		op_file.handle = {
			op_open_callbacks(op_file.file.get(), &opus_access_funcs,
			                  nullptr, 0, &op_err),
			opus_deleter
		};
	}

	if (op_err != 0) {

		const char *reason;

		switch (op_err) {
		case OP_EREAD:
			reason = "read/seek/tell failed or data has changed"; break;
		case OP_EFAULT:
			reason = "opus failed to allocate memory "
			         "or something else bad happened internally"; break;
		case OP_EIMPL:
			reason = "Stream used an unsupported feature"; break;
		case OP_EINVAL:
			reason = "seek() worked, but tell() did not, "
			         "or initial_bytes != start seek pos"; break;
		case OP_ENOTFORMAT:
			reason = "Data didn't contain opus stream"; break;
		case OP_EBADHEADER:
			reason = "Header packet was invalid or missing"; break;
		case OP_EVERSION:
			reason = "ID header has unrecognized version"; break;
		case OP_EBADLINK:
			reason = "Data we already saw before seeking not found"; break;
		case OP_EBADTIMESTAMP:
			reason = "Validity check for first/last timestamp failed"; break;

		default:
			reason = "Unknown other error in opusfile"; break;
		}

		throw audio::Error{
			ERR
			<< "Could not open opus file: "
			<< path << " = '" << native_path << "': "
			<< reason
		};
	}
	return op_file;
}
Example #9
0
static gboolean
xmms_opus_init (xmms_xform_t *xform)
{
	xmms_opus_data_t *data;
	gint ret;
	guint playtime;
	const gchar *metakey;

	g_return_val_if_fail (xform, FALSE);

	data = g_new0 (xmms_opus_data_t, 1),

	data->callbacks.read = opus_callback_read;
	data->callbacks.close = opus_callback_close;
	data->callbacks.tell = opus_callback_tell;
	data->callbacks.seek = opus_callback_seek;

	data->current = -1;

	xmms_xform_private_data_set (xform, data);

	data->opusfile = op_open_callbacks (xform, &data->callbacks, NULL, 0,
	                         &ret);
	if (ret) {
		return FALSE;
	}

	playtime = op_pcm_total (data->opusfile, -1) / 48000;

	if (playtime != OP_EINVAL) {
		gint filesize;

		metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE;
		if (xmms_xform_metadata_get_int (xform, metakey, &filesize)) {
			xmms_opus_set_duration (xform, playtime);
		}
	}

	xmms_opus_read_metadata (xform, data);

	/*
	xmms_xform_outdata_type_add (xform,
	                             XMMS_STREAM_TYPE_MIMETYPE,
	                             "audio/pcm",
	                             XMMS_STREAM_TYPE_FMT_FORMAT,
	                             XMMS_SAMPLE_FORMAT_FLOAT,
	                             XMMS_STREAM_TYPE_FMT_CHANNELS,
	                             data->channels,
	                             XMMS_STREAM_TYPE_FMT_SAMPLERATE,
	                             48000,
	                             XMMS_STREAM_TYPE_END);
	*/

	xmms_xform_outdata_type_add (xform,
	                             XMMS_STREAM_TYPE_MIMETYPE,
	                             "audio/pcm",
	                             XMMS_STREAM_TYPE_FMT_FORMAT,
	                             XMMS_SAMPLE_FORMAT_S16,
	                             XMMS_STREAM_TYPE_FMT_CHANNELS,
	                             data->channels,
	                             XMMS_STREAM_TYPE_FMT_SAMPLERATE,
	                             48000,
	                             XMMS_STREAM_TYPE_END);

	return TRUE;
}
Example #10
0
AudioData LoadOpusCodec(std::string filename)
{
	std::string audioFile;
	try
	{
		audioFile = FS::PakPath::ReadFile(filename);
	}
	catch (std::system_error& err)
	{
		audioLogs.Warn("Failed to open %s: %s", filename, err.what());
		return AudioData();
	}

	OpusDataSource dataSource = {&audioFile, 0};
	OggOpusFile* opusFile = op_open_callbacks(&dataSource, &Opus_Callbacks, nullptr, 0, nullptr);

	if (!opusFile) {
		audioLogs.Warn("Error while reading %s", filename);
		return AudioData();
	}

	const OpusHead* opusInfo = op_head(opusFile, -1);

	if (!opusInfo) {
		op_free(opusFile);
		audioLogs.Warn("Could not read OpusHead in %s", filename);
		return AudioData();
	}

	if (opusInfo->stream_count != 1) {
		op_free(opusFile);
		audioLogs.Warn("Only one stream is supported in Opus files: %s", filename);
		return AudioData();
	}

	if (opusInfo->channel_count != 1 && opusInfo->channel_count != 2) {
		op_free(opusFile);
		audioLogs.Warn("Only mono and stereo Opus files are supported: %s", filename);
		return AudioData();
	}

	const int sampleWidth = 2;

	int sampleRate = 48000;
	int numberOfChannels = opusInfo->channel_count;

	// The buffer is big enough to hold 120ms worth of samples per channel
	opus_int16* buffer = new opus_int16[numberOfChannels * 5760];
	int samplesPerChannelRead = 0;

	std::vector<opus_int16> samples;

	while ((samplesPerChannelRead =
	            op_read(opusFile, buffer, sampleWidth * numberOfChannels * 5760, nullptr)) > 0) {
		std::copy_n(buffer, samplesPerChannelRead * numberOfChannels, std::back_inserter(samples));
	}

	op_free(opusFile);

	char* rawSamples = new char[sampleWidth * samples.size()];
	std::copy_n(reinterpret_cast<char*>(samples.data()), sampleWidth * samples.size(), rawSamples);

	return AudioData(sampleRate, sampleWidth, numberOfChannels, samples.size() * sampleWidth,
	                 rawSamples);
}
Example #11
0
static OggOpusFile *
opus_file_open(DB_FILE *fp)
{
    int res = 0;
    return op_open_callbacks(fp, &opcb, NULL, 0, &res);
}
Example #12
0
static qboolean S_OPUS_CodecOpenStream (snd_stream_t *stream)
{
	OggOpusFile *opFile;
	const OpusHead *op_info;
	long numstreams;
	int res;

	opFile = op_open_callbacks(&stream->fh, &opc_qfs, NULL, 0, &res);
	if (!opFile)
	{
		Con_Printf("%s is not a valid Opus file (error %i).\n",
				stream->name, res);
		goto _fail;
	}

	stream->priv = opFile;

	if (!op_seekable(opFile))
	{
		Con_Printf("Opus stream %s not seekable.\n", stream->name);
		goto _fail;
	}

	op_info = op_head(opFile, -1);
	if (!op_info)
	{
		Con_Printf("Unable to get stream information for %s.\n", stream->name);
		goto _fail;
	}

	/* FIXME: handle section changes */
	numstreams = op_info->stream_count;
	if (numstreams != 1)
	{
		Con_Printf("More than one (%ld) stream in %s\n",
					(long)op_info->stream_count, stream->name);
		goto _fail;
	}

	if (op_info->channel_count != 1 && op_info->channel_count != 2)
	{
		Con_Printf("Unsupported number of channels %d in %s\n",
					op_info->channel_count, stream->name);
		goto _fail;
	}

	/* All Opus audio is coded at 48 kHz, and should also be decoded
	 * at 48 kHz for playback: info->input_sample_rate only tells us
	 * the sampling rate of the original input before opus encoding.
	 * S_RawSamples() shall already downsample this, as necessary.  */
	stream->info.rate = 48000;
	stream->info.channels = op_info->channel_count;
	/* op_read() yields 16-bit output using native endian ordering: */
	stream->info.bits = 16;
	stream->info.width = 2;

	return true;
_fail:
	if (opFile)
		op_free(opFile);
	return false;
}