Jump to content
  • Advertisement
Sign in to follow this  
Fabbo

XAudio2 and OGG as resource

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

If you intended to correct an error in the post then please contact us.

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.

the header:
#ifndef SOUNDSOURCE2D_H_INCLUDED
#define SOUNDSOURCE2D_H_INCLUDED

#include <Windows.h>


//forward decalrations
struct 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; } }
#endif


class 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 Destructor

SoundSource2D::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);

};



My coding skills are not the best. Please help me.

greets

Brainsmith

Share this post


Link to post
Share on other sites
Advertisement
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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..

@GreenToad: Perhaps your buffer is too big now.


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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!