Allegro.cc - Online Community

Allegro.cc Forums » Allegro Development » allegro audio stream improvements

This thread is locked; no one can reply to it. rss feed Print
 1   2 
allegro audio stream improvements
muhkuh
Member #14,826
January 2013

The UINT16 case is written strangely and would be wrong for big-endian. Why not just write 16-bit units? The UINT24 case will probably require an #ifdef for endianness.

I wasn't sure about how endianness is treated by allegro. My code assumed that the data has little endian byte order and keeps that byte order no matter what the system uses. I was under the assumption that allegro expects PCM in that format because it's most widely used. I had a look at the wav loaders and it seems like I was wrong. Data is converted to the system's byte order. I'm not sure about casting the buffer to uint16_t* for UINT16 though because of alignment issues. There might be some case where the provided buffer isn't 16 bit aligned. May be this could be a problem on some platforms allegro runs on? I would try to play it safe and assume the memory is unaligned.

Maybe. Users who are able to fill a fragment with non-silence probably don't need much help to fill it with silence ;) Actually, simply zeroing out the end of a partial buffer may result in an audible discontinuity which suggests not to encourage it.

Sorry. I don't understand. Do you mean zeroing out in opposite to filling with silence? What should be best written to the partial buffer? Should I make the function private again? Here is an updated version of the patch:
https://www.allegro.cc/files/attachment/608087

muhkuh said:
So I'm kindly asking again if it wouldn't be better to just add the function as al_get_audio_stream_played_samples and leave al_get_audio_stream_position_secs as it is?
Sure, we can do that. Thanks for looking into it.

I tried to create a patch that will add al_get_audio_stream_played_samples as well as al_get_audio_stream_position. The first works on all audio streams. The latter works only for self-updating streams. I tried to make al_get_audio_stream_position work as exactly as possible. I think I managed to get the common uses cases right for looping self-updating audio streams that have an intro, a loop area and an outro. The downside is that this requires some changes:

1. The stream has to remember the loop borders and keep track of the loop count. This is required to calculate the exact position from the number of played samples since the stream started.

2. Changing the loop area, seeking and rewinding the stream causes the stream to stop and restart. I don't see a big problem with this change but it is a change in behavior nonetheless. Previously loop borders could change at any time while playing. Seeking and rewinding should actually be more responsive now as they invalidate all fragment buffers and immediately allow new data to be uploaded by the feeder.

3. When the feeder has to be rewound at the end of the input data to allow seamless looping the stream's mutex will stay locked to prevent any changes to the loop area.

You can judge yourself if this is worth the effort. Doing it that way will make it easier to separate normal streams and self-updating streams in the future. al_get_audio_stream_played_samples can stay where it is and al_get_audio_stream_position can be moved to a new place. al_get_audio_stream_position could even stay internal for the time being.
https://www.allegro.cc/files/attachment/608088

PS. Since you will be submitting more patches, I would appreciate if you try to follow our coding style more closely in future. Thanks!

I already tried to adopt to your coding style. I'm sorry that I still missed something. I configured my IDE to an indent of 3 with inserted spaces. I also tried to use the K&R style brackets. Could you please point me at the mistakes I made for the new patches?

Thank you for your comments!

Regards

Peter Wang
Member #23
April 2000

muhkuh said:

I wasn't sure about how endianness is treated by allegro. My code assumed that the data has little endian byte order and keeps that byte order no matter what the system uses. I was under the assumption that allegro expects PCM in that format because it's most widely used. I had a look at the wav loaders and it seems like I was wrong. Data is converted to the system's byte order. I'm not sure about casting the buffer to uint16_t* for UINT16 though because of alignment issues. There might be some case where the provided buffer isn't 16 bit aligned. May be this could be a problem on some platforms allegro runs on? I would try to play it safe and assume the memory is unaligned.

Nah, I doubt it.

I will commit your patch with some changes (attached). It turns out we misinterpreted the 24-bit formats. Those actually use the lower 24-bits of 32-bit words. The dsound driver change was wrong and caused a crash.

Quote:

Sorry. I don't understand. Do you mean zeroing out in opposite to filling with silence? What should be best written to the partial buffer?

I always assumed it's slightly better to fade from the last sample value down to zero. Not sure it's true.

Will look at your other patch later. (edit: below)

Quote:

Could you please point me at the mistakes I made for the new patches?

Mostly add spaces around operators, and keep the lines within 80 chars unless it's really too hard.

Quote:

I tried to create a patch that will add al_get_audio_stream_played_samples as well as al_get_audio_stream_position. The first works on all audio streams. The latter works only for self-updating streams. I tried to make al_get_audio_stream_position work as exactly as possible.

I think it would be fine when the details are worked out, and the change in behaviour is probably acceptable. On the other hand, is there any reason to make this change if we want to deprecate self-updating streams, and al_get_audio_stream_played_samples exists for your use case?

aureus
Member #15,288
August 2013
avatar

muhkuh said:

@aureus:

could you please describe more detailed what the function is supposed to do? Basically you want to have two audio streams playing in sync and cross fade between them? Like in DJ Hero? How do you use this function? Several times or just one time to sync the streams?

What I do to make sure several streams play in sync is:
-create a separate mixer that is stopped and attach it to the global mixer
-create the streams and attach them to the separate mixer
-start the separate mixer

This will make sure the streams will start exactly at the same time. Otherwise it might happen that the OS makes a context switch between starting the first and the second stream which can introduce some delay under rare conditions.

The effect of the function is to set the playback time of the target stream to the current playback time of the reference stream, plus a specified offset, modulo the specified start and end times. If the two streams are on the same mixer and both playing, this will ensure that they are playing exactly in sync with each other.

What you suggested is something I considered, but found impractical for a few reasons: The game I'm working on could potentially have dozens of different music streams playing at various times in the course of a single play session. Your approach would require that I start each stream I want to play at launch, setting its volume to 0 and spending a lot of CPU time keeping its buffers filled so that it can be turned on and remain in sync. This function, on the other hand, will allow me to start a new stream and sync it to a stream that's always playing, like so:

#SelectExpand
1// Not a full-featured sound manager; just for illustrative purposes 2class SoundManager { 3public: 4 SoundManager() { 5 m_mixer = al_get_default_mixer(); 6 m_refStream = al_load_audio_stream("path/to/data/oneMinuteOfSilence.ogg"); 7 al_attach_audio_stream_to_mixer(m_refStream, m_mixer); 8 al_set_audio_stream_playmode(m_refStream, ALLEGRO_PLAYMODE_LOOP); 9 al_set_audio_stream_playing(m_refStream, true); 10 } 11 12 void playStreamSynced(ALLEGRO_AUDIO_STREAM * newStream, double loopStart, double loopEnd) { 13 al_set_audio_stream_gain(newStream, 0.f); 14 al_attach_audio_stream_to_mixer(newStream, m_mixer); 15 al_set_audio_stream_playmode(newStream, ALLEGRO_PLAYMODE_LOOP); 16 al_set_audio_stream_loop_secs(newStream, loopStart, loopEnd); 17 al_set_audio_stream_playing(newStream, true); // start the stream before syncing or it may go out of sync waiting for you to tell it to start. 18 al_sync_audio_stream_to_stream(newStream, m_refStream, 0.0, loopStart, loopEnd); 19 al_set_audio_stream_gain(newStream, 1.f); // should be a fade in here to prevent clipping, but that's beyond the scope of this example. 20 } 21protected: 22 ALLEGRO_MIXER * m_mixer; 23 ALLEGRO_AUDIO_STREAM * m_refStream; 24};

Does this answer your questions?

 1   2 


Go to: