diff --git a/generator/rs/audio_nodes.tmpl.rs b/generator/rs/audio_nodes.tmpl.rs index f3a96eb5..36d4ddde 100644 --- a/generator/rs/audio_nodes.tmpl.rs +++ b/generator/rs/audio_nodes.tmpl.rs @@ -335,7 +335,7 @@ fn listen_to_ended_event( use napi::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunctionCallMode}; use web_audio_api::Event; - let k_onended = crate::utils::get_symbol_for(env, "node-web-audio-api:onended"); + let k_onended = env.symbol_for("node-web-audio-api:onended")?; let ended_cb = js_this.get_property(k_onended).unwrap(); let mut ended_tsfn = env.create_threadsafe_function( &ended_cb, @@ -536,17 +536,20 @@ fn get_${d.slug(attr)}(ctx: CallContext) -> Result { if let Some(arr_f32) = value { let length = arr_f32.len(); - let arr_u8 = crate::utils::to_byte_slice(arr_f32); - - Ok(ctx.env - .create_arraybuffer_with_data(arr_u8.to_vec()) - .map(|array_buffer| { - array_buffer - .into_raw() - .into_typedarray(TypedArrayType::Float32, length, 0) - }) - .unwrap()? - .into_unknown()) + + let array_buffer = ctx.env.create_arraybuffer(length * 4).unwrap(); + let js_typed_array = array_buffer + .into_raw() + .into_typedarray(TypedArrayType::Float32, length, 0)?; + + let mut js_typed_array_value = js_typed_array.into_value()?; + let buffer: &mut [f32] = js_typed_array_value.as_mut(); + buffer.copy_from_slice(arr_f32); + + let js_typed_array = js_typed_array_value.arraybuffer + .into_typedarray(TypedArrayType::Float32, length, 0)?; + + Ok(js_typed_array.into_unknown()) } else { Ok(ctx.env.get_null()?.into_unknown()) } diff --git a/src/audio_buffer_source_node.rs b/src/audio_buffer_source_node.rs index 0b4fda86..3a79217f 100644 --- a/src/audio_buffer_source_node.rs +++ b/src/audio_buffer_source_node.rs @@ -192,7 +192,7 @@ fn listen_to_ended_event( use napi::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunctionCallMode}; use web_audio_api::Event; - let k_onended = crate::utils::get_symbol_for(env, "node-web-audio-api:onended"); + let k_onended = env.symbol_for("node-web-audio-api:onended")?; let ended_cb = js_this.get_property(k_onended).unwrap(); let mut ended_tsfn = env.create_threadsafe_function(&ended_cb, 0, |ctx: ThreadSafeCallContext| { diff --git a/src/audio_context.rs b/src/audio_context.rs index 2cce1a2b..5dc8df16 100644 --- a/src/audio_context.rs +++ b/src/audio_context.rs @@ -237,7 +237,7 @@ fn listen_to_events(ctx: CallContext) -> Result { let napi_context = ctx.env.unwrap::(&js_this)?; let context = napi_context.unwrap(); - let k_onsinkchange = crate::utils::get_symbol_for(ctx.env, "node-web-audio-api:onsinkchange"); + let k_onsinkchange = ctx.env.symbol_for("node-web-audio-api:onsinkchange")?; let sinkchange_cb = js_this.get_property(k_onsinkchange).unwrap(); let mut sinkchange_tsfn = ctx.env.create_threadsafe_function( &sinkchange_cb, @@ -250,7 +250,7 @@ fn listen_to_events(ctx: CallContext) -> Result { }, )?; - let k_onstatechange = crate::utils::get_symbol_for(ctx.env, "node-web-audio-api:onstatechange"); + let k_onstatechange = ctx.env.symbol_for("node-web-audio-api:onstatechange")?; let statechange_cb = js_this.get_property(k_onstatechange).unwrap(); let context_clone = Arc::clone(&napi_context.0); diff --git a/src/audio_render_capacity.rs b/src/audio_render_capacity.rs index 63db4f3f..e0c32314 100644 --- a/src/audio_render_capacity.rs +++ b/src/audio_render_capacity.rs @@ -97,7 +97,7 @@ fn listen_to_events(ctx: CallContext) -> Result { let napi_node = ctx.env.unwrap::(&js_this)?; let node = napi_node.unwrap(); - let k_onupdate = crate::utils::get_symbol_for(ctx.env, "node-web-audio-api:onupdate"); + let k_onupdate = ctx.env.symbol_for("node-web-audio-api:onupdate")?; let update_cb = js_this.get_property(k_onupdate).unwrap(); let mut update_tsfn = ctx.env.create_threadsafe_function( &update_cb, diff --git a/src/constant_source_node.rs b/src/constant_source_node.rs index 78752991..ae55fbef 100644 --- a/src/constant_source_node.rs +++ b/src/constant_source_node.rs @@ -136,7 +136,7 @@ fn listen_to_ended_event( use napi::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunctionCallMode}; use web_audio_api::Event; - let k_onended = crate::utils::get_symbol_for(env, "node-web-audio-api:onended"); + let k_onended = env.symbol_for("node-web-audio-api:onended")?; let ended_cb = js_this.get_property(k_onended).unwrap(); let mut ended_tsfn = env.create_threadsafe_function(&ended_cb, 0, |ctx: ThreadSafeCallContext| { diff --git a/src/offline_audio_context.rs b/src/offline_audio_context.rs index 3db04b7a..c89e02c5 100644 --- a/src/offline_audio_context.rs +++ b/src/offline_audio_context.rs @@ -101,7 +101,7 @@ fn start_rendering(ctx: CallContext) -> Result { let napi_context = ctx.env.unwrap::(&js_this)?; let context = napi_context.unwrap(); - let k_onstatechange = crate::utils::get_symbol_for(ctx.env, "node-web-audio-api:onstatechange"); + let k_onstatechange = ctx.env.symbol_for("node-web-audio-api:onstatechange")?; let statechange_cb = js_this.get_property(k_onstatechange).unwrap(); let mut statechange_tsfn = ctx.env.create_threadsafe_function( &statechange_cb, @@ -122,7 +122,7 @@ fn start_rendering(ctx: CallContext) -> Result { statechange_tsfn.call(Ok(e), ThreadsafeFunctionCallMode::Blocking); }); - let k_oncomplete = crate::utils::get_symbol_for(ctx.env, "node-web-audio-api:oncomplete"); + let k_oncomplete = ctx.env.symbol_for("node-web-audio-api:oncomplete")?; let complete_cb = js_this.get_property(k_oncomplete).unwrap(); let context_clone = Arc::clone(&napi_context.0); diff --git a/src/oscillator_node.rs b/src/oscillator_node.rs index 4e85e1e4..f4790c04 100644 --- a/src/oscillator_node.rs +++ b/src/oscillator_node.rs @@ -228,7 +228,7 @@ fn listen_to_ended_event(env: &Env, js_this: &JsObject, node: &mut OscillatorNod use napi::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunctionCallMode}; use web_audio_api::Event; - let k_onended = crate::utils::get_symbol_for(env, "node-web-audio-api:onended"); + let k_onended = env.symbol_for("node-web-audio-api:onended")?; let ended_cb = js_this.get_property(k_onended).unwrap(); let mut ended_tsfn = env.create_threadsafe_function(&ended_cb, 0, |ctx: ThreadSafeCallContext| { diff --git a/src/script_processor_node.rs b/src/script_processor_node.rs index 6be54794..d7f681d6 100644 --- a/src/script_processor_node.rs +++ b/src/script_processor_node.rs @@ -130,8 +130,7 @@ fn listen_to_events(ctx: CallContext) -> Result { let napi_node = ctx.env.unwrap::(&js_this)?; let node = napi_node.unwrap(); - let k_onaudioprocess = - crate::utils::get_symbol_for(ctx.env, "node-web-audio-api:onaudioprocess"); + let k_onaudioprocess = ctx.env.symbol_for("node-web-audio-api:onaudioprocess")?; let audioprocess_cb: JsFunction = js_this.get_property(k_onaudioprocess).unwrap(); let audioprocess_tsfn = ThreadsafeFunctionPatched::create( diff --git a/src/utils/mod.rs b/src/utils/mod.rs index f793b04a..d59f3252 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,20 +1,10 @@ -use napi::{Env, JsFunction, JsObject, JsSymbol, Result}; +use napi::{Env, JsFunction, JsObject, Result}; // alternative implementation of Napi ThreadsafeFunction -// cf. // cf. https://github.com/parcel-bundler/lightningcss/blob/master/napi/src/threadsafe_function.rs +// cf. https://github.com/parcel-bundler/lightningcss/blob/master/napi/src/threadsafe_function.rs mod thread_safe_function; pub(crate) use thread_safe_function::*; -// cf. https://users.rust-lang.org/t/vec-f32-to-u8/21522/7 -#[allow(clippy::needless_lifetimes)] -pub(crate) fn to_byte_slice<'a>(floats: &'a [f32]) -> &'a [u8] { - unsafe { std::slice::from_raw_parts(floats.as_ptr() as *const _, floats.len() * 4) } -} - -pub(crate) fn get_symbol_for(env: &Env, name: &str) -> JsSymbol { - env.symbol_for(name).unwrap() -} - pub(crate) fn get_class_ctor(env: &Env, name: &str) -> Result { let store_ref: &mut napi::Ref<()> = env.get_instance_data()?.unwrap(); let store: JsObject = env.get_reference_value(store_ref)?; diff --git a/src/wave_shaper_node.rs b/src/wave_shaper_node.rs index c893498b..a7101a8a 100644 --- a/src/wave_shaper_node.rs +++ b/src/wave_shaper_node.rs @@ -204,18 +204,23 @@ fn get_curve(ctx: CallContext) -> Result { if let Some(arr_f32) = value { let length = arr_f32.len(); - let arr_u8 = crate::utils::to_byte_slice(arr_f32); - - Ok(ctx - .env - .create_arraybuffer_with_data(arr_u8.to_vec()) - .map(|array_buffer| { - array_buffer - .into_raw() - .into_typedarray(TypedArrayType::Float32, length, 0) - }) - .unwrap()? - .into_unknown()) + + let array_buffer = ctx.env.create_arraybuffer(length * 4).unwrap(); + let js_typed_array = + array_buffer + .into_raw() + .into_typedarray(TypedArrayType::Float32, length, 0)?; + + let mut js_typed_array_value = js_typed_array.into_value()?; + let buffer: &mut [f32] = js_typed_array_value.as_mut(); + buffer.copy_from_slice(arr_f32); + + let js_typed_array = + js_typed_array_value + .arraybuffer + .into_typedarray(TypedArrayType::Float32, length, 0)?; + + Ok(js_typed_array.into_unknown()) } else { Ok(ctx.env.get_null()?.into_unknown()) } diff --git a/tests/WaveShaper.spec.mjs b/tests/WaveShaper.spec.mjs new file mode 100644 index 00000000..35e2ee93 --- /dev/null +++ b/tests/WaveShaper.spec.mjs @@ -0,0 +1,21 @@ +import { assert } from 'chai'; +import { AudioContext } from '../index.mjs'; + +describe('# WaveShaper', () => { + describe('## curve', () => { + it('getter should return a copy of the given curve', async () => { + const context = new AudioContext({}); + const curve = new Float32Array([-1, -0.5, 0, 0.5, 1]); + + const ws = context.createWaveShaper(); + ws.curve = curve; + + // same content + assert.deepEqual(curve, ws.curve); + // not the same instance + assert.notStrictEqual(curve, ws.curve); + + await context.close(); + }); + }); +});