11// This file is part of SmallBASIC
22//
3- // Copyright(C) 2001-2019 Chris Warren-Smith.
3+ // Copyright(C) 2001-2020 Chris Warren-Smith.
44//
55// This program is distributed under the terms of the GPL v2.0 or later
66// Download the GNU Public License (GPL) from www.gnu.org
@@ -32,7 +32,7 @@ struct Sound;
3232static ma_device device;
3333static ma_device_config config;
3434static strlib::Queue<Sound *> queue;
35- static strlib::Properties<Sound *> cache ;
35+ static int queuePos = 0 ;
3636
3737struct Sound {
3838 Sound (int frequency, int millis, int volume);
@@ -41,7 +41,7 @@ struct Sound {
4141
4242 ma_result construct (const char *path);
4343
44- ma_sine_wave *_tone;
44+ ma_waveform *_tone;
4545 ma_decoder *_decoder;
4646 uint32_t _start;
4747 uint32_t _duration;
@@ -59,8 +59,11 @@ Sound::Sound(int frequency, int millis, int volume) :
5959 _decoder(nullptr ),
6060 _start(0 ),
6161 _duration(millis) {
62- _tone = (ma_sine_wave *)malloc (sizeof (ma_sine_wave));
63- ma_sine_wave_init (volume / 100.0 , frequency, DEFAULT_SAMPLE_RATE, _tone);
62+ _tone = (ma_waveform *)malloc (sizeof (ma_waveform));
63+ ma_waveform_config config =
64+ ma_waveform_config_init (DEFAULT_FORMAT, DEFAULT_CHANNELS, DEFAULT_SAMPLE_RATE,
65+ ma_waveform_type_sine, volume / 100.0 , frequency);
66+ ma_waveform_init (&config, _tone);
6467}
6568
6669Sound::~Sound () {
@@ -82,20 +85,25 @@ static void data_callback(ma_device *device, void *output, const void *input, ma
8285 if (queue.empty ()) {
8386 usleep (MILLIS_TO_MICROS (10 ));
8487 } else {
85- Sound *sound = queue.front ();
88+ queuePos = (queuePos + 1 ) % queue.size ();
89+ Sound *sound = queue[queuePos];
8690 if (sound->_decoder != nullptr ) {
8791 // play audio track
88- ma_decoder_read_pcm_frames (sound->_decoder , output, frameCount);
92+ ma_uint64 framesRead = ma_decoder_read_pcm_frames (sound->_decoder , output, frameCount);
93+ if (framesRead == 0 ) {
94+ // finished playing
95+ queue.pop (false );
96+ }
8997 } else if (sound->_start == 0 ) {
9098 // start new sound
9199 sound->_start = dev_get_millisecond_count ();
92- ma_sine_wave_read_f32 (sound->_tone , frameCount, (float *)output);
100+ ma_waveform_read_pcm_frames (sound->_tone , (float *)output, frameCount );
93101 } else if (dev_get_millisecond_count () - sound->_start > sound->_duration ) {
94102 // sound has timed out
95- queue.pop (sound-> _decoder == nullptr );
103+ queue.pop (false );
96104 } else {
97105 // continue sound
98- ma_sine_wave_read_f32 (sound->_tone , frameCount, (float *)output);
106+ ma_waveform_read_pcm_frames (sound->_tone , (float *)output, frameCount );
99107 }
100108 }
101109}
@@ -122,8 +130,18 @@ static void setup_format(ma_format format, ma_uint32 channels, ma_uint32 sampleR
122130 }
123131}
124132
133+ static void device_start () {
134+ if (ma_device__get_state (&device) != MA_STATE_STARTED) {
135+ ma_result result = ma_device_start (&device);
136+ if (result != MA_SUCCESS) {
137+ err_throw (" Failed to start audio [%d]" , result);
138+ }
139+ }
140+ }
141+
125142bool audio_open () {
126143 setup_config (DEFAULT_FORMAT, DEFAULT_CHANNELS, DEFAULT_SAMPLE_RATE);
144+ queuePos = 0 ;
127145 return (ma_device_init (nullptr , &config, &device) == MA_SUCCESS);
128146}
129147
@@ -133,32 +151,19 @@ void audio_close() {
133151}
134152
135153void osd_audio (const char *path) {
136- Sound *sound = cache.get (path);
137- if (sound) {
154+ Sound *sound = new Sound ();
155+ ma_result result = sound->construct (path);
156+ if (result != MA_SUCCESS) {
157+ delete sound;
158+ err_throw (" Failed to open sound file [%d]" , result);
159+ } else {
160+ setup_format (sound->_decoder ->outputFormat ,
161+ sound->_decoder ->outputChannels ,
162+ sound->_decoder ->outputSampleRate );
138163 ma_mutex_lock (&device.lock );
139164 queue.push (sound);
140165 ma_mutex_unlock (&device.lock );
141- } else {
142- sound = new Sound ();
143- ma_result result = sound->construct (path);
144- if (result != MA_SUCCESS) {
145- delete sound;
146- err_throw (" Failed to open sound file [%d]" , result);
147- } else {
148- setup_format (sound->_decoder ->outputFormat ,
149- sound->_decoder ->outputChannels ,
150- sound->_decoder ->outputSampleRate );
151- ma_mutex_lock (&device.lock );
152- queue.push (sound);
153- cache.put (path, sound);
154- ma_mutex_unlock (&device.lock );
155- if (queue.size () == 1 ) {
156- result = ma_device_start (&device);
157- if (result != MA_SUCCESS) {
158- err_throw (" Failed to start audio [%d]" , result);
159- }
160- }
161- }
166+ device_start ();
162167 }
163168}
164169
@@ -180,7 +185,7 @@ void osd_clear_sound_queue() {
180185 }
181186
182187 queue.removeAll ();
183- cache. removeAll () ;
188+ queuePos = 0 ;
184189}
185190
186191void osd_sound (int frequency, int millis, int volume, int background) {
@@ -190,13 +195,13 @@ void osd_sound(int frequency, int millis, int volume, int background) {
190195 ma_mutex_unlock (&device.lock );
191196
192197 if (!background) {
193- ma_device_start (&device );
198+ device_start ( );
194199 usleep (MILLIS_TO_MICROS (millis));
195200 ma_device_stop (&device);
196201 ma_mutex_lock (&device.lock );
197202 queue.pop ();
198203 ma_mutex_unlock (&device.lock );
199204 } else if (queue.size () == 1 ) {
200- ma_device_start (&device );
205+ device_start ( );
201206 }
202207}
0 commit comments