diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..a4ddebe --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "fable": { + "version": "4.1.4", + "commands": [ + "fable" + ] + }, + "paket": { + "version": "7.2.1", + "commands": [ + "paket" + ] + } + } +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..421c0d8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +# http://editorconfig.org +root = true + +[*.fs] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true + diff --git a/.gitignore b/.gitignore index d12fdd1..c7957a3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,11 @@ Thumbs.db # local vscode settings .vscode/ +# jetbrains ide's +cmake-build-debug + +.idea + # libsamplerate tests Dependencies/libsamplerate/ @@ -17,7 +22,23 @@ Dependencies/libsamplerate/ # used by cmake build/ - +cmake-build-debug # private config (see Config.cmake template) MyConfig.cmake +# dotnet +paket-files +bin +**/obj + + +# rust +Source/rust/target +Source/fsharp/**.fs.rs +Source/fsharp/**.fs.js +Source/fsharp/fable_modules +target + +# generated code +Source/generated +!/Source/generated/foo/Cargo.toml diff --git a/CMakeLists.txt b/CMakeLists.txt index da92454..b1c845e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,14 @@ execute_process( string(TIMESTAMP CURRENT_DATE "%Y-%m-%d") set(PROJECT_DESCRIPTION "ComposeSiren du ${CURRENT_DATE} sur commit n ${GIT_HASH}") +include(FetchContent) +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/AndrewGaspar/corrosion.git + GIT_TAG origin/master # Optionally specify a version tag or branch here +) +FetchContent_MakeAvailable(Corrosion) + project(ComposeSiren VERSION 1.5.0 DESCRIPTION ${PROJECT_DESCRIPTION}) set(BaseTargetName ${PROJECT_NAME}) set(VendorName "Mecanique Vivante") @@ -36,30 +44,30 @@ if (APPLE) endif() juce_add_plugin(${BaseTargetName} - PRODUCT_NAME "${BaseTargetName}" - COMPANY_NAME "${VendorName}" - VERSION ${CMAKE_PROJECT_VERSION} - ICON_BIG "${CMAKE_SOURCE_DIR}/Assets/Icon.png" - ICON_SMALL "${CMAKE_SOURCE_DIR}/Assets/Icon.png" - FORMATS ${FORMATS} - # A four-character manufacturer id with at least one upper-case character - PLUGIN_MANUFACTURER_CODE McVv - # A unique four-character plugin id with at least one upper-case character - PLUGIN_CODE MvCs - IS_SYNTH TRUE # Is this a synth or an effect? - NEEDS_MIDI_INPUT TRUE # Does the plugin need midi input? - NEEDS_MIDI_OUTPUT TRUE # Does the plugin need midi output? - IS_MIDI_EFFECT FALSE # Is this plugin a MIDI effect? - EDITOR_WANTS_KEYBOARD_FOCUS TRUE # Does the editor need keyboard focus? - COPY_PLUGIN_AFTER_BUILD FALSE # Should the plugin be installed to a default location after building? - # VST3_CATEGORIES - # AAX_CATEGORY - # AU_MAIN_TYPE - # COMPANY_WEBSITE https://www.mecanique-vivante.com - # COMPANY_EMAIL - BUNDLE_ID "com.mecaviv.${BaseTargetName}" - PLUGIN_NAME "${BaseTargetName}" - PRODUCT_NAME "${BaseTargetName}" + PRODUCT_NAME "${BaseTargetName}" + COMPANY_NAME "${VendorName}" + VERSION ${CMAKE_PROJECT_VERSION} + ICON_BIG "${CMAKE_SOURCE_DIR}/Assets/Icon.png" + ICON_SMALL "${CMAKE_SOURCE_DIR}/Assets/Icon.png" + FORMATS ${FORMATS} + # A four-character manufacturer id with at least one upper-case character + PLUGIN_MANUFACTURER_CODE McVv + # A unique four-character plugin id with at least one upper-case character + PLUGIN_CODE MvCs + IS_SYNTH TRUE # Is this a synth or an effect? + NEEDS_MIDI_INPUT TRUE # Does the plugin need midi input? + NEEDS_MIDI_OUTPUT TRUE # Does the plugin need midi output? + IS_MIDI_EFFECT FALSE # Is this plugin a MIDI effect? + EDITOR_WANTS_KEYBOARD_FOCUS TRUE # Does the editor need keyboard focus? + COPY_PLUGIN_AFTER_BUILD FALSE # Should the plugin be installed to a default location after building? + # VST3_CATEGORIES + # AAX_CATEGORY + # AU_MAIN_TYPE + # COMPANY_WEBSITE https://www.mecanique-vivante.com + # COMPANY_EMAIL + BUNDLE_ID "com.mecaviv.${BaseTargetName}" + PLUGIN_NAME "${BaseTargetName}" + PRODUCT_NAME "${BaseTargetName}" ) juce_generate_juce_header(${BaseTargetName}) @@ -82,31 +90,37 @@ add_subdirectory(Assets) add_subdirectory(Source) target_link_libraries(${BaseTargetName} - PRIVATE - # copied from projucer project - juce::juce_audio_basics - juce::juce_audio_devices - juce::juce_audio_formats - juce::juce_audio_processors - juce::juce_audio_utils - juce::juce_core - juce::juce_data_structures - juce::juce_events - juce::juce_graphics - juce::juce_gui_basics - juce::juce_gui_extra - # recommended - juce::juce_recommended_warning_flags - juce::juce_recommended_config_flags - juce::juce_recommended_lto_flags + PRIVATE + # copied from projucer project + juce::juce_audio_basics + juce::juce_audio_devices + juce::juce_audio_formats + juce::juce_audio_processors + juce::juce_audio_utils + juce::juce_core + juce::juce_data_structures + juce::juce_events + juce::juce_graphics + juce::juce_gui_basics + juce::juce_gui_extra + # recommended + juce::juce_recommended_warning_flags + juce::juce_recommended_config_flags + juce::juce_recommended_lto_flags ) -target_compile_definitions(${BaseTargetName} - PUBLIC - JUCE_VST3_CAN_REPLACE_VST2=0 - JUCE_WEB_BROWSER=0 +target_compile_definitions(${BaseTargetName} + PUBLIC + JUCE_VST3_CAN_REPLACE_VST2=0 + JUCE_WEB_BROWSER=0 ) + + +corrosion_import_crate(MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Source/rust/Cargo.toml CRATES composesiren-dsp-rs) +target_link_libraries(${BaseTargetName} PUBLIC composesiren-dsp-rs) + + ################################################################################ # packaging @@ -122,4 +136,4 @@ if(APPLE) # we generate a cmake subproject to build the installer include(Packaging/Apple/MakePackage.cmake) elseif(WIN32) # we just proceed the regular way include(Packaging/Windows/MakePackage.cmake) -endif() +endif() \ No newline at end of file diff --git a/Source/fsharp/ComposeSiren.fsproj b/Source/fsharp/ComposeSiren.fsproj new file mode 100644 index 0000000..8598ce3 --- /dev/null +++ b/Source/fsharp/ComposeSiren.fsproj @@ -0,0 +1,17 @@ + + + + net7.0 + true + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/fsharp/composesiren.declarations.fs b/Source/fsharp/composesiren.declarations.fs new file mode 100644 index 0000000..441270d --- /dev/null +++ b/Source/fsharp/composesiren.declarations.fs @@ -0,0 +1,19 @@ +namespace composesiren.declarations +open Fable.Core.Rust +[] +type SirenDataFileSuffix = +| S1 +| S2 +| S3 +| S4 +| S5 +| S7 + +[] +type SirenModel = +| Alto1 +| Alto2 +| Bass +| Tenor +| Soprano +| Piccolo diff --git a/Source/fsharp/composesiren.dsp.fs b/Source/fsharp/composesiren.dsp.fs new file mode 100644 index 0000000..bc5a41c --- /dev/null +++ b/Source/fsharp/composesiren.dsp.fs @@ -0,0 +1,274 @@ +namespace composesiren.dsp + +open composesiren.declarations +//open System.IO +open System.Collections.Generic +open Fable.Core.Rust +(* +type SirenId = + | Piccolo + | AltoS1 + | AltoS2 + | Bass| Tenor |SopranoS5 | SopranoS6 +*) +[] +type SirenModelFileSet = + { + amp : SirenDataFileSuffix + freq: SirenDataFileSuffix + length: SirenDataFileSuffix + vector: SirenDataFileSuffix + } +[] +type FileType = + | Amp + | Freq + | Length + | Vector // deprecated by approximation formula + +module ComposeSirenesLouetteDsp = + + [] + + type ReverbParameterId = + | Size + | DryWet + | Depth + | Width + [] + + type SirenDspParameterId = + //| DspStereoPan of siren: SirenId + | DspGain + | DspPartialCount + | ReverParameter of reverParameter: ReverbParameterId + + [] + + type LengthTable = + { + sample_count: uint32 + max_tab_count: uint16 + average_frequency: float32 + } + + let NOMBRE_DE_NOTE = 80 + + let MAX_Partiel = 200 + + let MAX_TAB = 1000 + +module DspState = + [] + type midi_note_index = midi_note_index of uint8 + [] + type midi_velocity = midi_velocity of uint8 + + [] + type midi_pitchbend = midi_pitchbend of uint16 + [] + type dsp_frame = dsp_frame of uint64 + [] + type VibratoEvent = + | NewVibratoValueSample of frame: dsp_frame * vibratoDepthValue: float + [] + type TremoloEvent = + | NewTremoloValueSample of frame: dsp_frame * tremoloDepthValue: float + [] + type EngineSpeedUpdate = + | LiveMidiNoteOn of note: midi_note_index + | LiveMidiNoteOff of note: midi_note_index + | PitchbendValue of bend: midi_pitchbend + | VibratoEvent of VibratoEvent + + type ShutterUpdateEvent = + | TremoloEvent of TremoloEvent + | LiveMidiNoteOn of note: midi_note_index + | LiveMidiNoteOff of note: midi_note_index + type ShutterState = + { + lastShutterEvent: ShutterUpdateEvent option + } + //| TuningMap // todo v3 + type PitchEvent = + | MidiNote of midi_note_index * midi_velocity // add isOn isOff, for now, if velocity is 0, it is note off + + type EngineSpeed() = + class + end + + [] + + type EngineState = + { + lastPlayedNote: PitchEvent option + currentSpeed: EngineSpeed + } + [] + + type SirenVoiceDspState = + { + pan: float + engineState: EngineState + shutterState: ShutterState + } + [] + type SirenDspState = + { + sirens : SirenVoiceDspState array + + } + +#if false +module Routines = + open ComposeSirenesLouetteDsp + + let sirenmodel_get_file_set (sirenModel: SirenModel) : SirenModelFileSet = + let amp, length, vector, freq = + match sirenModel with + |Alto1 -> (S1, S1, S1, S1) + |Alto2 -> (S1, S1, S2, S1) + |Bass -> (S3, S3, S3, S3) + |Tenor -> (S4, S4, S4, S4) + |Soprano -> (S5, S5, S5, S5) + |Piccolo -> (S7, S7, S5, S7) + { amp=amp + freq=freq + length=length + vector=vector} + + let get_filename_and_buffer_size file (suffix: SirenDataFileSuffix) (directory:DirectoryInfo) = + //let s = sizeof + let filePath, bufferSize = + let amplitudeTable = NOMBRE_DE_NOTE * MAX_TAB * MAX_Partiel + let lengthTable = NOMBRE_DE_NOTE * (*uint32 * uint16 * f32*) 4 * 2 * 4 //sizeof //"" // LengthTable::dim_1() * std::mem::size_of::() * 3) + let dataVectorInterval = (*f32*) 4 * 392 + let frequencyTable = NOMBRE_DE_NOTE * MAX_TAB * MAX_Partiel + match file with + | FileType.Amp -> "dataAmp", amplitudeTable + | FileType.Freq -> "dataFreq", frequencyTable //FrequencyTable::size_of() + | FileType.Length -> "datadureTabs", lengthTable + | FileType.Vector -> "dataVectorInterval", dataVectorInterval //, VectorTable::dim_1() * std::mem::size_of::()) + + let isEqual = 0 = bufferSize % 4 + if not isEqual then + failwith "rustcodetodo: assert_eq!(0, bufferSize % 4)" + + let directoryName = $"filename{file}"// directory.Name + let filePath = directoryName + "/" + filePath + string suffix + filePath, bufferSize + + //type FileMap = System.Collections.Generic.IDictionary,Box>> + type FileMap = System.Collections.Generic.IDictionary> + + + let read_siren_dataset (sirenModel: SirenModel) (folder: DirectoryInfo) (fileMap: FileMap) = + + let fileSet = sirenmodel_get_file_set(sirenModel); + + let readFileAsFloatsVector (f: FileType) (suffix: SirenDataFileSuffix) = + let file_path, buffer_size = get_filename_and_buffer_size(f, suffix, folder) + let fileInfo = FileInfo filePath + let buffer_size = buffer_size / sizeof // std::mem::size_of::(); + let file_size = fileInfo.Length //std::fs::metadata(&file_path).expect("could not get file meta data").len() as usize; + let datafile = + // + failwith $"rustcodetodo: std::fs::File::open(&file_path).expect(&format!( not able to read {fileInfo.FullName})" + //let datafile = BufReader::new(datafile); + (*let mut floats_buffer = { + let mut floats = Vec::::with_capacity(buffer_size); + unsafe { floats.set_len(file_size / std::mem::size_of::()); } + + datafile.read_f32_into::(&mut floats[..]).unwrap(); + floats + }; + if buffer_size != floats_buffer.len() { + eprintln!("expected buffersize:{} got:{} {}", buffer_size, floats_buffer.len(), file_path.as_str()); + floats_buffer.resize(buffer_size, 0.); + } + *) + let float_buffer = () + floats_buffer + + (* + let amp = readFileAsFloatsVector(&FileType::Amp, &fileSet.amp); + let freq = readFileAsFloatsVector(&FileType::Freq, &fileSet.freq); + let length = readFileAsFloatsVector(&FileType::Length, &fileSet.length); + let vector = readFileAsFloatsVector(&FileType::Vector, &fileSet.vector); + + let amp = AmplitudeTable { data: Array3::from_shape_vec((AmplitudeTable::dim_1(), AmplitudeTable::dim_2(), AmplitudeTable::dim_3()), amp).unwrap() }; + let freq = FrequencyTable { data: Array3::from_shape_vec((FrequencyTable::dim_1(), FrequencyTable::dim_2(), FrequencyTable::dim_3()), freq).unwrap() }; + let length = { + let mut v = Vec::::with_capacity(LengthTable::dim_1()); + for n in 0 .. LengthTable::dim_1() { + let (sample_count, max_tab_count, average_frequency) = + (length[n * 3] + , length[n * 3 + 1] + , length[n * 3 + 2]) + ; + let entry = LengthTableEntry { + sample_count: sample_count.round() as u32 + , max_tab_count : max_tab_count.round() as u16 + , average_frequency + }; + v.push(entry); + } + if v.len() < LengthTable::dim_1() { + eprintln!("expected length table of length {} but got {}", LengthTable::dim_1(), v.len()); + } + LengthTable { data: Array1::from_shape_vec(LengthTable::dim_1(), v).unwrap() } + + }; + let vector = VectorTable { data: Array1::from_shape_vec(VectorTable::dim_1(), vector).unwrap() }; + *) + let sirenDataset = + { + amp = amp + freq= freq + length = length + vector = vector + } + sirenDataset +#endif + +//module TestRoutines = +//#[cfg(test)] + + //use std::collections::HashMap; + //use crate::{sirenmodel_get_file_set, read_siren_dataset}; + + //use crate::types::SirenModel::{*}; + //const folder : &str = "/Users/gauthiersegay/dev/src/mecaviv/benoit/CodesSources/ComposeSirenes2/ComposeSirenes/"; + + //[] +#if false + let it_worksreadfiles() = + let map = Dictionary() + let s1 = read_siren_dataset(&crate::types::SirenModel::Alto2, folder, &map); + for v in s1.vector do + //let v = s1.vector.data[i]; + printfn $"{v}" + + + + //[] + let it_works () = + let s1 = sirenmodel_get_file_set(&Alto1) + let s2 = sirenmodel_get_file_set(&Alto2) + let s3 = sirenmodel_get_file_set(&Bass) + let s4 = sirenmodel_get_file_set(&Tenor) + let s5 = sirenmodel_get_file_set(&Soprano) + let s6 = sirenmodel_get_file_set(&Soprano) + let s7 = sirenmodel_get_file_set(&Piccolo) + + printfn $"s1={s1}" + printfn $"s2={s2}" + printfn $"s3={s3}" + printfn $"s4={s4}" + printfn $"s5={s5}" + printfn $"s6={s6}" + printfn $"s7={s7}" + //assert_eq!(2 + 2, 4); + + +#endif \ No newline at end of file diff --git a/Source/fsharp/composesiren.dsp.processor.fs b/Source/fsharp/composesiren.dsp.processor.fs new file mode 100644 index 0000000..fcea0e2 --- /dev/null +++ b/Source/fsharp/composesiren.dsp.processor.fs @@ -0,0 +1,22 @@ +namespace composesiren.dsp.processor + +open composesiren.dsp +open composesiren.dsp.ComposeSirenesLouetteDsp + +open composesiren.dsp.state + +//type SirenDspStqIndex + +type ProcessorState = { + + sirens : SirenOrchestraDspState + +} + +type JuceMidiBuffer = | JuceMidiBuffer + +type UIEvents = + | AdjustSirenControl of parameterooo: SirenDspParameterId * value: uint8 + | MidiEvents of JuceMidiBuffer + | ReplyStateQuery of toCallback : (ProcessorState -> unit) + diff --git a/Source/fsharp/lib.fs b/Source/fsharp/lib.fs new file mode 100644 index 0000000..1c17ba5 --- /dev/null +++ b/Source/fsharp/lib.fs @@ -0,0 +1,12 @@ +namespace composesiren +open Fable.Core.Rust +[] +type SirenLibrary = + { + version: string + } + +module refs_ = + importAll "composesiren.declarations.rs" + importAll "composesiren.dsp.rs" + importAll "composesiren.dsp.processor.rs" \ No newline at end of file diff --git a/Source/fsharp/paket.references b/Source/fsharp/paket.references new file mode 100644 index 0000000..1d37423 --- /dev/null +++ b/Source/fsharp/paket.references @@ -0,0 +1 @@ +Fable.Core \ No newline at end of file diff --git a/Source/fsharp/samples/sample.fs b/Source/fsharp/samples/sample.fs new file mode 100644 index 0000000..b187055 --- /dev/null +++ b/Source/fsharp/samples/sample.fs @@ -0,0 +1,60 @@ +module Programs.sample + +open composesiren.dsp.processor +open composesiren.dsp.state + + +[] +let main args = + let sirens = + [| + composesiren.declarations.Alto1 + composesiren.declarations.Alto2 + composesiren.declarations.Bass + composesiren.declarations.Tenor + composesiren.declarations.Soprano + composesiren.declarations.Soprano + composesiren.declarations.Piccolo + |] + + let engineState = + { + lastPlayedNote = None// PitchEvent option + currentSpeed = EngineSpeed() + } + + let shutterState = { lastShutterEvent = None } + let sirenState = + { + pan = 0. + engineState = engineState + shutterState = shutterState + } + + let orchestra : SirenOrchestraDspState = + { + sirens = + [| + + sirenState + sirenState + sirenState + sirenState + sirenState + sirenState + sirenState + |] + } + let state = + { + ProcessorState.sirens = orchestra + } + + + + + printfn "hello F# into rusdt world?" + printfn "hello F# irrnto rusdt world?" + + + 1 \ No newline at end of file diff --git a/Source/fsharp/samples/sample.fsx b/Source/fsharp/samples/sample.fsx new file mode 100644 index 0000000..29401d4 --- /dev/null +++ b/Source/fsharp/samples/sample.fsx @@ -0,0 +1,54 @@ +#r "bin/Debug/net7.0/ComposeSiren.dll" +open composesiren.dsp.processor +open composesiren.dsp.state + +[] +let main args = + let sirens = + [| + composesiren.declarations.Alto1 + composesiren.declarations.Alto2 + composesiren.declarations.Bass + composesiren.declarations.Tenor + composesiren.declarations.Soprano + composesiren.declarations.Soprano + composesiren.declarations.Piccolo + |] + + let engineState = + { + lastPlayedNote = None// PitchEvent option + currentSpeed = EngineSpeed() + } + + let shutterState = { lastShutterEvent = None } + let sirenState = + { + pan = 0. + engineState = engineState + shutterState = shutterState + } + + let orchestra : SirenOrchestraDspState = + { + sirens = + [| + + sirenState + sirenState + sirenState + sirenState + sirenState + sirenState + sirenState + |] + } + let state = + { + ProcessorState.sirens = orchestra + } + + + + + 1 \ No newline at end of file diff --git a/Source/fsharp/samples/samples.fsproj b/Source/fsharp/samples/samples.fsproj new file mode 100644 index 0000000..79f3506 --- /dev/null +++ b/Source/fsharp/samples/samples.fsproj @@ -0,0 +1,16 @@ + + + + net8.0 + true + + + + + + + + + + + diff --git a/Source/generated/rust/Cargo.toml b/Source/generated/rust/Cargo.toml new file mode 100644 index 0000000..fbe4d70 --- /dev/null +++ b/Source/generated/rust/Cargo.toml @@ -0,0 +1,5 @@ +[workspace] +members = [ + "mecaviv-siren-declarations-rs", + "samples" +] \ No newline at end of file diff --git a/Source/generated/rust/mecaviv-siren-declarations-rs/Cargo.lock b/Source/generated/rust/mecaviv-siren-declarations-rs/Cargo.lock new file mode 100644 index 0000000..303acbb --- /dev/null +++ b/Source/generated/rust/mecaviv-siren-declarations-rs/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "mecaviv-siren-declarations-rs" +version = "0.1.0" diff --git a/Source/generated/rust/mecaviv-siren-declarations-rs/Cargo.toml b/Source/generated/rust/mecaviv-siren-declarations-rs/Cargo.toml new file mode 100644 index 0000000..03c5d9e --- /dev/null +++ b/Source/generated/rust/mecaviv-siren-declarations-rs/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "mecaviv-siren-declarations-rs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +fable_library_rust = { path="src/fable_modules/fable-library-rust" } + + + + +[build-dependencies] +cmake = "*" +cbindgen = "*" \ No newline at end of file diff --git a/Source/generated/rust/samples/Cargo.toml b/Source/generated/rust/samples/Cargo.toml new file mode 100644 index 0000000..4609861 --- /dev/null +++ b/Source/generated/rust/samples/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "samples" +version = "0.0.0" +edition = "2021" + +[[example]] +name = "sample" +path = "sample.rs" + +[dependencies] +fable_library_rust = { path = "../../../fsharp/fable_modules/fable-library-rust/" } +mecaviv-siren-declarations-rs = { path = "../mecaviv-siren-declarations-rs" } \ No newline at end of file diff --git a/Source/rust/Cargo.lock b/Source/rust/Cargo.lock new file mode 100644 index 0000000..48fe5a3 --- /dev/null +++ b/Source/rust/Cargo.lock @@ -0,0 +1,873 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cbindgen" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6358dedf60f4d9b8db43ad187391afe959746101346fe51bb978126bec61dfb" +dependencies = [ + "clap", + "heck", + "indexmap", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 1.0.109", + "tempfile", + "toml", +] + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags", + "clap_lex", + "indexmap", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + +[[package]] +name = "composesiren-dsp-rs-lib" +version = "0.1.0" +dependencies = [ + "bytemuck", + "byteorder", + "cbindgen", + "cmake", + "fable_library_rust", + "lazy_static", + "mecaviv-siren-declarations-rs", + "ndarray", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fable_library_rust" +version = "0.1.0" +dependencies = [ + "chrono", + "getrandom", + "num-bigint", + "num-integer", + "num-traits", + "regex", + "rust_decimal", + "uuid", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "iana-time-zone" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "js-sys" +version = "0.3.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "mecaviv-siren-declarations-rs" +version = "0.1.0" +dependencies = [ + "fable_library_rust", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "ndarray" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "rawpointer", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "os_str_bytes" +version = "6.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" + +[[package]] +name = "proc-macro2" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" + +[[package]] +name = "rust_decimal" +version = "1.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26bd36b60561ee1fb5ec2817f198b6fd09fa571c897a5e86d1487cfc2b096dfc" +dependencies = [ + "arrayvec", + "num-traits", +] + +[[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "serde" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.45.0", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "uuid" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" +dependencies = [ + "getrandom", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.16", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/Source/rust/Cargo.toml b/Source/rust/Cargo.toml new file mode 100644 index 0000000..56a56c4 --- /dev/null +++ b/Source/rust/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "composesiren-dsp-rs-lib" +version = "0.1.0" +edition = "2021" + + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + + +[lib] +crate-type = ["staticlib"] + + +[[bin]] +name = "composesiren-dsp-rs-main" +path = "src/main.rs" +# +[dependencies] +fable_library_rust = { path = "../fsharp/fable_modules/fable-library-rust" } +mecaviv-siren-declarations-rs = { path = "../generated/rust/mecaviv-siren-declarations-rs"} +bytemuck = { version = "*", features = ["extern_crate_alloc"]} +lazy_static = "*" +ndarray = "*" +byteorder = "*" + + +[build-dependencies] +cmake = "*" +cbindgen = "*" \ No newline at end of file diff --git a/Source/rust/build.rs b/Source/rust/build.rs new file mode 100644 index 0000000..8c62085 --- /dev/null +++ b/Source/rust/build.rs @@ -0,0 +1,32 @@ +#![allow(non_snake_case)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(non_upper_case_globals)] +#![allow(unused_variables)] +extern crate cbindgen; + +use std::env; +use std::fs::File; +use std::path::Path; + +fn main() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + run_cbindgen(&crate_dir); +} + +fn run_cbindgen(crate_dir: &String) { + let result = + cbindgen::Builder::new() + .with_crate(crate_dir) + .generate(); + match result { + Ok(bindings) => { + bindings.write_to_file("../generated/ffi/composesirenrs.h"); + println!("generated C binding."); + } + Err(error) => { + println!("failed to do C binding generation: {}", error.to_string()); + } + } +} + diff --git a/Source/rust/src/lib.rs b/Source/rust/src/lib.rs new file mode 100644 index 0000000..4788094 --- /dev/null +++ b/Source/rust/src/lib.rs @@ -0,0 +1,190 @@ +//use composesiren; +//use composesiren::dsp; +//use composesiren::declarations; +//#![feature(type_ascription)] +#![allow(non_snake_case)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(non_upper_case_globals)] +#![allow(unused_variables)] +//pub mod midiinput; +pub mod types; +//pub mod ndarraytests; +//pub mod siren_send; +//pub const midiNoteMin: i32 = 0; +//pub const midiNoteMax: crate::types::midi_note = 127; + +use std::collections::HashMap; +use std::ffi::OsStr; +use std::io::{BufReader, Read}; +use std::iter::Map; +use std::os::raw::c_char; +use std::path::Path; +use std::rc::Rc; +use byteorder::{NativeEndian, ReadBytesExt}; +use crate::types::{AmplitudeTable, FrequencyTable, LengthTable, LengthTableEntry, MAX_Partiel, MAX_TAB, NOMBRE_DE_NOTE, SirenDataFileSuffix, SirenDataSet, SirenModel, SirenModelFileSet, VectorTable}; + +#[no_mangle] +pub extern "C" fn sirenmodel_get_file_set(sirenModel: &SirenModel) -> SirenModelFileSet { + use crate::types::SirenModel::{*}; + + use SirenDataFileSuffix::*; + let (amp, length, vector, freq) = match sirenModel { + Alto1 => (S1, S1, S1, S1), + Alto2 => (S1, S1, S2, S1), + Bass => (S3, S3, S3, S3), + Tenor => (S4, S4, S4, S4), + Soprano => (S5, S5, S5, S5), + Piccolo => (S7, S7, S5, S7), + }; + SirenModelFileSet { amp, + freq, + length, + vector } +} + +#[derive(PartialEq,Eq,Hash)] +enum FileType { + Amp, + Freq, + Length, + Vector, +} +/* +enum FileData { + Amp(Box), + Freq(Box), + Length(Box), + Vector(Box), +}*/ + +fn get_filename_and_buffer_size(f: &FileType, suffix: &SirenDataFileSuffix, folder: &str) -> (String, usize) { + let s = AmplitudeTable::size_of(); + let (filePath, bufferSize) = match f { + FileType::Amp => ("dataAmp", AmplitudeTable::size_of()), + FileType::Freq => ("dataFreq", FrequencyTable::size_of()), + FileType::Length => ("datadureTabs", LengthTable::dim_1() * std::mem::size_of::() * 3), + FileType::Vector => ("dataVectorInterval", VectorTable::dim_1() * std::mem::size_of::()), + }; + assert_eq!(0, bufferSize % 4); + let filePath = + format!("{}{}{}", + folder,filePath, suffix); + + (filePath, bufferSize) +} + +type FileMap = HashMap,Box>>; + + +use lazy_static::lazy_static; +use ndarray::{Array1, Array3}; + +lazy_static! { + static ref PRIVILEGES: HashMap<&'static str, Vec<&'static u8>> = { + let mut map = HashMap::new(); + map + }; +} + + +pub extern "C" fn read_siren_dataset(sirenModel: &SirenModel, folder: &str, mut fileMap: &FileMap) -> SirenDataSet //-> SirenDataSet +{ + let fileSet = sirenmodel_get_file_set(sirenModel); + + let readFileAsFloatsVector = |f: &FileType, suffix: &SirenDataFileSuffix| { + let (file_path, buffer_size) = get_filename_and_buffer_size(f, suffix, folder); + let buffer_size = buffer_size / std::mem::size_of::(); + let file_size = std::fs::metadata(&file_path).expect("could not get file meta data").len() as usize; + let datafile = std::fs::File::open(&file_path).expect(&format!("not able to read {}", file_path)); + let mut datafile = BufReader::new(datafile); + let mut floats_buffer = { + let mut floats = Vec::::with_capacity(buffer_size); + unsafe { floats.set_len(file_size / std::mem::size_of::()); } + + datafile.read_f32_into::(&mut floats[..]).unwrap(); + floats + }; + if buffer_size != floats_buffer.len() { + eprintln!("expected buffersize:{} got:{} {}", buffer_size, floats_buffer.len(), file_path.as_str()); + floats_buffer.resize(buffer_size, 0.); + } + + floats_buffer + }; + + let amp = readFileAsFloatsVector(&FileType::Amp, &fileSet.amp); + let freq = readFileAsFloatsVector(&FileType::Freq, &fileSet.freq); + let length = readFileAsFloatsVector(&FileType::Length, &fileSet.length); + let vector = readFileAsFloatsVector(&FileType::Vector, &fileSet.vector); + + let amp = AmplitudeTable { data: Array3::from_shape_vec((AmplitudeTable::dim_1(), AmplitudeTable::dim_2(), AmplitudeTable::dim_3()), amp).unwrap() }; + let freq = FrequencyTable { data: Array3::from_shape_vec((FrequencyTable::dim_1(), FrequencyTable::dim_2(), FrequencyTable::dim_3()), freq).unwrap() }; + let length = { + let mut v = Vec::::with_capacity(LengthTable::dim_1()); + for n in 0 .. LengthTable::dim_1() { + let (sample_count, max_tab_count, average_frequency) = + (length[n * 3] + , length[n * 3 + 1] + , length[n * 3 + 2]) + ; + let entry = LengthTableEntry { + sample_count: sample_count.round() as u32 + , max_tab_count : max_tab_count.round() as u16 + , average_frequency + }; + v.push(entry); + } + if v.len() < LengthTable::dim_1() { + eprintln!("expected length table of length {} but got {}", LengthTable::dim_1(), v.len()); + } + LengthTable { data: Array1::from_shape_vec(LengthTable::dim_1(), v).unwrap() } + + }; + let vector = VectorTable { data: Array1::from_shape_vec(VectorTable::dim_1(), vector).unwrap() }; + SirenDataSet{ amp, freq, length, vector } + +} +#[cfg(test)] +pub mod tests { + use std::collections::HashMap; + use crate::{sirenmodel_get_file_set, read_siren_dataset}; + + use crate::types::SirenModel::{*}; + const folder : &str = "/Users/gauthiersegay/dev/src/mecaviv/benoit/CodesSources/ComposeSirenes2/ComposeSirenes/"; + #[test] + pub fn a() {} + + #[test] + pub fn it_worksreadfiles() { + let map = HashMap::new(); + let s1 = read_siren_dataset(&crate::types::SirenModel::Alto2, folder, &map); + for i in 0 .. s1.vector.data.len() { + let v = s1.vector.data[i]; + println!("{}", v); + } + } + + #[test] + pub fn it_works() { + let s1 = sirenmodel_get_file_set(&Alto1); + let s2 = sirenmodel_get_file_set(&Alto2); + let s3 = sirenmodel_get_file_set(&Bass); + let s4 = sirenmodel_get_file_set(&Tenor); + let s5 = sirenmodel_get_file_set(&Soprano); + let s6 = sirenmodel_get_file_set(&Soprano); + let s7 = sirenmodel_get_file_set(&Piccolo); + + println!("s1={}", s1); + println!("s2={}", s2); + println!("s3={}", s3); + println!("s4={}", s4); + println!("s5={}", s5); + println!("s6={}", s6); + println!("s7={}", s7); + assert_eq!(2 + 2, 4); + } +} + + + diff --git a/Source/rust/src/main.rs b/Source/rust/src/main.rs new file mode 100644 index 0000000..7baeb4d --- /dev/null +++ b/Source/rust/src/main.rs @@ -0,0 +1,22 @@ +extern crate mecaviv_siren_declarations_rs; + +//use src; +///++.use crate::meaviv_siren_declarations_rs::composesiren::dsp; +//use crate::composesiren::dsp; + +use std::collections::HashMap; +//use composesiren::dsp::SirenModel; +//use mecaviv_siren_declarations_rs::{*}; +//use mecaviv_siren_declarations_rs::composesiren::dsp::processor::{*}; +fn main() { + + let sirens = Default::default(); + let state = mecaviv_siren_declarations_rs::composesiren::DspState::ProcessorState{ sirens: sirens }; + + println!("Hello, world!"); + //let map = HashMap::new(); + let folder = "/Users/gauthiersegay/m1/macbookairm1/Library/Developer/Xcode/DerivedData/ComposeSirenes-docslgnkxmlfdudsoqsmkhkympli/Build/Products/Debug/ComposeSirenes.app/Contents/Resources/"; +//composesiren_dsp_rs::types::SirenModel + //read_siren_dataset(&SirenModel::Alto1, folder, &map); + //libcomposesirendataset::pppp(SirenModel::Alto1, &map); +} \ No newline at end of file diff --git a/Source/rust/src/tests.rs b/Source/rust/src/tests.rs new file mode 100644 index 0000000..db3917b --- /dev/null +++ b/Source/rust/src/tests.rs @@ -0,0 +1,41 @@ + +#[cfg(test)] +pub mod tests { + use std::collections::HashMap; + use crate::{sirenmodel_get_file_set, read_siren_dataset}; + + use crate::types::SirenModel::{*}; + const folder : &str = "/Users/gauthiersegay/dev/src/mecaviv/benoit/CodesSources/ComposeSirenes2/ComposeSirenes/"; + #[test] + pub fn a() {} + + #[test] + pub fn it_worksreadfiles() { + let map = HashMap::new(); + let s1 = read_siren_dataset(&crate::types::SirenModel::Alto2, folder, &map); + for i in 0 .. s1.vector.data.len() { + let v = s1.vector.data[i]; + println!("{}", v); + } + } + + #[test] + pub fn it_works() { + let s1 = sirenmodel_get_file_set(&Alto1); + let s2 = sirenmodel_get_file_set(&Alto2); + let s3 = sirenmodel_get_file_set(&Bass); + let s4 = sirenmodel_get_file_set(&Tenor); + let s5 = sirenmodel_get_file_set(&Soprano); + let s6 = sirenmodel_get_file_set(&Soprano); + let s7 = sirenmodel_get_file_set(&Piccolo); + + println!("s1={}", s1); + println!("s2={}", s2); + println!("s3={}", s3); + println!("s4={}", s4); + println!("s5={}", s5); + println!("s6={}", s6); + println!("s7={}", s7); + assert_eq!(2 + 2, 4); + } +} diff --git a/Source/rust/src/types.rs b/Source/rust/src/types.rs new file mode 100644 index 0000000..bb39fb7 --- /dev/null +++ b/Source/rust/src/types.rs @@ -0,0 +1,122 @@ + +#[repr(C)] +pub enum SirenModel { + Alto1, + Alto2, + Bass, + Tenor, + Soprano, + Piccolo, +} + +#[derive(PartialEq,Eq,Hash)] +#[repr(C)] +pub enum SirenDataFileSuffix { + S1, + S2, + S3, + S4, + S5, + //S6, + S7, +} + +pub const NOMBRE_DE_NOTE: usize = 80; +pub const MAX_Partiel: usize = 200; +pub const MAX_TAB: usize = 1000; + +#[repr(C)] +pub struct Array3D +{ + pub data: ndarray::Array3 + +} + +impl Array3D { + pub fn dim_1 () -> usize { Dim1 } + pub fn dim_2 () -> usize { Dim2 } + pub fn dim_3 () -> usize { Dim3 } + pub fn size_of() -> usize { + std::mem::size_of::() * Dim1 * Dim2 * Dim3 + } +} + +#[repr(C)] +pub struct Array1D +{ + pub data: ndarray::Array1 +} + +impl Array1D{ + pub fn dim_1 () -> usize { Dim1 } + /*fn size_of() -> usize { + std::mem::size_of::() * Dim1 + }*/ +} + +#[repr(C)] +pub struct LengthTableEntry { + pub sample_count: u32 + , pub max_tab_count: u16 + , pub average_frequency: f32 +} + + +pub type AmplitudeTable = Array3D; + +pub type FrequencyTable = Array3D; + +pub type LengthTable = Array1D; + +pub type VectorTable = Array1D; + +//typedef float AmpTable[NOMBRE_DE_NOTE][MAX_TAB][MAX_Partiel]; +//typedef float FreqTable[NOMBRE_DE_NOTE][MAX_TAB][MAX_Partiel]; +//typedef float DurationTable[NOMBRE_DE_NOTE][3]; +//typedef float VectorTable [392]; + +type i7 = i8; +pub type midi_note = i7; + +#[repr(C)] +pub struct SirenDataSet { + pub amp: AmplitudeTable, + pub freq: FrequencyTable, + pub length: LengthTable, + pub vector: VectorTable, +} + +#[repr(C)] +pub struct SirenSpec { + lowest_note: midi_note, + highest_note: midi_note, +} +#[repr(C)] +pub struct SirenModelFileSet { + pub(crate) amp: SirenDataFileSuffix, + pub(crate) freq: SirenDataFileSuffix, + pub(crate) length: SirenDataFileSuffix, + pub(crate) vector: SirenDataFileSuffix, +} + +impl std::fmt::Display for SirenDataFileSuffix { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use SirenDataFileSuffix::*; + let result = match self { + S1 => "S1", + S2 => "S2", + S3 => "S3", + S4 => "S4", + S5 => "S5", + S7 => "S7", + }; + write!(f, "{}", result) + } +} +impl std::fmt::Display for SirenModelFileSet { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, + "SirenDataSet(freq:{},amp:{},length:{},vector:{})", + self.freq, self.amp, self.length, self.vector) + } +} \ No newline at end of file diff --git a/build.dotnet.sh b/build.dotnet.sh new file mode 100755 index 0000000..5ca9ff9 --- /dev/null +++ b/build.dotnet.sh @@ -0,0 +1,10 @@ +dotnet tool restore +dotnet build +dotnet fable Source/fsharp/ComposeSiren.fsproj -o Source/generated/rust/mecaviv-siren-declarations-rs/src --lang rust + +#dotnet fable Source/fsharp/ComposeSiren.fsproj -o Source/generated/python --lang python +# dotnet fable Source/fsharp/ComposeSiren.fsproj -o Source/generated/php --lang php +#dotnet fable Source/fsharp/ComposeSiren.fsproj -o Source/generated/typescript --lang ts +# dotnet fable Source/fsharp/ComposeSiren.fsproj -o Source/generated/dart --lang dart + + diff --git a/build.rust.sh b/build.rust.sh new file mode 100755 index 0000000..0876ac5 --- /dev/null +++ b/build.rust.sh @@ -0,0 +1,5 @@ +bash build.dotnet.sh +cd ./Source/rust +cargo build +cd ../generated/rust/samples +cargo run --example sample \ No newline at end of file diff --git a/dotnet.sln b/dotnet.sln new file mode 100644 index 0000000..abe6725 --- /dev/null +++ b/dotnet.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ComposeSiren", "Source\fsharp\ComposeSiren.fsproj", "{C6CF8E55-F53B-4EF1-A6A4-56D155B88C42}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "samples", "Source\fsharp\samples\samples.fsproj", "{1678588D-72F5-462C-93EF-ACA4ABD18A6A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C6CF8E55-F53B-4EF1-A6A4-56D155B88C42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6CF8E55-F53B-4EF1-A6A4-56D155B88C42}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6CF8E55-F53B-4EF1-A6A4-56D155B88C42}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6CF8E55-F53B-4EF1-A6A4-56D155B88C42}.Release|Any CPU.Build.0 = Release|Any CPU + {1678588D-72F5-462C-93EF-ACA4ABD18A6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1678588D-72F5-462C-93EF-ACA4ABD18A6A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1678588D-72F5-462C-93EF-ACA4ABD18A6A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1678588D-72F5-462C-93EF-ACA4ABD18A6A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/funbuild.fsx b/funbuild.fsx new file mode 100644 index 0000000..9418d46 --- /dev/null +++ b/funbuild.fsx @@ -0,0 +1,43 @@ +#r "nuget: Fun.Result" +#r "nuget: Fun.Build, 0.3.8" + +open Fun.Result +open Fun.Build + +pipeline "Fun.Build" { + description "building f# & rust code" + stage "F#" { + run "dotnet tool restore" + run "dotnet restore" + run "dotnet fable Source/fsharp/ComposeSiren.fsproj -o Source/generated/rust/mecaviv-siren-declarations-rs/src --lang rust" + } + stage "rust" { + workingDir "./Source/rust" + run "cargo build" + } + runIfOnlySpecified false +} + +pipeline "watch" { + description "developer mode watch" + + stage "run" { + run "dotnet fable Source/fsharp/ComposeSiren.fsproj -o Source/generated/rust/mecaviv-siren-declarations-rs/src --lang rust --watch bash build.dotnet.sh" + //workingDir "./Source/generated/Source/generated/rust/mecaviv-siren-declarations-rs/" + //run "cargo build" + } + runIfOnlySpecified + +} +pipeline "run" { + description "running the rust sample program" + + stage "run" { + workingDir "./Source/rust" + run "cargo run" + + } + runIfOnlySpecified +} + +tryPrintPipelineCommandHelp () \ No newline at end of file diff --git a/paket.dependencies b/paket.dependencies new file mode 100644 index 0000000..5f697b0 --- /dev/null +++ b/paket.dependencies @@ -0,0 +1,5 @@ +source https://api.nuget.org/v3/index.json + +storage: none + +nuget Fable.Core \ No newline at end of file diff --git a/watch.sh b/watch.sh new file mode 100755 index 0000000..8233f30 --- /dev/null +++ b/watch.sh @@ -0,0 +1 @@ +dotnet fable watch Source/fsharp/samples/samples.fsproj --lang rust --run bash build.rust \ No newline at end of file