[Need help] Why this code crached?

------------------- HPP ----------------------

#ifndef CPL_AUDIO_HPP
#define CPL_AUDIO_HPP

#include “SDL.h”
#include “SDL_audio.h”

namespace cpl_audio {

//
// struct sample_t
//

struct sample_t{
SDL_AudioSpec m_spec;
Uint8 *m_sound;
Uint32 m_soundlen;
Uint32 m_soundpos;
};// struct sample_t

//
// class cpl_audio_t
//

class cpl_audio_t {

public:
cpl_audio_t();
~cpl_audio_t();

void set_volume( const size_t vol );
void play_sound( const char * file );

private:
static size_t m_volume;
static SDL_AudioSpec m_dev_spec;
static SDL_AudioSpec m_desired_spec;
static sample_t m_sample;
static bool m_done;

static void audio_callback( void *userdata, Uint8 *stream, int len );

};// class cpl_audio_t

}// namespace cpl_audio

#endif // CPL_AUDIO_HPP

------------------------ CPP ------------------------

#include “cpl_audio.hpp”

namespace cpl_audio {

SDL_AudioSpec cpl_audio_t::m_dev_spec;
SDL_AudioSpec cpl_audio_t::m_desired_spec;
sample_t cpl_audio_t::m_sample;
size_t cpl_audio_t::m_volume( SDL_MIX_MAXVOLUME );
bool cpl_audio_t::m_done( false );

cpl_audio_t::cpl_audio_t()
{
m_desired_spec.freq = 22050;
m_desired_spec.format = AUDIO_S16LSB;
m_desired_spec.samples = 8192;
m_desired_spec.callback = audio_callback;
m_desired_spec.userdata = NULL;
m_sample.m_spec.callback = audio_callback;

m_sample.m_sound = 0;

if ( SDL_OpenAudio( &m_desired_spec, &m_dev_spec ) < 0 ) {
    std::cout << SDL_GetError() << std::endl;
}

SDL_PauseAudio(0);

}

cpl_audio_t::~cpl_audio_t()
{
SDL_CloseAudio();
SDL_FreeWAV( m_sample.m_sound );
}

void
cpl_audio_t::set_volume( const size_t vol )
{
SDL_LockAudio();
m_volume = vol;
SDL_UnlockAudio();
}

void
cpl_audio_t::play_sound( const char * file )
{
SDL_AudioCVT cvt;
SDL_AudioSpec spec;
Uint8 *data;
Uint32 dlen;

if ( SDL_LoadWAV( file, &spec, &data, &dlen ) == NULL )
    return;

if( SDL_BuildAudioCVT( &cvt, spec.format, spec.channels, spec.freq,
    m_dev_spec.format, m_dev_spec.channels, m_dev_spec.freq ) != 0 )
        return;

cvt.buf = new Uint8[dlen * cvt.len_mult];
memcpy( cvt.buf, data, dlen );
cvt.len = dlen;

if( SDL_ConvertAudio( &cvt ) != 0 )
{
    SDL_FreeWAV( data );
    delete [] cvt.buf;
    return;
}

SDL_FreeWAV( data );

SDL_LockAudio();

free( m_sample.m_sound );

m_sample.m_sound = cvt.buf;
m_sample.m_soundlen = cvt.len_cvt;
m_sample.m_soundpos = 0;
m_done = false;

SDL_UnlockAudio();

}

void
cpl_audio_t::audio_callback( void *userdata, Uint8 *stream, int len )
{
if( m_sample.m_sound && !m_done )
{
Uint8 *waveptr;
Uint32 waveleft;

    if( m_sample.m_soundpos < m_sample.m_soundlen )
    {
        waveptr = m_sample.m_sound + m_sample.m_soundpos;
        waveleft = m_sample.m_soundlen - m_sample.m_soundpos;

        SDL_MixAudio( stream, waveptr, waveleft, m_volume );
        m_sample.m_soundpos += len;

        if( m_sample.m_soundpos >= m_sample.m_soundlen )
            m_done = true;
    }
}

}// void audio_callback(…)

-------------------- MAIN ------------------------

#include “cpl_audio.hpp”

#include “SDL.h”

int main(int argc, char *argv[])
{
if ( SDL_Init( SDL_INIT_AUDIO ) < 0 )
return 1;

cpl_audio::cpl_audio_t audio;

audio.play_sound( "test.wav" );

while ( SDL_GetAudioStatus() == SDL_AUDIO_PLAYING )
    SDL_Delay(1000);

SDL_Quit();

return 0;

}

}// namespace cpl_audio–
Regards,
Igor Mironchick,
Intervale ©
#ICQ 492-597-570

[…]

static void audio_callback( void *userdata, Uint8 *stream,
  			int [...] len );

[…]

You can’t pass this function as a C callback! It needs
an “invisible” ‘this’ argument to work.

You need to use a C calling convension wrapper callback, that
casts ‘userdata’ to the type of your class, and then forwards the
call to your audio_callback().

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --'On Saturday 20 January 2007 21:07, Igor Mironchick wrote:

2007/1/20, David Olofson :

[…]

static void audio_callback( void *userdata, Uint8 *stream,
                                  int [...] len );

[…]

You can’t pass this function as a C callback! It needs
an “invisible” ‘this’ argument to work.

You need to use a C calling convension wrapper callback, that
casts ‘userdata’ to the type of your class, and then forwards the
call to your audio_callback().

Ooops, and where I can read about “C calling convension wrapper callback”?> On Saturday 20 January 2007 21:07, Igor Mironchick wrote:


Regards,
Igor Mironchick,
Intervale ©
#ICQ 492-597-570

I don’t think this is the problem - he’s using a static member
function as the callback, which doesn’t have a ‘this’ pointer. And
he’s only using static data in audio_callback(), so he doesn’t need to
do the typical casting of userdata that you would expect.

When I ran it I had several issues:

  1. main() was in the namespace - I assume this is a copy/paste error
  2. SDL_OpenAudio failed - I had to set m_desired_spec.channels before
    it would work for me (since this doesn’t stop the program, it later
    crashed in SDL_BuildAudioCVT())
  3. The check to see if SDL_BuildAudioCVT() doesn’t work (at least in
    SDL1.2.7 - maybe this changed). The man page says it returns 1 on
    success and -1 on error, but it’s checking for != 0 to determine an
    error condition.
  4. And I believe this is the main issue: In the audio callback, you
    call SDL_MixAudio with the amount of data left in your wave file. This
    doesn’t necessarily fit within the mix buffer (defined by the ‘len’
    argument in the callback). I think you want to pass in the min of
    ’waveleft’ and ‘len’ to SDL_MixAudio.

With those changes I was able to get some sound out.
-MikeOn 1/20/07, David Olofson wrote:

On Saturday 20 January 2007 21:07, Igor Mironchick wrote:
[…]

static void audio_callback( void *userdata, Uint8 *stream,
                                  int [...] len );

[…]

You can’t pass this function as a C callback! It needs
an “invisible” ‘this’ argument to work.

You need to use a C calling convension wrapper callback, that
casts ‘userdata’ to the type of your class, and then forwards the
call to your audio_callback().

[…]

Yes, you’re right, of course. Wasn’t reading carefully enough…

Also, one would expect to get compile errors, or at least warnings if
trying to pass a non static member.

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --'On Saturday 20 January 2007 22:07, Mike Shal wrote:

On 1/20/07, David Olofson <@David_Olofson> wrote:

On Saturday 20 January 2007 21:07, Igor Mironchick wrote:
[…]

static void audio_callback( void *userdata, Uint8 *stream,
                                  int [...] len );

[…]

You can’t pass this function as a C callback! It needs
an “invisible” ‘this’ argument to work.

You need to use a C calling convension wrapper callback, that
casts ‘userdata’ to the type of your class, and then forwards the
call to your audio_callback().

I don’t think this is the problem - he’s using a static member
function as the callback, which doesn’t have a ‘this’ pointer. And
he’s only using static data in audio_callback(), so he doesn’t need
to do the typical casting of userdata that you would expect.

2007/1/20, David Olofson <@David_Olofson>:

[…]

static void audio_callback( void *userdata, Uint8 *stream,
                                  int [...] len );

[…]

You can’t pass this function as a C callback! It needs
an “invisible” ‘this’ argument to work.

You need to use a C calling convension wrapper callback, that
casts ‘userdata’ to the type of your class, and then forwards the
call to your audio_callback().

Ooops, and where I can read about “C calling convension wrapper
callback”?

I think this has been discussed a few times in the past. It’s a
standard solution for wiring C API callbacks to non static C++ class
members. Handy when you need to keep track of multiple instances of
things in a mixed C/C++ system.

Either way, as you’re using a static member here, this shouldn’t be an
issue. I should learn to read. :smiley:

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --'On Saturday 20 January 2007 21:57, Igor Mironchick wrote:

On Saturday 20 January 2007 21:07, Igor Mironchick wrote:

2007/1/20, Mike Shal :

When I ran it I had several issues:

  1. main() was in the namespace - I assume this is a copy/paste error

U are righ.

  1. SDL_OpenAudio failed - I had to set m_desired_spec.channels before

it would work for me (since this doesn’t stop the program, it later
crashed in SDL_BuildAudioCVT())

Not sure. I was tested with this parameter. And I never have initialized
this in ctor. Try to do:
std::cout << m_dev_spec.channels << std::endl;
after SDL_OpenAudio()
There is NOTHING!!! (Or this is on my machine only?)

  1. The check to see if SDL_BuildAudioCVT() doesn’t work (at least in

SDL1.2.7 - maybe this changed). The man page says it returns 1 on
success and -1 on error, but it’s checking for != 0 to determine an
error condition.

Where I can read about reasons of craches SDL_BuildAudioCVT()?

  1. And I believe this is the main issue: In the audio callback, you

call SDL_MixAudio with the amount of data left in your wave file. This
doesn’t necessarily fit within the mix buffer (defined by the ‘len’
argument in the callback). I think you want to pass in the min of
’waveleft’ and ‘len’ to SDL_MixAudio.

May be… I fix it. But I still can’t play any WAV files. Why? How
audio_callback() calles? Is len parameter always equal length of the WAV?
Or this is something another?

With those changes I was able to get some sound out.

-Mike

How I can play all types of WAV files?–
Regards,
Igor Mironchick,
Intervale ©
#ICQ 492-597-570

[…]

Ooops, and where I can read about “C calling convension wrapper
callback”?
[…]

Here’s an old post describing how to do it:
http://www.libsdl.org/pipermail/sdl/2006-July/075468.html

Unfortunately, libsdl.org is virtually dead now. You can Google for
SDL audio callback “C++” userdata
and go for the cached version of the first hit.

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --'On Saturday 20 January 2007 23:02, David Olofson wrote:

2007/1/20, Mike Shal <@Mike_Shal>:

  1. The check to see if SDL_BuildAudioCVT() doesn’t work (at least in
    SDL1.2.7 - maybe this changed). The man page says it returns 1 on
    success and -1 on error, but it’s checking for != 0 to determine an
    error condition.

Where I can read about reasons of craches SDL_BuildAudioCVT()?

I’m not sure where you could read about it - SDL_BuildAudioCVT() only
crashed for me if SDL_OpenAudio() failed (which made everything 0 in
m_dev_spec). Once I set m_desired_spec.channels, SDL_OpenAudio
succeeded and SDL_BuildAudioCVT() didn’t crash.

  1. And I believe this is the main issue: In the audio callback, you
    call SDL_MixAudio with the amount of data left in your wave file. This
    doesn’t necessarily fit within the mix buffer (defined by the ‘len’
    argument in the callback). I think you want to pass in the min of
    ’waveleft’ and ‘len’ to SDL_MixAudio.

May be… I fix it. But I still can’t play any WAV files. Why? How
audio_callback() calles? Is len parameter always equal length of the WAV?
Or this is something another?

The ‘len’ parameter isn’t the size of the WAV, it’s the size of the
mix buffer. You can’t write more than ‘len’ bytes to the mix buffer,
and you can’t read past the end of the WAV. This is why you have to
find the minimum of the two and pass that to SDL_MixAudio().

How I can play all types of WAV files?

Not really sure what you mean here - if you’re looking for other
formats (like mp3, ogg, or whatever) you may want to look into some
add-on libraries like SDL_Mixer. Anyway, here’s your program with some
changes (look for the /* MARF */ comments). This ran for me and played
test.wav:

#include
#include “cpl_audio.hpp”

namespace cpl_audio {

SDL_AudioSpec cpl_audio_t::m_dev_spec;
SDL_AudioSpec cpl_audio_t::m_desired_spec;
sample_t cpl_audio_t::m_sample;
size_t cpl_audio_t::m_volume( SDL_MIX_MAXVOLUME );
bool cpl_audio_t::m_done( false );

cpl_audio_t::cpl_audio_t()
{
m_desired_spec.freq = 22050;
m_desired_spec.format = AUDIO_S16LSB;
m_desired_spec.samples = 8192;
m_desired_spec.callback = audio_callback;
m_desired_spec.userdata = NULL;
m_desired_spec.channels = 2; /* MARF */
m_sample.m_spec.callback = audio_callback;

m_sample.m_sound = 0;

if ( SDL_OpenAudio( &m_desired_spec, &m_dev_spec ) < 0 ) {
    std::cout << SDL_GetError() << std::endl;
}

SDL_PauseAudio(0);

}

cpl_audio_t::~cpl_audio_t()
{
SDL_CloseAudio();
SDL_FreeWAV( m_sample.m_sound );
}

void
cpl_audio_t::set_volume( const size_t vol )
{
SDL_LockAudio();
m_volume = vol;
SDL_UnlockAudio();
}

void
cpl_audio_t::play_sound( const char * file )
{
SDL_AudioCVT cvt;
SDL_AudioSpec spec;
Uint8 *data;
Uint32 dlen;

if ( SDL_LoadWAV( file, &spec, &data, &dlen ) == NULL )
    return;

if( SDL_BuildAudioCVT( &cvt, spec.format, spec.channels, spec.freq,
    m_dev_spec.format, m_dev_spec.channels, m_dev_spec.freq ) ==

-1 /* MARF */) {

        return;
}

cvt.buf = new Uint8[dlen * cvt.len_mult];
memcpy( cvt.buf, data, dlen );
cvt.len = dlen;

if( SDL_ConvertAudio( &cvt ) != 0 )
{
    SDL_FreeWAV( data );
    delete [] cvt.buf;
    return;
}

SDL_FreeWAV( data );

SDL_LockAudio();

free( m_sample.m_sound );

m_sample.m_sound = cvt.buf;
m_sample.m_soundlen = cvt.len_cvt;
m_sample.m_soundpos = 0;
m_done = false;

SDL_UnlockAudio();

}

void
cpl_audio_t::audio_callback( void *userdata, Uint8 *stream, int len )
{
if( m_sample.m_sound && !m_done )
{
Uint8 *waveptr;
Uint32 waveleft;

    if( m_sample.m_soundpos < m_sample.m_soundlen )
    {
        int mix_size; /* MARF */
        waveptr = m_sample.m_sound + m_sample.m_soundpos;
        waveleft = m_sample.m_soundlen - m_sample.m_soundpos;

        if(waveleft < len) /* MARF */
            mix_size = waveleft; /* MARF */
        else /* MARF */
            mix_size = len; /* MARF */
        SDL_MixAudio( stream, waveptr, mix_size /* MARF */, m_volume );
        m_sample.m_soundpos += mix_size; /* MARF */

        if( m_sample.m_soundpos >= m_sample.m_soundlen )
            m_done = true;
    }
}

}// void audio_callback(…)

}// namespace cpl_audio

#include “cpl_audio.hpp”

#include “SDL.h”

int main(int argc, char *argv[])
{
if ( SDL_Init( SDL_INIT_AUDIO ) < 0 )
return 1;

cpl_audio::cpl_audio_t audio;

audio.play_sound( "test.wav" );

while ( SDL_GetAudioStatus() == SDL_AUDIO_PLAYING )
    SDL_Delay(1000);

SDL_Quit();

return 0;

}

Hope that helps,
-MikeOn 1/20/07, Igor Mironchick wrote:

Thx for your reply.

2007/1/21, Mike Shal :

2007/1/20, Mike Shal :

  1. The check to see if SDL_BuildAudioCVT() doesn’t work (at least in
    SDL1.2.7 - maybe this changed). The man page says it returns 1 on
    success and -1 on error, but it’s checking for != 0 to determine an
    error condition.

Where I can read about reasons of craches SDL_BuildAudioCVT()?

I’m not sure where you could read about it - SDL_BuildAudioCVT() only
crashed for me if SDL_OpenAudio() failed (which made everything 0 in
m_dev_spec). Once I set m_desired_spec.channels, SDL_OpenAudio
succeeded and SDL_BuildAudioCVT() didn’t crash.

SDL_BuildAudioCVT() does not crash (if SDL_OpenAudio() does not fail). But
this function set cvt.needed flag!!! Which I does not verify. Now I solve
this problem and everething is Ok.

How I can play all types of WAV files?

Not really sure what you mean here - if you’re looking for other
formats (like mp3, ogg, or whatever) you may want to look into some
add-on libraries like SDL_Mixer. Anyway, here’s your program with some
changes (look for the /* MARF */ comments). This ran for me and played
test.wav:

I mean only WAV, not ogg ro mp3… And after fixing usage of
SDL_BuildAudioCVT() all is Ok.

One more time thx for your reply. It realy help me.> On 1/20/07, Igor Mironchick <@Igor_Mironchick> wrote:


Regards,
Igor Mironchick,
Intervale ©
#ICQ 492-597-570