Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » how to use play_audio_stream?

This thread is locked; no one can reply to it. rss feed Print
how to use play_audio_stream?
aesteves
Member #12,798
April 2011

I want an example where load a wav file and play it, and when it finished sound start again and again and again...

I want to use the function play_audio_stream, but I dont know how.

I try these, but not soud anything:

int main()
{
allegro_init();
install_keyboard();
install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL);

//create the audio stream
AUDIOSTREAM *stream = play_audio_stream(1024, 8, FALSE, 22050, 255, 128);

//Them create the sample "archivo" loading a wav
SAMPLE *archivo=load_wav("wav.wav");
while(!key[KEY_ESC]){
void *mem_chunk;
mem_chunk = get_audio_stream_buffer(stream);

//when the sound buffer is void:
if (mem_chunk != NULL){

//Put into the buffer the sample "archivo"
mem_chunk=&archivo;

//Indicate that the buffer is ready
free_audio_stream_buffer(stream);
}
}
}

I am from uruguay and my english is basic, please write correctly

Desmond Taylor
Member #11,943
May 2010
avatar

This may or may not help you but I wrote a basic class that loads, plays and stops audio using ALLEGRO_SAMPLE.

#SelectExpand
1#ifndef __AUDIO_HPP_INCLUDED 2#define __AUDIO_HPP_INCLUDED 3 4#include <allegro5/allegro_audio.h> 5#include <allegro5/allegro_acodec.h> 6 7struct SAMPLE_DATA 8{ 9 ALLEGRO_SAMPLE* sample; 10 ALLEGRO_SAMPLE_ID sample_id; 11}; 12 13class Audio 14{ 15 public: 16 Audio(); 17 ~Audio(); 18 19 int load_from_file( std::string filename ); 20 void play( int id, ALLEGRO_PLAYMODE loop = ALLEGRO_PLAYMODE_ONCE, float gain = 1.0, float pan = 0.0, float speed = 1.0 ); 21 void stop( int id ); 22 23 private: 24 std::vector<SAMPLE_DATA> sample; 25 bool is_valid_id( unsigned int id ); 26}; 27 28#endif // __AUDIO_HPP_INCLUDED

#SelectExpand
1#include "audio.hpp" 2 3Audio::Audio() 4{ 5 if ( !al_install_audio() ) 6 exit(-1); 7 8 if ( !al_init_acodec_addon() ) 9 exit(-1); 10 11 if ( !al_reserve_samples( 32 ) ) 12 exit(-1); 13} 14 15Audio::~Audio() 16{ 17 al_stop_samples(); 18 19 for ( unsigned int i=0; i<this->sample.size(); i++ ) 20 { 21 if ( this->sample[i].sample ) 22 al_destroy_sample( this->sample[i].sample ); 23 } 24 25 al_uninstall_audio(); 26} 27 28int Audio::load_from_file( std::string filename ) 29{ 30 ALLEGRO_SAMPLE* temp_sample = al_load_sample( filename.c_str() ); 31 if ( temp_sample ) 32 { 33 SAMPLE_DATA sd; 34 sd.sample = temp_sample; 35 this->sample.push_back( sd ); 36 return this->sample.size() - 1; 37 } 38 39 return -1; 40} 41 42void Audio::play( int id, ALLEGRO_PLAYMODE loop, float gain, float pan, float speed ) 43{ 44 if ( this->is_valid_id( id ) ) 45 { 46 al_play_sample( this->sample[id].sample, gain, pan, speed, loop, &this->sample[id].sample_id ); 47 } 48} 49 50void Audio::stop( int id ) 51{ 52 if ( this->is_valid_id( id ) ) 53 { 54 al_stop_sample( &this->sample[id].sample_id ); 55 } 56} 57 58bool Audio::is_valid_id( unsigned int id ) 59{ 60 if ( id < 0 || id >= this->sample.size() ) 61 return false; 62 63 if ( !this->sample[id].sample ) 64 return false; 65 66 return true; 67}

#SelectExpand
1#include <allegro5/allegro.h> 2 3// Include the audio header. 4#include "audio.hpp" 5 6int main() 7{ 8 al_init(); 9 10 // Create an audio pointer. This also initializes allegro audio addons. 11 // Must be called after al_init(). 12 Audio* audio = new Audio(); 13 14 // Load the audio file. 15 int sound_id = audio->load_from_file( "music.wav" ); 16 if ( sound_id == -1 ) // Returns -1 on failure. 17 exit(-1); 18 19 // Play the sound using the returned sound_id. 20 audio->play( sound_id, ALLEGRO_PLAYMODE_LOOP ); 21 22 // You need to add something here to stop the program ending else you shall not hear anything. 23 al_rest( 10000 ); // Rest for 10 seconds for now :) 24 25 return 0; 26}

Hope this helps getting sound to work.

Append: I haven't tested this code myself since I am now going to bed. Must be up for the kids in the morning.

aesteves
Member #12,798
April 2011

I want do it want do it with play_audio_stream

my reason:
"The audio stream functions are for playing digital sounds that are too big to fit in a regular SAMPLE structure, either because they are huge files that you want to load in pieces as the data is required, or because you are doing something clever like generating the waveform on the fly."
http://alleg.sourceforge.net/latestdocs/en/alleg028.html

Desmond Taylor
Member #11,943
May 2010
avatar

I never read that :P I shall have to add it to my class at some point for music files :)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

aesteves said:

#SelectExpand
1int main() 2{ 3 allegro_init(); 4 install_keyboard(); 5 install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL); 6 7 //create the audio stream 8 AUDIOSTREAM *stream = play_audio_stream(1024, 8, FALSE, 22050, 255, 128); 9 10 //Them create the sample "archivo" loading a wav 11 SAMPLE *archivo=load_wav("wav.wav"); 12 while(!key[KEY_ESC]){ 13 void *mem_chunk; 14 mem_chunk = get_audio_stream_buffer(stream); 15 16 //when the sound buffer is void: 17 if (mem_chunk != NULL){ 18 19 //Put into the buffer the sample "archivo"
20 mem_chunk=&archivo;
21 22 //Indicate that the buffer is ready 23 free_audio_stream_buffer(stream); 24 } 25 } 26}

The line 'mem_chunk = &archivo;' does nothing. You have to fill the buffer using the pointer provided to you by get_audio_stream_buffer.

Example :

#SelectExpand
1 int length = 1024;// 1024 frames of data 2 int bits = 8;// 8 bit data 3 int stereo = 0;// mono data 4 int freq = 22050;// 22050 samples per second 5 int vol = 255; 6 int pan = 127; 7 8// AUDIOSTREAM *play_audio_stream(int len, int bits, int stereo, int freq, int vol, int pan); 9 AUDIOSTREAM *stream = play_audio_stream(1024, 8, FALSE, 22050, 255, 128); 10 11 void* mem_chunk; 12 mem_chunk = get_audio_stream_buffer(stream); 13 int bytes = length * (bits / 8) * (stereo ? 2 : 1) 14 if (mem_chunk) { 15 for (int i = 0 ; i < bytes ; ++i) { 16 mem_chunk[i] = SoundData();// However you generate your data 17 } 18 }

If you're going to use SAMPLE*s, then use the routines for playing samples - play_sample.

aesteves
Member #12,798
April 2011

it give me an error:
`void*' is not a pointer-to-object type

I put 3 lines to your example to generate my data:

#include <allegro.h>
#include <math.h>

int main()
{
allegro_init();
install_keyboard();
install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL);

int length = 1024;
int bits = 8;
int stereo = 0;
int freq = 22050;
int vol = 255;
int pan = 127;


//I generate my data
float PI=3.14159;
char data[1024];
for(int i=0;i<1024;i++) data[i]=sin(i*2*PI/10)*127;//I create the wave, 1 cycle per 10 sampes


AUDIOSTREAM *stream = play_audio_stream(1024, 8, FALSE, 22050, 255, 128);

void* mem_chunk;
mem_chunk = get_audio_stream_buffer(stream);
int bytes = length * (bits / 8) * (stereo ? 2 : 1);
if (mem_chunk) {
for (int i = 0 ; i < bytes ; ++i) {
mem_chunk[i] = data[i];
}
}
}

thank you for the reply

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

aesteves said:

`void*' is not a pointer-to-object type
...

void* mem_chunk;
    mem_chunk = get_audio_stream_buffer(stream);
    int bytes = length * (bits / 8) * (stereo ? 2 : 1);
    if (mem_chunk) {
       for (int i = 0 ; i < bytes ; ++i) {
           mem_chunk[i] = data[i];

Sorry, I mislead you. Before you can assign values to the array returned by get_audio_stream_buffer, you must cast it to a specific type. Since you are using a 8 bit mono stream, then you want to cast it to an unsigned char*.

The sample data are always in unsigned format.

This means that you need to convert your data from signed format into unsigned format.

So, before you had this :

aesteves said:

char data[1024];
for(int i=0;i<1024;i++) data[i]=sin(i*2*PI/10)*127;//I create the wave, 1 cycle per 10 sampes

But now you should have this :

unsigned char data[1024];
for (int i = 0 ; i < 1024 ; ++i) {
   float raw = sin((float)i*2.0f*M_PI/10.0);
   unsigned char d = (unsigned char)((raw*127.5f) + 127.5f);
   data[i] = d;
}

Edit
Please use <code>code goes here...</code> tags when posting code. It makes it much easier to read.

aesteves
Member #12,798
April 2011

ok thank

I want to know if allegro in the code use 1 or 2 buffers for the sound???

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

There are two buffers for the AUDIOSTREAM :

The manual said:

You can think of an AUDIOSTREAM structure as a wrapper around two audio buffers. The first thing you do is fill both buffers with sound data and let Allegro play them. Once the first buffer has been played, the second starts, and Allegro lets you know you have to fill the other one (i.e. graphics double buffering applied to sounds too big to fit into memory).

So fill both when you start the stream, and then only fill the other buffer when get_audio_stream_buffer returns non-null.

aesteves
Member #12,798
April 2011

Can I use more than 2 buffers?

I want to make a piano, and I am thinking use 1 buffer per musical note, beacause of these way I should not to refill the buffers and is would be more efficient and fast. I only would need to indicate what buffer play.

Beacuse I made a litle program that play a sound with AUDIOSTREAM, and when I order to change the sound, the program takes too long (you know that the speed is very important in a piano)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

aesteves said:

Can I use more than 2 buffers?

Not with an AUDIOSTREAM, no. You can make your own 'buffers' and then copy them into your AUDIOSTREAM buffer though.

aesteves said:

I want to make a piano, and I am thinking use 1 buffer per musical note, beacause of these way I should not to refill the buffers and is would be more efficient and fast. I only would need to indicate what buffer play.

You could make your own SAMPLE's, modifying the SAMPLE::data array after making a new sample with create_sample. Then you could just use play_sample.

aesteves said:

Beacuse I made a litle program that play a sound with AUDIOSTREAM, and when I order to change the sound, the program takes too long (you know that the speed is very important in a piano)

aesteves said:

//AUDIOSTREAM *play_audio_stream(int len, int bits, int stereo, int freq, int vol, int pan);
AUDIOSTREAM *stream = play_audio_stream(1024, 8, FALSE, 22050, 255, 128);

The reason it takes so long to hear the sound again is because you are not filling the buffer fast enough. With only 1024 frames in the buffer at 22050 frames per second, you need to refill the buffer (22050/1024 ~= 21) 21 times every second. You can either use a larger number of frames (len) and refill it less often (which will make the sound take longer to change), or you can continue to use a small number of frames and update the sound more often.

aesteves
Member #12,798
April 2011

I taste what you said, but it doesn't change.

Look at these example, I can set the variable whit values bigers or smollers than 1024, but there arent change.

The example has to play the note1 or note2 if the key z is presed or not

#SelectExpand
1#include <allegro.h> 2#include <string.h> 3#include <math.h> 4 5int main() 6{ 7 allegro_init(); 8 install_keyboard(); 9 set_gfx_mode(GFX_AUTODETECT_WINDOWED, 300, 200, 0, 0); 10 install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL); 11 12 int TAMANIODELBUFFER=1024;//Set the buffer's size 13 14 AUDIOSTREAM *stream = play_audio_stream(TAMANIODELBUFFER, 8, FALSE, 22050,255, 128); 15 unsigned char nota1[16];//Declare the notes 16 unsigned char nota2[16]; 17 for(int j=0;j<16;j++) nota1[j]=sin(j*2*3.14159/8)*127+127;//Create the notes 18 for(int j=0;j<16;j++) nota2[j]=sin(j*2*3.14159/16)*127+127; 19 unsigned char buf[TAMANIODELBUFFER]; 20 void *mem_chunk; 21 int pos=0; 22 int tecla=0; 23 while(!key[KEY_ESC]){ 24 mem_chunk = get_audio_stream_buffer(stream); 25 if(mem_chunk != NULL){ 26 if(key[KEY_Z]) for(int j=0;j<TAMANIODELBUFFER;j++) {buf[j]=nota2[(j+pos)%(16)]; if(j==TAMANIODELBUFFER-1) pos=(j+pos+1)%(16);} 27 else for(int j=0;j<TAMANIODELBUFFER;j++) {buf[j]=nota1[(j+pos)%(16)]; if(j==TAMANIODELBUFFER-1) pos=(j+pos+1)%(16);} 28 memcpy(mem_chunk, buf, sizeof(char)*TAMANIODELBUFFER ); 29 free_audio_stream_buffer(stream); 30 } 31 } 32} 33END_OF_MAIN();

what is the better way to get a fast reply of the sound about the keyboard?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I compiled your program and ran it, and there is a noticeable delay when changing sounds.

I think this has to do with Allegro's internal mixer buffer size, and I don't believe that can be changed by the user. Sorry.

play_sample is much faster for me, and plays pretty much immediately after a key press for me.

Go to: