Exemplo n.º 1
0
/*
====================
OGG_LoadVorbisFile

Load an Ogg Vorbis file into memory
====================
*/
qboolean OGG_LoadVorbisFile(const char *filename, sfx_t *sfx)
{
	unsigned char *data;
	fs_offset_t filesize;
	ov_decode_t ov_decode;
	OggVorbis_File vf;
	vorbis_info *vi;
	vorbis_comment *vc;
	double peak, gaindb;

#ifndef LINK_TO_LIBVORBIS
	if (!vf_dll)
		return false;
#endif

	// Return if already loaded
	if (sfx->fetcher != NULL)
		return true;

	// Load the file completely
	data = FS_LoadFile(filename, snd_mempool, false, &filesize);
	if (data == NULL)
		return false;

	if (developer_loading.integer >= 2)
		Con_Printf("Loading Ogg Vorbis file \"%s\"\n", filename);

	// Open it with the VorbisFile API
	ov_decode.buffer = data;
	ov_decode.ind = 0;
	ov_decode.buffsize = filesize;
	if (qov_open_callbacks(&ov_decode, &vf, NULL, 0, callbacks) < 0)
	{
		Con_Printf("error while opening Ogg Vorbis file \"%s\"\n", filename);
		Mem_Free(data);
		return false;
	}

	// Get the stream information
	vi = qov_info(&vf, -1);
	if (vi->channels < 1 || vi->channels > 2)
	{
		Con_Printf("%s has an unsupported number of channels (%i)\n",
					sfx->name, vi->channels);
		qov_clear (&vf);
		Mem_Free(data);
		return false;
	}

	sfx->format.speed = vi->rate;
	sfx->format.channels = vi->channels;
	sfx->format.width = 2;  // We always work with 16 bits samples

	sfx->total_length = qov_pcm_total(&vf, -1);

	if (snd_streaming.integer && (snd_streaming.integer >= 2 || sfx->total_length > max(sizeof(ogg_stream_perchannel_t), snd_streaming_length.value * sfx->format.speed)))
	{
		// large sounds use the OGG fetcher to decode the file on demand (but the entire file is held in memory)
		ogg_stream_persfx_t* per_sfx;
		if (developer_loading.integer >= 2)
			Con_Printf("Ogg sound file \"%s\" will be streamed\n", filename);
		per_sfx = (ogg_stream_persfx_t *)Mem_Alloc(snd_mempool, sizeof(*per_sfx));
		sfx->memsize += sizeof (*per_sfx);
		per_sfx->file = data;
		per_sfx->filesize = filesize;
		sfx->memsize += filesize;
		sfx->fetcher_data = per_sfx;
		sfx->fetcher = &ogg_fetcher;
		sfx->flags |= SFXFLAG_STREAMED;
		vc = qov_comment(&vf, -1);
		OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, sfx->total_length, &peak, &gaindb);
		qov_clear(&vf);
	}
	else
	{
		// small sounds are entirely loaded and use the PCM fetcher
		char *buff;
		ogg_int64_t len;
		ogg_int64_t done;
		int bs;
		long ret;
		if (developer_loading.integer >= 2)
			Con_Printf ("Ogg sound file \"%s\" will be cached\n", filename);
		len = sfx->total_length * sfx->format.channels * sfx->format.width;
		sfx->flags &= ~SFXFLAG_STREAMED;
		sfx->memsize += len;
		sfx->fetcher = &wav_fetcher;
		sfx->fetcher_data = Mem_Alloc(snd_mempool, (size_t)len);
		buff = (char *)sfx->fetcher_data;
		done = 0;
		bs = 0;
		while ((ret = qov_read(&vf, &buff[done], (int)(len - done), mem_bigendian, 2, 1, &bs)) > 0)
			done += ret;
		vc = qov_comment(&vf, -1);
		OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, sfx->total_length, &peak, &gaindb);
		qov_clear(&vf);
		Mem_Free(data);
	}

	if(peak)
	{
		sfx->volume_mult = min(1.0f / peak, exp(gaindb * 0.05f * log(10.0f)));
		sfx->volume_peak = peak;
		if (developer_loading.integer >= 2)
			Con_Printf ("Ogg sound file \"%s\" uses ReplayGain (gain %f, peak %f)\n", filename, sfx->volume_mult, sfx->volume_peak);
	}
	else if(gaindb != 0)
	{
		sfx->volume_mult = min(1.0f / peak, exp(gaindb * 0.05f * log(10.0f)));
		sfx->volume_peak = 1.0; // if peak is not defined, we won't trust it
		if (developer_loading.integer >= 2)
			Con_Printf ("Ogg sound file \"%s\" uses ReplayGain (gain %f, peak not defined and assumed to be %f)\n", filename, sfx->volume_mult, sfx->volume_peak);
	}

	return true;
}
Exemplo n.º 2
0
sfxcache_t *S_LoadSound(sfx_t *s)
{
	char namebuffer[MAX_OSPATH];
	char extionless[MAX_OSPATH];
	sfxcache_t *sc = NULL;
	int eof = 0;
	int current_section;
	vfsfile_t *f;
	OggVorbis_File oggfile;
	vorbis_info *ogginfo;
	ov_callbacks ovc = {
		vorbis_callback_read,
		vorbis_callback_seek,
		vorbis_callback_close,
		vorbis_callback_tell
	};
	static char pcmbuff[4096];
	
	//unsigned char *data;
	wavinfo_t info;
	int len;
	//int filesize;

	// see if still in memory
	if ((sc = (sfxcache_t *) Cache_Check (&s->cache)))
		return sc;

	if (!vorbis_CheckActive())
		vorbis_LoadLibrary();

	// load it in
	COM_StripExtension(s->name, extionless);
	snprintf (namebuffer, sizeof (namebuffer), "sound/%s.ogg", extionless);

/*	if (!(data = FS_LoadTempFile (namebuffer, &filesize))) {
		Com_Printf ("Couldn't load %s\n", namebuffer);
		return NULL;
	}*/

	if (!(f = FS_OpenVFS(namebuffer, "rb", FS_ANY))) {
		Com_Printf("Couldn't load %s\n", namebuffer);
		return NULL;
	}

	if (qov_open_callbacks(f, &oggfile, NULL, 0, ovc)) {
		Com_Printf("Invalid sound file %s\n", namebuffer);
		VFS_CLOSE(f);
		return NULL;
	}
	if (!(ogginfo = qov_info(&oggfile,-1))) {
		Com_Printf("Unable to retrieve information for %s\n", namebuffer);
		goto fail;
	}

	/* Print some information */
	fprintf(stderr, "%s\n", namebuffer);
	{
		char **ptr = qov_comment(&oggfile,-1)->user_comments;
		while(*ptr){
			fprintf(stderr,"%s\n",*ptr);
			++ptr;
		}
		fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",
				ogginfo->channels, ogginfo->rate);
		fprintf(stderr,"\nDecoded length: %ld samples\n",
				(long) qov_pcm_total(&oggfile,-1));
		fprintf(stderr,"Encoded by: %s\n\n", qov_comment(&oggfile,-1)->vendor);
	}

	info.rate = ogginfo->rate;			// Frequency rate
	info.width = 1;						// 8 bit samples
	info.channels = ogginfo->channels;	// 1 == mono, 2 == stereo
	info.loopstart = -1;				// NOOO idea...
	info.samples = qov_pcm_total(&oggfile,-1);	// Total samples
	info.dataofs = 0;					// offset

	
	//FMod_CheckModel(namebuffer, data, filesize);

	//info = GetWavinfo (s->name, data, filesize);

	// Stereo sounds are allowed (intended for music)
	if (info.channels < 1 || info.channels > 2) {
		Com_Printf("%s has an unsupported number of channels (%i)\n",s->name, info.channels);
		return NULL;
	}

	len = (int) ((double) info.samples * (double) shm->format.speed / (double) info.rate);
	len = len * info.width * info.channels;

	if (!(sc = (sfxcache_t *) Cache_Alloc (&s->cache, len + sizeof(sfxcache_t), s->name)))
		return NULL;

	/* Read the whole Ogg Vorbis file in */
	byte *output = sc->data;
	while (!eof) {
		// 0 == little endian, 1 = big endian
		// 1 == 8 bit samples, 2 = 16 bit samples
		// 1 == signed samples
		long ret = qov_read(&oggfile, pcmbuff, sizeof(pcmbuff), 
				0, info.width, 1, &current_section);
		if (ret == 0) {
			eof = 1;
		} else if (ret < 0) {
			/* error in the stream. Not a problem, just reporting it in
			 * case we (the app) cares. In this case, we don't. */
		} else {
			/* we don't bother dealing with sample rate changes, etc, but
			 * you'll have to */
			memcpy(output, pcmbuff, ret);
			output += ret;
		}
	}
	qov_clear(&oggfile);

	sc->total_length = (unsigned int) info.samples;
	sc->format.speed = info.rate;
	sc->format.width = info.width;
	sc->format.channels = info.channels;
	if (info.loopstart < 0)
		sc->loopstart = -1;
	else
		sc->loopstart = (int)((double)info.loopstart * (double)shm->format.speed / (double)sc->format.speed);

//	ResampleSfx (s, data + info.dataofs, info.samples, &sc->format, sc->data);
	return sc;

fail:
	qov_clear(&oggfile); // Only goto fail if ov_open* succeded
	if (f) {
		VFS_CLOSE(f);
	}
	return NULL;
}