2
0
Эх сурвалжийг харах

Require AudioStream::mix to return the number of frames successfully mixed

Ellen Poe 4 жил өмнө
parent
commit
53843ba872

+ 1 - 1
doc/classes/AudioStreamPlayback.xml

@@ -26,7 +26,7 @@
 			</description>
 		</method>
 		<method name="_mix" qualifiers="virtual">
-			<return type="void" />
+			<return type="int" />
 			<argument index="0" name="buffer" type="AudioFrame*" />
 			<argument index="1" name="rate_scale" type="float" />
 			<argument index="2" name="frames" type="int" />

+ 6 - 2
modules/minimp3/audio_stream_mp3.cpp

@@ -37,11 +37,13 @@
 
 #include "core/io/file_access.h"
 
-void AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) {
-	ERR_FAIL_COND(!active);
+int AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) {
+	ERR_FAIL_COND_V(!active, 0);
 
 	int todo = p_frames;
 
+	int frames_mixed_this_step = p_frames;
+
 	while (todo && active) {
 		mp3dec_frame_info_t frame_info;
 		mp3d_sample_t *buf_frame = nullptr;
@@ -60,6 +62,7 @@ void AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) {
 				seek(mp3_stream->loop_offset);
 				loops++;
 			} else {
+				frames_mixed_this_step = p_frames - todo;
 				//fill remainder with silence
 				for (int i = p_frames - todo; i < p_frames; i++) {
 					p_buffer[i] = AudioFrame(0, 0);
@@ -69,6 +72,7 @@ void AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) {
 			}
 		}
 	}
+	return frames_mixed_this_step;
 }
 
 float AudioStreamPlaybackMP3::get_stream_sampling_rate() {

+ 1 - 1
modules/minimp3/audio_stream_mp3.h

@@ -51,7 +51,7 @@ class AudioStreamPlaybackMP3 : public AudioStreamPlaybackResampled {
 	Ref<AudioStreamMP3> mp3_stream;
 
 protected:
-	virtual void _mix_internal(AudioFrame *p_buffer, int p_frames) override;
+	virtual int _mix_internal(AudioFrame *p_buffer, int p_frames) override;
 	virtual float get_stream_sampling_rate() override;
 
 public:

+ 6 - 2
modules/stb_vorbis/audio_stream_ogg_vorbis.cpp

@@ -32,13 +32,15 @@
 
 #include "core/io/file_access.h"
 
-void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) {
-	ERR_FAIL_COND(!active);
+int AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) {
+	ERR_FAIL_COND_V(!active, 0);
 
 	int todo = p_frames;
 
 	int start_buffer = 0;
 
+	int frames_mixed_this_step = p_frames;
+
 	while (todo && active) {
 		float *buffer = (float *)p_buffer;
 		if (start_buffer > 0) {
@@ -64,6 +66,7 @@ void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_fra
 				// we still have buffer to fill, start from this element in the next iteration.
 				start_buffer = p_frames - todo;
 			} else {
+				frames_mixed_this_step = p_frames - todo;
 				for (int i = p_frames - todo; i < p_frames; i++) {
 					p_buffer[i] = AudioFrame(0, 0);
 				}
@@ -72,6 +75,7 @@ void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_fra
 			}
 		}
 	}
+	return frames_mixed_this_step;
 }
 
 float AudioStreamPlaybackOGGVorbis::get_stream_sampling_rate() {

+ 1 - 1
modules/stb_vorbis/audio_stream_ogg_vorbis.h

@@ -52,7 +52,7 @@ class AudioStreamPlaybackOGGVorbis : public AudioStreamPlaybackResampled {
 	Ref<AudioStreamOGGVorbis> vorbis_stream;
 
 protected:
-	virtual void _mix_internal(AudioFrame *p_buffer, int p_frames) override;
+	virtual int _mix_internal(AudioFrame *p_buffer, int p_frames) override;
 	virtual float get_stream_sampling_rate() override;
 
 public:

+ 5 - 2
scene/resources/audio_stream_sample.cpp

@@ -221,12 +221,12 @@ void AudioStreamPlaybackSample::do_resample(const Depth *p_src, AudioFrame *p_ds
 	}
 }
 
-void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
 	if (!base->data || !active) {
 		for (int i = 0; i < p_frames; i++) {
 			p_buffer[i] = AudioFrame(0, 0);
 		}
-		return;
+		return 0;
 	}
 
 	int len = base->data_bytes;
@@ -395,12 +395,15 @@ void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, in
 	}
 
 	if (todo) {
+		int mixed_frames = p_frames - todo;
 		//bit was missing from mix
 		int todo_ofs = p_frames - todo;
 		for (int i = todo_ofs; i < p_frames; i++) {
 			p_buffer[i] = AudioFrame(0, 0);
 		}
+		return mixed_frames;
 	}
+	return p_frames;
 }
 
 AudioStreamPlaybackSample::AudioStreamPlaybackSample() {}

+ 1 - 1
scene/resources/audio_stream_sample.h

@@ -73,7 +73,7 @@ public:
 	virtual float get_playback_position() const override;
 	virtual void seek(float p_time) override;
 
-	virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
+	virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
 
 	AudioStreamPlaybackSample();
 };

+ 35 - 10
servers/audio/audio_stream.cpp

@@ -74,11 +74,13 @@ void AudioStreamPlayback::seek(float p_time) {
 	}
 }
 
-void AudioStreamPlayback::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
-	if (GDVIRTUAL_CALL(_mix, p_buffer, p_rate_scale, p_frames)) {
-		return;
+int AudioStreamPlayback::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+	int ret;
+	if (GDVIRTUAL_CALL(_mix, p_buffer, p_rate_scale, p_frames, ret)) {
+		return ret;
 	}
 	WARN_PRINT_ONCE("AudioStreamPlayback::mix unimplemented!");
+	return 0;
 }
 
 void AudioStreamPlayback::_bind_methods() {
@@ -103,12 +105,14 @@ void AudioStreamPlaybackResampled::_begin_resample() {
 	mix_offset = 0;
 }
 
-void AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+int AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
 	float target_rate = AudioServer::get_singleton()->get_mix_rate();
 	float playback_speed_scale = AudioServer::get_singleton()->get_playback_speed_scale();
 
 	uint64_t mix_increment = uint64_t(((get_stream_sampling_rate() * p_rate_scale * playback_speed_scale) / double(target_rate)) * double(FP_LEN));
 
+	int mixed_frames_total = p_frames;
+
 	for (int i = 0; i < p_frames; i++) {
 		uint32_t idx = CUBIC_INTERP_HISTORY + uint32_t(mix_offset >> FP_BITS);
 		//standard cubic interpolation (great quality/performance ratio)
@@ -119,6 +123,11 @@ void AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale,
 		AudioFrame y2 = internal_buffer[idx - 1];
 		AudioFrame y3 = internal_buffer[idx - 0];
 
+		if (idx <= internal_buffer_end && idx >= internal_buffer_end && mixed_frames_total == p_frames) {
+			// The internal buffer ends somewhere in this range, and we haven't yet recorded the number of good frames we have.
+			mixed_frames_total = i;
+		}
+
 		float mu2 = mu * mu;
 		AudioFrame a0 = 3 * y1 - 3 * y2 + y3 - y0;
 		AudioFrame a1 = 2 * y0 - 5 * y1 + 4 * y2 - y3;
@@ -135,7 +144,14 @@ void AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale,
 			internal_buffer[2] = internal_buffer[INTERNAL_BUFFER_LEN + 2];
 			internal_buffer[3] = internal_buffer[INTERNAL_BUFFER_LEN + 3];
 			if (is_playing()) {
-				_mix_internal(internal_buffer + 4, INTERNAL_BUFFER_LEN);
+				int mixed_frames = _mix_internal(internal_buffer + 4, INTERNAL_BUFFER_LEN);
+				if (mixed_frames != INTERNAL_BUFFER_LEN) {
+					// internal_buffer[mixed_frames] is the first frame of silence.
+					internal_buffer_end = mixed_frames;
+				} else {
+					// The internal buffer does not contain the first frame of silence.
+					internal_buffer_end = -1;
+				}
 			} else {
 				//fill with silence, not playing
 				for (int j = 0; j < INTERNAL_BUFFER_LEN; ++j) {
@@ -145,6 +161,7 @@ void AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale,
 			mix_offset -= (INTERNAL_BUFFER_LEN << FP_BITS);
 		}
 	}
+	return mixed_frames_total;
 }
 
 ////////////////////////////////
@@ -210,7 +227,7 @@ void AudioStreamMicrophone::_bind_methods() {
 AudioStreamMicrophone::AudioStreamMicrophone() {
 }
 
-void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_frames) {
+int AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_frames) {
 	AudioDriver::get_singleton()->lock();
 
 	Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer();
@@ -221,6 +238,8 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr
 	unsigned int input_position = AudioDriver::get_singleton()->get_input_position();
 #endif
 
+	int mixed_frames = p_frames;
+
 	if (playback_delay > input_size) {
 		for (int i = 0; i < p_frames; i++) {
 			p_buffer[i] = AudioFrame(0.0f, 0.0f);
@@ -240,6 +259,9 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr
 
 				p_buffer[i] = AudioFrame(l, r);
 			} else {
+				if (mixed_frames == p_frames) {
+					mixed_frames = i;
+				}
 				p_buffer[i] = AudioFrame(0.0f, 0.0f);
 			}
 		}
@@ -252,10 +274,12 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr
 #endif
 
 	AudioDriver::get_singleton()->unlock();
+
+	return mixed_frames;
 }
 
-void AudioStreamPlaybackMicrophone::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
-	AudioStreamPlaybackResampled::mix(p_buffer, p_rate_scale, p_frames);
+int AudioStreamPlaybackMicrophone::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+	return AudioStreamPlaybackResampled::mix(p_buffer, p_rate_scale, p_frames);
 }
 
 float AudioStreamPlaybackMicrophone::get_stream_sampling_rate() {
@@ -428,13 +452,14 @@ void AudioStreamPlaybackRandomPitch::seek(float p_time) {
 	}
 }
 
-void AudioStreamPlaybackRandomPitch::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+int AudioStreamPlaybackRandomPitch::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
 	if (playing.is_valid()) {
-		playing->mix(p_buffer, p_rate_scale * pitch_scale, p_frames);
+		return playing->mix(p_buffer, p_rate_scale * pitch_scale, p_frames);
 	} else {
 		for (int i = 0; i < p_frames; i++) {
 			p_buffer[i] = AudioFrame(0, 0);
 		}
+		return p_frames;
 	}
 }
 

+ 9 - 7
servers/audio/audio_stream.h

@@ -51,7 +51,7 @@ protected:
 	GDVIRTUAL0RC(int, _get_loop_count)
 	GDVIRTUAL0RC(float, _get_playback_position)
 	GDVIRTUAL1(_seek, float)
-	GDVIRTUAL3(_mix, GDNativePtr<AudioFrame>, float, int)
+	GDVIRTUAL3R(int, _mix, GDNativePtr<AudioFrame>, float, int)
 public:
 	virtual void start(float p_from_pos = 0.0);
 	virtual void stop();
@@ -62,7 +62,7 @@ public:
 	virtual float get_playback_position() const;
 	virtual void seek(float p_time);
 
-	virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames);
+	virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames);
 };
 
 class AudioStreamPlaybackResampled : public AudioStreamPlayback {
@@ -77,15 +77,17 @@ class AudioStreamPlaybackResampled : public AudioStreamPlayback {
 	};
 
 	AudioFrame internal_buffer[INTERNAL_BUFFER_LEN + CUBIC_INTERP_HISTORY];
+	unsigned int internal_buffer_end = -1;
 	uint64_t mix_offset;
 
 protected:
 	void _begin_resample();
-	virtual void _mix_internal(AudioFrame *p_buffer, int p_frames) = 0;
+	// Returns the number of frames that were mixed.
+	virtual int _mix_internal(AudioFrame *p_buffer, int p_frames) = 0;
 	virtual float get_stream_sampling_rate() = 0;
 
 public:
-	virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
+	virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
 
 	AudioStreamPlaybackResampled() { mix_offset = 0; }
 };
@@ -140,11 +142,11 @@ class AudioStreamPlaybackMicrophone : public AudioStreamPlaybackResampled {
 	Ref<AudioStreamMicrophone> microphone;
 
 protected:
-	virtual void _mix_internal(AudioFrame *p_buffer, int p_frames) override;
+	virtual int _mix_internal(AudioFrame *p_buffer, int p_frames) override;
 	virtual float get_stream_sampling_rate() override;
 
 public:
-	virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
+	virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
 
 	virtual void start(float p_from_pos = 0.0) override;
 	virtual void stop() override;
@@ -208,7 +210,7 @@ public:
 	virtual float get_playback_position() const override;
 	virtual void seek(float p_time) override;
 
-	virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
+	virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
 
 	~AudioStreamPlaybackRandomPitch();
 };

+ 2 - 1
servers/audio/effects/audio_stream_generator.cpp

@@ -138,7 +138,7 @@ void AudioStreamGeneratorPlayback::clear_buffer() {
 	mixed = 0;
 }
 
-void AudioStreamGeneratorPlayback::_mix_internal(AudioFrame *p_buffer, int p_frames) {
+int AudioStreamGeneratorPlayback::_mix_internal(AudioFrame *p_buffer, int p_frames) {
 	int read_amount = buffer.data_left();
 	if (p_frames < read_amount) {
 		read_amount = p_frames;
@@ -156,6 +156,7 @@ void AudioStreamGeneratorPlayback::_mix_internal(AudioFrame *p_buffer, int p_fra
 	}
 
 	mixed += p_frames / generator->get_mix_rate();
+	return read_amount < p_frames ? read_amount : p_frames;
 }
 
 float AudioStreamGeneratorPlayback::get_stream_sampling_rate() {

+ 1 - 1
servers/audio/effects/audio_stream_generator.h

@@ -67,7 +67,7 @@ class AudioStreamGeneratorPlayback : public AudioStreamPlaybackResampled {
 	AudioStreamGenerator *generator;
 
 protected:
-	virtual void _mix_internal(AudioFrame *p_buffer, int p_frames) override;
+	virtual int _mix_internal(AudioFrame *p_buffer, int p_frames) override;
 	virtual float get_stream_sampling_rate() override;
 
 	static void _bind_methods();