1 /*************************************************************************/
2 /* audio_stream_generator.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "audio_stream_generator.h"
32
set_mix_rate(float p_mix_rate)33 void AudioStreamGenerator::set_mix_rate(float p_mix_rate) {
34 mix_rate = p_mix_rate;
35 }
36
get_mix_rate() const37 float AudioStreamGenerator::get_mix_rate() const {
38
39 return mix_rate;
40 }
41
set_buffer_length(float p_seconds)42 void AudioStreamGenerator::set_buffer_length(float p_seconds) {
43
44 buffer_len = p_seconds;
45 }
get_buffer_length() const46 float AudioStreamGenerator::get_buffer_length() const {
47
48 return buffer_len;
49 }
50
instance_playback()51 Ref<AudioStreamPlayback> AudioStreamGenerator::instance_playback() {
52
53 Ref<AudioStreamGeneratorPlayback> playback;
54 playback.instance();
55 playback->generator = this;
56 int target_buffer_size = mix_rate * buffer_len;
57 playback->buffer.resize(nearest_shift(target_buffer_size));
58 playback->buffer.clear();
59 return playback;
60 }
get_stream_name() const61 String AudioStreamGenerator::get_stream_name() const {
62
63 return "UserFeed";
64 }
65
get_length() const66 float AudioStreamGenerator::get_length() const {
67 return 0;
68 }
69
_bind_methods()70 void AudioStreamGenerator::_bind_methods() {
71 ClassDB::bind_method(D_METHOD("set_mix_rate", "hz"), &AudioStreamGenerator::set_mix_rate);
72 ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioStreamGenerator::get_mix_rate);
73
74 ClassDB::bind_method(D_METHOD("set_buffer_length", "seconds"), &AudioStreamGenerator::set_buffer_length);
75 ClassDB::bind_method(D_METHOD("get_buffer_length"), &AudioStreamGenerator::get_buffer_length);
76
77 ADD_PROPERTY(PropertyInfo(Variant::REAL, "mix_rate", PROPERTY_HINT_RANGE, "20,192000,1"), "set_mix_rate", "get_mix_rate");
78 ADD_PROPERTY(PropertyInfo(Variant::REAL, "buffer_length", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_buffer_length", "get_buffer_length");
79 }
80
AudioStreamGenerator()81 AudioStreamGenerator::AudioStreamGenerator() {
82 mix_rate = 44100;
83 buffer_len = 0.5;
84 }
85
86 ////////////////
87
push_frame(const Vector2 & p_frame)88 bool AudioStreamGeneratorPlayback::push_frame(const Vector2 &p_frame) {
89 if (buffer.space_left() < 1) {
90 return false;
91 }
92
93 AudioFrame f = p_frame;
94
95 buffer.write(&f, 1);
96 return true;
97 }
98
can_push_buffer(int p_frames) const99 bool AudioStreamGeneratorPlayback::can_push_buffer(int p_frames) const {
100 return buffer.space_left() >= p_frames;
101 }
push_buffer(const PoolVector2Array & p_frames)102 bool AudioStreamGeneratorPlayback::push_buffer(const PoolVector2Array &p_frames) {
103
104 int to_write = p_frames.size();
105 if (buffer.space_left() < to_write) {
106 return false;
107 }
108
109 PoolVector2Array::Read r = p_frames.read();
110 if (sizeof(real_t) == 4) {
111 //write directly
112 buffer.write((const AudioFrame *)r.ptr(), to_write);
113 } else {
114 //convert from double
115 AudioFrame buf[2048];
116 int ofs = 0;
117 while (to_write) {
118
119 int w = MIN(to_write, 2048);
120 for (int i = 0; i < w; i++) {
121 buf[i] = r[i + ofs];
122 }
123 buffer.write(buf, w);
124 ofs += w;
125 to_write -= w;
126 }
127 }
128 return true;
129 }
130
get_frames_available() const131 int AudioStreamGeneratorPlayback::get_frames_available() const {
132 return buffer.space_left();
133 }
134
get_skips() const135 int AudioStreamGeneratorPlayback::get_skips() const {
136 return skips;
137 }
138
clear_buffer()139 void AudioStreamGeneratorPlayback::clear_buffer() {
140 ERR_FAIL_COND(active);
141 buffer.clear();
142 mixed = 0;
143 }
144
_mix_internal(AudioFrame * p_buffer,int p_frames)145 void AudioStreamGeneratorPlayback::_mix_internal(AudioFrame *p_buffer, int p_frames) {
146
147 int read_amount = buffer.data_left();
148 if (p_frames < read_amount) {
149 read_amount = p_frames;
150 }
151
152 buffer.read(p_buffer, read_amount);
153
154 if (read_amount < p_frames) {
155 //skipped, not ideal
156 for (int i = read_amount; i < p_frames; i++) {
157 p_buffer[i] = AudioFrame(0, 0);
158 }
159
160 skips++;
161 }
162
163 mixed += p_frames / generator->get_mix_rate();
164 }
get_stream_sampling_rate()165 float AudioStreamGeneratorPlayback::get_stream_sampling_rate() {
166 return generator->get_mix_rate();
167 }
168
start(float p_from_pos)169 void AudioStreamGeneratorPlayback::start(float p_from_pos) {
170
171 if (mixed == 0.0) {
172 _begin_resample();
173 }
174 skips = 0;
175 active = true;
176 mixed = 0.0;
177 }
178
stop()179 void AudioStreamGeneratorPlayback::stop() {
180 active = false;
181 }
is_playing() const182 bool AudioStreamGeneratorPlayback::is_playing() const {
183
184 return active; //always playing, can't be stopped
185 }
186
get_loop_count() const187 int AudioStreamGeneratorPlayback::get_loop_count() const {
188 return 0;
189 }
190
get_playback_position() const191 float AudioStreamGeneratorPlayback::get_playback_position() const {
192 return mixed;
193 }
seek(float p_time)194 void AudioStreamGeneratorPlayback::seek(float p_time) {
195 //no seek possible
196 }
197
_bind_methods()198 void AudioStreamGeneratorPlayback::_bind_methods() {
199 ClassDB::bind_method(D_METHOD("push_frame", "frame"), &AudioStreamGeneratorPlayback::push_frame);
200 ClassDB::bind_method(D_METHOD("can_push_buffer", "amount"), &AudioStreamGeneratorPlayback::can_push_buffer);
201 ClassDB::bind_method(D_METHOD("push_buffer", "frames"), &AudioStreamGeneratorPlayback::push_buffer);
202 ClassDB::bind_method(D_METHOD("get_frames_available"), &AudioStreamGeneratorPlayback::get_frames_available);
203 ClassDB::bind_method(D_METHOD("get_skips"), &AudioStreamGeneratorPlayback::get_skips);
204 ClassDB::bind_method(D_METHOD("clear_buffer"), &AudioStreamGeneratorPlayback::clear_buffer);
205 }
206
AudioStreamGeneratorPlayback()207 AudioStreamGeneratorPlayback::AudioStreamGeneratorPlayback() {
208 generator = NULL;
209 skips = 0;
210 active = false;
211 mixed = 0;
212 }
213