@@ -23,6 +23,7 @@ using ::godot::PropertyHint;
2323using ::godot::PropertyInfo;
2424using ::godot::Ref;
2525using ::godot::StringName;
26+ using ::godot::TypedArray;
2627using ::godot::Variant;
2728
2829#define BARELY_BIND_GODOT_ENUM_VALUE (EnumType, Name, Value ) \
@@ -109,13 +110,20 @@ void BarelyInstrument::set_note_on(float pitch, float gain, float pitch_shift) {
109110 }
110111}
111112
112- void BarelyInstrument::set_slice (const Ref<BarelySliceResource>& slice) {
113- if (slice_.is_valid ()) {
114- slice_->disconnect (" slice_changed" , Callable (this , " _on_slice_changed" ));
113+ void BarelyInstrument::set_slices (const TypedArray<Ref<BarelySliceResource>>& slices) {
114+ for (int i = 0 ; i < slices_.size (); ++i) {
115+ Ref<BarelySliceResource> slice = slices_[i];
116+ if (slice.is_valid ()) {
117+ slice->disconnect (" slice_changed" , Callable (this , " _on_slice_changed" ));
118+ }
115119 }
116- slice_ = slice;
117- if (slice_.is_valid ()) {
118- slice_->connect (" slice_changed" , Callable (this , " _on_slice_changed" ), Object::CONNECT_DEFERRED );
120+ slices_ = slices;
121+ for (int i = 0 ; i < slices_.size (); ++i) {
122+ Ref<BarelySliceResource> slice = slices_[i];
123+ if (slice.is_valid ()) {
124+ slice->connect (" slice_changed" , Callable (this , " _on_slice_changed" ),
125+ Object::CONNECT_DEFERRED );
126+ }
119127 }
120128 _on_slice_changed ();
121129}
@@ -126,8 +134,8 @@ void BarelyInstrument::_bind_methods() {
126134 ClassDB::bind_method (D_METHOD (" set_note_on" , " pitch" , " gain" , " pitch_shift" ),
127135 &BarelyInstrument::set_note_on, DEFVAL (1 .0f ), DEFVAL (0 .0f ));
128136 ClassDB::bind_method (D_METHOD (" is_note_on" , " pitch" ), &BarelyInstrument::is_note_on);
129- ClassDB::bind_method (D_METHOD (" set_slice " , " slice " ), &BarelyInstrument::set_slice );
130- ClassDB::bind_method (D_METHOD (" get_slice " ), &BarelyInstrument::get_slice );
137+ ClassDB::bind_method (D_METHOD (" set_slices " , " slices " ), &BarelyInstrument::set_slices );
138+ ClassDB::bind_method (D_METHOD (" get_slices " ), &BarelyInstrument::get_slices );
131139
132140 ClassDB::bind_method (D_METHOD (" _on_slice_changed" ), &BarelyInstrument::_on_slice_changed);
133141
@@ -168,9 +176,9 @@ void BarelyInstrument::_bind_methods() {
168176 ADD_PROPERTY (PropertyInfo (Variant::INT , " slice_mode" , PropertyHint::PROPERTY_HINT_ENUM ,
169177 " Sustain,Loop,Once" ),
170178 " set_slice_mode" , " get_slice_mode" );
171- ADD_PROPERTY (PropertyInfo (Variant::OBJECT , " slice " , PropertyHint::PROPERTY_HINT_RESOURCE_TYPE ,
179+ ADD_PROPERTY (PropertyInfo (Variant::ARRAY , " slices " , PropertyHint::PROPERTY_HINT_ARRAY_TYPE ,
172180 " BarelySliceResource" ),
173- " set_slice " , " get_slice " );
181+ " set_slices " , " get_slices " );
174182
175183 ADD_PROPERTY (
176184 PropertyInfo (Variant::FLOAT , " osc_mix" , PropertyHint::PROPERTY_HINT_RANGE , " 0,1,0.01" ),
@@ -228,71 +236,83 @@ void BarelyInstrument::_bind_methods() {
228236}
229237
230238void BarelyInstrument::_on_slice_changed () {
231- if (!slice_buffer_ .empty ()) {
239+ if (!slice_buffers_ .empty ()) {
232240 BarelyInstrument_SetSampleData (BarelyEngine::get_singleton ()->get (), instrument_id_, nullptr ,
233241 0 );
234- slice_buffer_.clear ();
235- }
236-
237- if (slice_.is_null ()) {
238- return ;
242+ slice_buffers_.clear ();
239243 }
240244
241- Ref<AudioStreamWAV> stream = slice_->get_stream ();
242- if (stream.is_null ()) {
245+ if (slices_.is_empty ()) {
243246 return ;
244247 }
245248
246- const auto & data = stream->get_data ();
247- const uint8_t * bytes = data.ptr ();
248- const int byte_count = data.size ();
249-
250- const auto format = stream->get_format ();
251- const int32_t sample_rate = stream->get_mix_rate ();
249+ std::vector<BarelySlice> sample_data (slices_.size (), BarelySlice{nullptr , 0 , 0 , 0 .0f });
250+ slice_buffers_.resize (slices_.size ());
252251
253- if (format == AudioStreamWAV::FORMAT_16_BITS ) {
254- const int16_t * pcm_bytes = (int16_t *)bytes;
255- const int count = byte_count / sizeof (int16_t );
256- slice_buffer_.resize (count);
257- for (int i = 0 ; i < count; ++i) {
258- static constexpr float kMaxSample = 32768 .0f ;
259- slice_buffer_[i] = pcm_bytes[i] / kMaxSample ;
252+ for (int i = 0 ; i < slices_.size (); ++i) {
253+ const Ref<BarelySliceResource>& slice = slices_[i];
254+ if (slice.is_null ()) {
255+ continue ;
260256 }
261- } else if (format == AudioStreamWAV::FORMAT_8_BITS ) {
262- slice_buffer_.resize (byte_count);
263- for (int i = 0 ; i < byte_count; ++i) {
264- static constexpr float kMaxSample = 128 .0f ;
265- slice_buffer_[i] = (bytes[i] - 128 ) / kMaxSample ;
266- }
267- } else if (format == AudioStreamWAV::FORMAT_QOA ) {
268- Ref<AudioStreamPlayback> playback = stream->instantiate_playback ();
269- if (!playback.is_valid ()) {
270- return ;
271- }
272- playback->start (0.0 );
273257
274- const float length = stream->get_length ();
275- slice_buffer_.reserve (static_cast <int32_t >(length * static_cast <float >(sample_rate)));
258+ Ref<AudioStreamWAV> stream = slice->get_stream ();
259+ if (stream.is_null ()) {
260+ continue ;
261+ }
276262
277- static constexpr int kQoaFrameCount = 512 ;
278- while (playback->is_playing ()) {
279- const auto frames = playback->mix_audio (1 .0f , kQoaFrameCount );
280- if (frames.size () == 0 ) {
281- break ;
263+ const auto & data = stream->get_data ();
264+ const uint8_t * bytes = data.ptr ();
265+ const int byte_count = data.size ();
266+
267+ const auto format = stream->get_format ();
268+ const int32_t sample_rate = stream->get_mix_rate ();
269+
270+ auto & samples = slice_buffers_[i];
271+ if (format == AudioStreamWAV::FORMAT_16_BITS ) {
272+ const int16_t * pcm_bytes = reinterpret_cast <const int16_t *>(bytes);
273+ const int count = byte_count / sizeof (int16_t );
274+ samples.resize (count);
275+ for (int i = 0 ; i < count; ++i) {
276+ static constexpr float kMaxSample = 32768 .0f ;
277+ samples[i] = pcm_bytes[i] / kMaxSample ;
282278 }
283- for (int i = 0 ; i < static_cast <int >(frames.size ()); ++i) {
284- const auto & frame = frames.ptr ()[i];
285- slice_buffer_.push_back (0 .5f * (frame.x + frame.y ));
279+ } else if (format == AudioStreamWAV::FORMAT_8_BITS ) {
280+ samples.resize (byte_count);
281+ for (int i = 0 ; i < byte_count; ++i) {
282+ static constexpr float kMaxSample = 128 .0f ;
283+ samples[i] = (bytes[i] - 128 ) / kMaxSample ;
286284 }
285+ } else if (format == AudioStreamWAV::FORMAT_QOA ) {
286+ Ref<AudioStreamPlayback> playback = stream->instantiate_playback ();
287+ if (!playback.is_valid ()) {
288+ continue ;
289+ }
290+ playback->start (0.0 );
291+
292+ const float length = stream->get_length ();
293+ samples.reserve (static_cast <int32_t >(length * static_cast <float >(sample_rate)));
294+
295+ static constexpr int kQoaFrameCount = 512 ;
296+ while (playback->is_playing ()) {
297+ const auto frames = playback->mix_audio (1 .0f , kQoaFrameCount );
298+ if (frames.size () == 0 ) {
299+ break ;
300+ }
301+ for (int i = 0 ; i < static_cast <int >(frames.size ()); ++i) {
302+ const auto & frame = frames.ptr ()[i];
303+ samples.push_back (0 .5f * (frame.x + frame.y ));
304+ }
305+ }
306+ } else {
307+ continue ; // TODO(#181): Support all formats.
287308 }
288- } else {
289- return ; // TODO(#181): Support all formats.
309+
310+ sample_data[i] = {samples.data (), static_cast <int32_t >(samples.size ()), sample_rate,
311+ slice->get_root_pitch ()};
290312 }
291313
292- const BarelySlice sample_data{slice_buffer_.data (), static_cast <int32_t >(slice_buffer_.size ()),
293- sample_rate, slice_->get_root_pitch ()};
294- BarelyInstrument_SetSampleData (BarelyEngine::get_singleton ()->get (), instrument_id_, &sample_data,
295- 1 );
314+ BarelyInstrument_SetSampleData (BarelyEngine::get_singleton ()->get (), instrument_id_,
315+ sample_data.data (), static_cast <int32_t >(sample_data.size ()));
296316}
297317
298318} // namespace barely::godot
0 commit comments