XAudio2 and OGG as resource

This topic is 2329 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hola,

I try to write a sound engine for a non commercial project. May goal is to load ogg vorbis sounds to the RAM and put them into a buffer if the sounds are needed. I found a great tutorial from the beast about XAudio2 and OGG that can be found here.
The difference of my sounds and the background sounds of the beast is that i want to read in the whole sound (short sounds). Now my problem: How do I find out the size of the decoded OGG file? I tried

*m_vorbisFile->pcmlengths;

this one gives me a pointer to a 64bit integer, which i can not use to initialize a buffer. when i cast it to a 32bit integer i get a warning that there is a possible loss of data ( of course ).
My code is prototyped and i will change the design as soon as I resolved the Problem.

#ifndef SOUNDSOURCE2D_H_INCLUDED#define SOUNDSOURCE2D_H_INCLUDED#include <Windows.h>//forward decalrationsstruct OggVorbis_File;//helper macros#ifndef SAFE_DELETE#define SAFE_DELETE(p) {if(p) { delete (p); (p) = NULL; } }#endif#ifndef SAFE_DELETE_ARRAY#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }#endif#ifndef SAFE_RELEASE#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }#endifclass SoundSource2D{//private:	OggVorbis_File*		m_vorbisFile;	WAVEFORMATEX*		m_soundFormat;//public:	SoundSource2D(const char* b_sound);	~SoundSource2D();	};#endif

the cpp file:
#pragma hdrstop#include "SoundSource2D.h"#include <vorbisfile.h>//Constructor and DestructorSoundSource2D::SoundSource2D(const char* b_sound) :	m_vorbisFile(NULL),													m_soundFormat(NULL){		FILE *file;	errno_t errMsg;		//open file for reading	if ((errMsg  = fopen_s( &file, b_sound, "rb" )) != 0)	{				MessageBoxA(NULL,"Sound konnte nicht geladen werden" , "Error loading Sound", MB_OK | MB_ICONERROR);		return;	}		//getting infos from file	if (ov_open_callbacks(file, m_vorbisFile, NULL, 0, OV_CALLBACKS_DEFAULT) < 0)	{		fclose(file);		return;	}	vorbis_info* vInfo = ov_info(m_vorbisFile, -1);		//memset(&m_soundFormat, 0, sizeof(m_soundFormat));		m_soundFormat->cbSize          = sizeof(m_soundFormat); 	m_soundFormat->nChannels       = vInfo->channels;	m_soundFormat->wBitsPerSample  = 16;                    //Ogg vorbis is always 16 bit	m_soundFormat->nSamplesPerSec  = vInfo->rate;	m_soundFormat->nAvgBytesPerSec = m_soundFormat->nSamplesPerSec * m_soundFormat->nChannels * 2; 	m_soundFormat->nBlockAlign     = 2 * m_soundFormat->nChannels;	m_soundFormat->wFormatTag      = 1;	//WIP	/*ogg_int64_t *buf= m_vorbisFile->pcmlengths;	__int64 bufferLength= (__int64) *m_vorbisFile->pcmlengths;	char* BUFFER= new char[bufferLength];	buf->*/	};SoundSource2D::~SoundSource2D(){	SAFE_DELETE(m_vorbisFile);	SAFE_DELETE(m_soundFormat);};

greets

Brainsmith

Share on other sites
To get the uncompressed data size you can use ov_pcm_total():

DWORD bytes = ov_pcm_total(m_vorbisFile, -1);

Share on other sites
thanks for the hint but it has the same problem with loss of data.
ov_pcm_total
gives me a 64bit integer. I do not really mind about that because the sounds I want to load this way are very short.

Is there no other way to initialize an array with a size larger than a 32 bit integer?

Share on other sites
The array is of chars (bytes) so the integer's size being 4 bytes or 8 bytes doesn't matter, it's only there to make sure that you can have enough bytes in the array. If it says 200 in the number, the array will be 200 bytes.
Just use it as it is, it's fine, you're confusing something...

Share on other sites
Hey man, I actually just wrote code today that does exactly what you want to do, load an entire ogg file into a buffer. It was slightly tricky, as like you mention, it's hard to determine the right buffer size. It turns out you can call ov_pcm_total() but then you have to multiply that length by the number of channels in the file. Here's what I had to do:

        ogg_int64_t bufSize = ov_pcm_total(m_vorbisFile, -1) * m_soundFormat->nChannels; //this is the key!        char* buffer = new char[bufSize];                char array[BUFFER_SIZE]; //BUFFER_SIZE = 32768        int bytes = 0;        //now keep reading until we've read everything                 do                  {                                // ov_read only reads a 'packet' so we have to keep calling it to get everything                                bytes = ov_read(&oggFile, array, BUFFER_SIZE, endian, 2, 1, &bitStream);                                                                // copy to our buffer at the end                                 memcpy(buffer + size,array,bytes);                                                                 size += bytes;                                if(bytes <= 0 || size >= totalSize)                                        break;                        }                        while (bytes > 0);      // and so on and so forth...

Hope this helps!

Share on other sites
Thanks for the advice but now I am really confused.

in my code it works without multiplying with the channel count.
bool SoundSource2D::LoadSound(){	//needed temporary data structures	OggVorbis_File					tmp_vorbisFile;	FILE*							file(NULL);	errno_t							errMsg;		//open file for reading	if ((errMsg  = fopen_s( &file, m_soundName, "rb" )) != 0)		{				MessageBoxA(NULL, m_soundName , "Error loading Sound", MB_OK | MB_ICONERROR);				return false;	}		//getting infos from file	if (ov_open_callbacks(file, &tmp_vorbisFile, NULL, 0, OV_CALLBACKS_DEFAULT) < 0)	{		fclose(file);		return false;	}	vorbis_info* vInfo = ov_info(&tmp_vorbisFile, -1);			// filling the WAVEFORMAT structure	m_soundFormat.cbSize          = sizeof(m_soundFormat); 	m_soundFormat.nChannels       = vInfo->channels;	m_soundFormat.wBitsPerSample  = 16;                    //Ogg vorbis is always 16 bit	m_soundFormat.nSamplesPerSec  = vInfo->rate;	m_soundFormat.nAvgBytesPerSec = m_soundFormat.nChannels * 2 * m_soundFormat.nSamplesPerSec  ; 	m_soundFormat.nBlockAlign     = m_soundFormat.nChannels * 2;	m_soundFormat.wFormatTag      = WAVE_FORMAT_PCM;		//disable warning in this case. These sounds should have less bytes than the maximum of a DWORD	#pragma warning (disable:4244)	m_soundSize = ov_pcm_total(&tmp_vorbisFile, -1);	#pragma warning (default:4244)			m_soundData= new char[m_soundSize];			DWORD pos = 0;	int sec = 0;	int ret = 1;		while(ret && pos<m_soundSize)	{		ret = ov_read(&tmp_vorbisFile, m_soundData+pos, m_soundSize-pos, 0, 2, 1, &sec);		pos += ret;	}	//kill the vorbis file	ov_clear(&tmp_vorbisFile);		//close file				fclose(file);				return true;

This works really fine for me. I can hear my first sounds in an application.. Whohoo..

Now I have to think about how to implement the Source Voices ;(

Please do not mind about message boxes in my code. They are just temporary stuff, which I will exchange when I start to log everything into a file.

@Shanee
I was just worried if the DWORD can assure that I have enough space in my array. If the int64 was bigger than the maximum of a 32 bit integer there would be a problem because I would not be able to read in the whole track. Or am I missunderstanding sth.?

Greetings =D

Fabbo

Share on other sites
Hello,

I know this topic is pretty old but I'm having trouble reading a .ogg file with XAudio2.

Result of my code is it plays some crazy sounds for a second or two and crashes with an Access violation reading location...

 FILE* file; errno_t err; //Open Filestream if( (err = fopen_s(&file,(char*)Sound->file.c_str(), "rb")) != 0) { System_Log("<li>Failed to open audio: %s", Sound->file.c_str()); } int re = 0; //Initalize Ogg bitstream if( (re = ov_fopen((char*)Sound->file.c_str(),&OggVFile)) != 0) { switch(re) { case OV_EREAD: System_Log("A read from media returned an error."); break; case OV_ENOTVORBIS: System_Log("Bitstream is not Vorbis data."); break; case OV_EVERSION: System_Log("Vorbis version mismatch."); break; case OV_EBADHEADER: System_Log("Invalid Vorbis bitstream header"); break; case OV_EFAULT: System_Log("Internal logic fault; indicates a bug or heap/stack corruption."); break; } } vorbis_info* vi = ov_info(&OggVFile, -1); memset(&Sound->wfm, 0, sizeof(Sound->wfm)); Sound->wfm.cbSize = sizeof(Sound->wfm); Sound->wfm.nChannels = vi->channels; Sound->wfm.wBitsPerSample = 16; Sound->wfm.nSamplesPerSec = vi->rate; Sound->wfm.nAvgBytesPerSec = Sound->wfm.nSamplesPerSec * Sound->wfm.nChannels * 2;//ov_bitrate(&OggVFile,-1); Sound->wfm.nBlockAlign = 2 * Sound->wfm.nChannels; Sound->wfm.wFormatTag = WAVE_FORMAT_PCM; //char **ptr=ov_comment(&OggVFile,-1)->user_comments; //while(*ptr){ // fprintf(stderr,"%s\n",*ptr); // ++ptr; //} //fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi->channels,vi->rate); //fprintf(stderr,"\nDecoded length: %ld samples\n", // (long)ov_pcm_total(&OggVFile,-1)); //fprintf(stderr,"Encoded by: %s\n\n",ov_comment(&OggVFile,-1)->vendor); long audio_lenght = ov_pcm_total(&OggVFile,-1); char* pcmout = new char[audio_lenght]; DWORD pos = 0; int sec = 0; int ret = 1; while(ret && pos<audio_lenght) { ret = ov_read(&OggVFile, pcmout+pos, audio_lenght-pos, 0, 2, 1, &sec); if(ret == 0) printf("eof"); else if(ret < 0) printf("error in stream"); //printf("pcm: %c",pcmout[pos]); pos += ret; } ov_clear(&OggVFile); HRESULT hr; //Create the source voice if (FAILED(hr = pXAudio2->CreateSourceVoice(&Sound->pSourceVoice, &Sound->wfm))) { System_Log("<li>Error %#X creating source voice", hr); //return false; } ////Submit the wave sample data using an XAUDIO2_BUFFER structure XAUDIO2_BUFFER buf = {0}; buf.pAudioData = (BYTE*)&pcmout; buf.AudioBytes = audio_lenght; Sound->buffer = buf; delete pcmout; 

What am I doing wrong?

Share on other sites
It was my understanding [font=courier new,courier,monospace]ov_pcm_total [/font]returns the number of PCM samples, and not the memory footprint.
Thereby, most stuff above is slightly off.
My system does
 const ogg_int64_t numSamples = ov_pcm_total(&add.object->state, -1); const ogg_int64_t numBytes = numSamples * sizeof(asingle);
Perhaps I have a problem but I think the documentation is rather clear.
[font=courier new,courier,monospace]ov_pcm_total[/font]: number of samples where [font=courier new,courier,monospace]numChannels [/font]samples is a 'block', [font=courier new,courier,monospace]numSamples = k * numChannels[/font] for some [font=courier new,courier,monospace]k[/font].
I am decoding to float32 so I multiply that by the size of a single precision float. In general, it must match the settings of the decode call involved.

So what you're doing is suspect. I don't recall the exact semantics of the decode call. Odds are it might work in bytes... or perhaps in samples... I don't remember, but considering you say [font=courier new,courier,monospace]Sound->wfm.wBitsPerSample = 16[/font] I'm inclined to speculate [font=courier new,courier,monospace]new char[ov_pcm_total(&OggVFile,-1)] [/font]is not what you really wanted to do, albeit it might work for some input. Edited by Krohm

Share on other sites
I'm totally confused right now.

I understand that ov_pcm_total returns the number of PCM samples, but how do I actually calculate the memory footprint?

What do you mean by this?

[font=courier new,courier,monospace]ov_pcm_total[/font]: number of samples where [font=courier new,courier,monospace]numChannels [/font]samples is a 'block', [font=courier new,courier,monospace]numSamples = k * numChannels[/font] for some [font=courier new,courier,monospace]k[/font].[/quote]

ov_pcm_total(&OggVFile,-1) * Sound->wfm.nChannels = audio bytes? (Doesn't work)

• 40
• 12
• 10
• 10
• 9
• Forum Statistics

• Total Topics
631371
• Total Posts
2999607
×