From cb3183af6075e402b925bf00c4450bc4ad8acb14 Mon Sep 17 00:00:00 2001 From: dreamer Date: Sun, 22 Sep 2024 10:10:57 +0200 Subject: [PATCH 01/38] add DPF types; simplify midi docs --- docs/03.gen.dpf.md | 25 +++-- docs/04.midi.md | 260 ++------------------------------------------- 2 files changed, 25 insertions(+), 260 deletions(-) diff --git a/docs/03.gen.dpf.md b/docs/03.gen.dpf.md index 7ce5d0b4..22ce4fcf 100644 --- a/docs/03.gen.dpf.md +++ b/docs/03.gen.dpf.md @@ -22,21 +22,32 @@ Additionally you can use the special `[r __hv_dpf_bpm]` receiver to get the curr ## Parameter Types -In DPF a parameter can get an optional type configured. The default type is `float`. Other assignable types are `bool` - for toggling a value - and `trig` - for momentary signals. +In DPF a parameter can get an optional type configured. The default type is `float`. + +Other assignable types are `int` - or whole numbers, `bool` - for toggling a value, and `trig` - for momentary signals. ![dpf](img/docs_param_type.png) Using jinja the `v.attributes.type` can be evaluated for a specific string and different templating applied to the parameter. In DPF the extra types `bool` and `trig` result in the following plugin code: ```c++ - parameter.hints = kParameterIsAutomable | kParameterIsBoolean; + parameter.hints = kParameterIsInteger +// or + parameter.hints = kParameterIsBoolean; // or - parameter.hints = kParameterIsAutomable | kParameterIsTrigger; + parameter.hints = kParameterIsTrigger; ``` +Other special types can give additional information to the host: + +* `dB` - unit `dB` - min_value `-inf` label (assumes `0.0f`) +* `Hz` - unit `Hz` +* `log` - hints `kParameterIsLogarithmic` +* `log_hz` - unit `Hz` - hints `kParameterIsLogarithmic` + ## Metadata -An accomponying metadata.json file can be included to set additional plugin settings. +An accompanying metadata.json file can be included to set additional plugin settings. The `project` flag creates a `README.md` and `Makefile` in the root of the project output, but may conflict with other generators. @@ -55,7 +66,7 @@ Each of these are optional and have either a default value or are entirely optio "midi_input": 1, "midi_output": 0, "plugin_formats": [ - "lv2_dsp", + "lv2_sep", "vst2", "vst3", "clap", @@ -67,7 +78,7 @@ Each of these are optional and have either a default value or are entirely optio Other fields that the DPF metadata supports are: -* `port_groups` - If your plugin has more audio i/o that need to be grouped together. +* `port_groups` - If your plugin has more audio i/o that need to be grouped together or given Control Voltage status * `enumerators` - Configure a set of parameters that cycle over `: ` * `enable_ui` - Boolean that creates a generic GUI. Requires `dpf-widgets` on the same level as `dpf`. * `enable_modgui` - Boolean for use in MOD audio based systems. @@ -77,6 +88,8 @@ Other fields that the DPF metadata supports are: * `vst3_info` - String describing the VST3 plugin type. * `clap_info` - List of strings describing the CLAP plugin type. +The full type specification can be found [here](https://github.com/Wasted-Audio/hvcc/blob/develop/hvcc/generators/types/meta.py). + An example plugin that uses some of these extended metadata is [WSTD 3Q](https://github.com/Wasted-Audio/wstd-3q). ## Notes diff --git a/docs/04.midi.md b/docs/04.midi.md index 0f66212b..6599092e 100644 --- a/docs/04.midi.md +++ b/docs/04.midi.md @@ -1,6 +1,6 @@ -# MIDI I/O +# MIDI I/O -In PureData there are objects to handle interfacing with a machines MIDI device. +In PureData there are several objects to handle interfacing with MIDI. **heavy** doesn't provide cross-platform implementation for MIDI I/O as the requirements tend to change depending on the platform or framework being used. @@ -50,138 +50,11 @@ Here's the `DPF` implementation as an example. ## Handling MIDI Input -The MIDI input is called during the DPF `run()` loop where it receives `MidiEvent` messages: +The MIDI input is called during the DPF `run()` loop where it receives `MidiEvent` messages. -```cpp -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT -// ------------------------------------------------------------------- -// Midi Input handler - -void {{class_name}}::handleMidiInput(uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) -{ - // Realtime events - // TODO: Continue and Reset - - const TimePosition& timePos(getTimePosition()); - const bool playing = timePos.playing; - if (playing != wasPlaying) - { - if (playing) - { - _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, - "ff", (float) MIDI_RT_START); - } else { - _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, - "ff", (float) MIDI_RT_STOP); - } - wasPlaying = playing; - } - - if (playing && timePos.bbt.valid) - { - float samplesPerBeat = 60 * getSampleRate() / timePos.bbt.beatsPerMinute; - float samplesPerTick = samplesPerBeat / 24.0; - - int i = 1; - while (samplesProcessed > samplesPerTick) - { - _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, i * 1000.0*samplesPerTick/getSampleRate(), - "ff", (float) MIDI_RT_CLOCK); - samplesProcessed -= samplesPerTick; - i++; - } - samplesProcessed += frames; - // printf("> ticks: %f - samples: %f \n", samplesPerTick, samplesProcessed); - } - - // Midi events - for (uint32_t i=0; i < midiEventCount; ++i) - { - int status = midiEvents[i].data[0]; - int command = status & 0xF0; - int channel = status & 0x0F; - int data1 = midiEvents[i].data[1]; - int data2 = midiEvents[i].data[2]; +[Source code (run loop)](https://github.com/Wasted-Audio/hvcc/blob/develop/hvcc/generators/c2dpf/templates/HeavyDPF.cpp#L201-L205) - // raw [midiin] messages - int dataSize = *(&midiEvents[i].data + 1) - midiEvents[i].data; - - for (int i = 0; i < dataSize; ++i) { - _context->sendMessageToReceiverV(HV_HASH_MIDIIN, 1000.0*timePos.frame/getSampleRate(), "ff", - (float) midiEvents[i].data[i], - (float) channel); - } - - if(mrtSet.find(status) != mrtSet.end()) - { - _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 1000.0*timePos.frame/getSampleRate(), - "ff", (float) status); - } - - // typical midi messages - switch (command) { - case 0x80: { // note off - _context->sendMessageToReceiverV(HV_HASH_NOTEIN, 1000.0*timePos.frame/getSampleRate(), "fff", - (float) data1, // pitch - (float) 0, // velocity - (float) channel); - break; - } - case 0x90: { // note on - _context->sendMessageToReceiverV(HV_HASH_NOTEIN, 1000.0*timePos.frame/getSampleRate(), "fff", - (float) data1, // pitch - (float) data2, // velocity - (float) channel); - break; - } - case 0xB0: { // control change - _context->sendMessageToReceiverV(HV_HASH_CTLIN, 1000.0*timePos.frame/getSampleRate(), "fff", - (float) data2, // value - (float) data1, // cc number - (float) channel); - break; - } - case 0xC0: { // program change - _context->sendMessageToReceiverV(HV_HASH_PGMIN, 1000.0*timePos.frame/getSampleRate(), "ff", - (float) data1, - (float) channel); - break; - } - case 0xD0: { // aftertouch - _context->sendMessageToReceiverV(HV_HASH_TOUCHIN, 1000.0*timePos.frame/getSampleRate(), "ff", - (float) data1, - (float) channel); - break; - } - case 0xE0: { // pitch bend - // combine 7bit lsb and msb into 32bit int - hv_uint32_t value = (((hv_uint32_t) data2) << 7) | ((hv_uint32_t) data1); - _context->sendMessageToReceiverV(HV_HASH_BENDIN, 1000.0*timePos.frame/getSampleRate(), "ff", - (float) value, - (float) channel); - break; - } - default: break; - } - } -} -#endif - - -// ------------------------------------------------------------------- -// DPF Plugin run() loop - -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT -void {{class_name}}::run(const float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) -{ - handleMidiInput(frames, midiEvents, midiEventCount); -#else -void {{class_name}}::run(const float** inputs, float** outputs, uint32_t frames) -{ -#endif - _context->process((float**)inputs, outputs, frames); -} -``` +[Source code (handleMidiInput)](https://github.com/Wasted-Audio/hvcc/blob/develop/hvcc/generators/c2dpf/templates/midiInput.cpp) ## Handling MIDI Output @@ -213,125 +86,4 @@ Pd does not have specific Note Off events, so velocity 0 is assumed to be Note O Bend assumes input values ranged `0 - 16383` for `[bendin]` (normal bend range), however as mentioned before `[bendout]` uses `-8192 to 8191` to stay compatible with pd-vanilla. -```cpp -#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT -// ------------------------------------------------------------------- -// Midi Send handler - -void {{class_name}}::handleMidiSend(uint32_t sendHash, const HvMessage *m) -{ - MidiEvent midiSendEvent; - midiSendEvent.frame = 0; - midiSendEvent.dataExt = nullptr; - - switch(sendHash){ - case HV_HASH_NOTEOUT: // __hv_noteout - { - uint8_t note = hv_msg_getFloat(m, 0); - uint8_t velocity = hv_msg_getFloat(m, 1); - uint8_t ch = hv_msg_getFloat(m, 2); - ch %= 16; // drop any pd "ports" - - midiSendEvent.size = 3; - if (velocity > 0){ - midiSendEvent.data[0] = 0x90 | ch; // noteon - } else { - midiSendEvent.data[0] = 0x80 | ch; // noteoff - } - midiSendEvent.data[1] = note; - midiSendEvent.data[2] = velocity; - - writeMidiEvent(midiSendEvent); - break; - } - case HV_HASH_CTLOUT: - { - uint8_t value = hv_msg_getFloat(m, 0); - uint8_t cc = hv_msg_getFloat(m, 1); - uint8_t ch = hv_msg_getFloat(m, 2); - ch %= 16; - - midiSendEvent.size = 3; - midiSendEvent.data[0] = 0xB0 | ch; // send CC - midiSendEvent.data[1] = cc; - midiSendEvent.data[2] = value; - - writeMidiEvent(midiSendEvent); - break; - } - case HV_HASH_PGMOUT: - { - uint8_t pgm = hv_msg_getFloat(m, 0); - uint8_t ch = hv_msg_getFloat(m, 1); - ch %= 16; - - midiSendEvent.size = 2; - midiSendEvent.data[0] = 0xC0 | ch; // send Program Change - midiSendEvent.data[1] = pgm; - - writeMidiEvent(midiSendEvent); - break; - } - case HV_HASH_TOUCHOUT: - { - uint8_t value = hv_msg_getFloat(m, 0); - uint8_t ch = hv_msg_getFloat(m, 1); - ch %= 16; - - midiSendEvent.size = 2; - midiSendEvent.data[0] = 0xD0 | ch; // send Touch - midiSendEvent.data[1] = value; - - writeMidiEvent(midiSendEvent); - break; - } - case HV_HASH_BENDOUT: - { - uint16_t value = hv_msg_getFloat(m, 0); - uint8_t lsb = value & 0x7F; - uint8_t msb = (value >> 7) & 0x7F; - uint8_t ch = hv_msg_getFloat(m, 1); - ch %= 16; - - midiSendEvent.size = 3; - midiSendEvent.data[0] = 0xE0 | ch; // send Bend - midiSendEvent.data[1] = lsb; - midiSendEvent.data[2] = msb; - - writeMidiEvent(midiSendEvent); - break; - } - case HV_HASH_MIDIOUT: // __hv_midiout - { - const uint8_t numElements = m->numElements; - if (numElements <=4 ) - { - for (int i = 0; i < numElements; ++i) - { - midiSendEvent.data[i] = hv_msg_getFloat(m, i); - } - } - else - { - printf("> we do not support sysex yet \n"); - break; - } - - // unsigned char* rawData = new unsigned char; - // for (int i = 0; i < numElements; ++i) { - // rawData[i] = (uint8_t) hv_msg_getFloat(m, i); - // printf("> data: %d \n", rawData[i]); - // } - - midiSendEvent.size = numElements; - // midiSendEvent.dataExt = (const uint8_t *) rawData; - - writeMidiEvent(midiSendEvent); - break; - } - default: - break; - } -} -#endif -``` +[Source code (handleMidiSend)](https://github.com/Wasted-Audio/hvcc/blob/develop/hvcc/generators/c2dpf/templates/midiOutput.cpp) \ No newline at end of file From 8feda17699c47e800191b4a72bdd16175cb41cfb Mon Sep 17 00:00:00 2001 From: dreamer Date: Thu, 26 Sep 2024 17:23:05 +0200 Subject: [PATCH 02/38] add known limitation --- docs/02.getting_started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/02.getting_started.md b/docs/02.getting_started.md index 087e2412..aa01e25f 100644 --- a/docs/02.getting_started.md +++ b/docs/02.getting_started.md @@ -102,6 +102,6 @@ This list will be continuously epanded to document differences in object behavio * On the `[select]` object it is currently not possible to set the arguments via the right inlet (internally a hardcoded switch_case is used). * Heavy supports remote/send messages, however empty messages are currently removed. So the typical `[; bla 1(` multiline message needs to contain at least something on the first line: `[_; bla 1(`. * `[metro]` and `[timer]` objects do not accept tempo messages or unit arguments. -* `[snapshot~]` does not respond within the same control flow as it executes in signal context. Its output happens on the next audio cycle, so additional care for this control flow needs to be taken into account if you depend on synchronous execution. +* `[snapshot~]` does not respond within the same control flow as it executes in signal context. Its output happens on the next audio cycle, so additional care for this control flow needs to be taken into account if you depend on synchronous execution. It also doesn't accept `[set(` messages. * Certain filters are sensitive to ‘blowing up’ at very low or very high cutoff frequencies and/or resonances, due to the filter coefficients not being perfectly represented with a finite number of bits. While Pure data natively uses 64 bits, platforms like `OWL` and `Daisy` that use 32 bit float are more sensitive to this. For example, the Pure data `[bp~]` filter is implemented with a biquad which is prone to fail or distort with cutoff frequencies less than around 200 Hz (at 48kHz sample rate). * Heavy does not support multichannel connections. From e6d2b9361ea3d46ba762fb207946d693adeb2498 Mon Sep 17 00:00:00 2001 From: dreamer <1185977+dromer@users.noreply.github.com> Date: Thu, 26 Sep 2024 23:00:55 +0200 Subject: [PATCH 03/38] Use poetry to manage project settings and provide pyinstaller build (#199) * try using poetry and poetry build. fix application_path for executable * cleanup pyproject.toml * add arch value for macOS * use typehint for older pythons * switch macOS to x86_64 * add metadata * use pyproject.toml * update changelog * remove setup.cfg * use requirements export from poetry * update python action * use specific numpy+scipy versions --- .bumpversion.cfg | 3 +- .github/workflows/build.yml | 4 +- CHANGELOG.md | 7 + hvcc/__init__.py | 8 +- hvcc/core/hv2ir/HeavyLangObject.py | 2 +- poetry.lock | 775 +++++++++++++++++++++++++++++ pyproject.toml | 57 +++ requirements-test.txt | 23 +- requirements.txt | 10 +- setup.cfg | 33 -- setup.py | 3 - tests/test_unity.py | 158 ------ tox.ini | 12 +- 13 files changed, 889 insertions(+), 206 deletions(-) create mode 100644 poetry.lock create mode 100644 pyproject.toml delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 tests/test_unity.py diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 9d2d9db5..5aa2a3b4 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,7 +1,8 @@ [bumpversion] current_version = 0.12.1 -[bumpversion:file:setup.cfg] +[bumpversion:file:pyproject.toml] +search = {current_version} [bumpversion:file:CHANGELOG.md] search = Next Release diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f7cf8353..088a0bcc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,12 +21,12 @@ jobs: - name: Initialize lfs run: git lfs pull - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip + python -m pip install --upgrade pip setuptools wheel pip install tox tox-gh-actions - name: Run tox run: tox diff --git a/CHANGELOG.md b/CHANGELOG.md index 39887ddb..1ca81b72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ CHANGELOG ===== +Next Release +----- + +Features: + +* migrating to poetry for project management + 0.12.1 ----- diff --git a/hvcc/__init__.py b/hvcc/__init__.py index d7434baf..5c384ad6 100644 --- a/hvcc/__init__.py +++ b/hvcc/__init__.py @@ -270,10 +270,16 @@ def compile_dataflow( patch_name = hvir["name"]["escaped"] externs = generate_extern_info(hvir, results) + # get application path + if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'): + application_path = os.path.join(sys._MEIPASS, 'hvcc') + elif __file__: + application_path = os.path.dirname(__file__) + c_src_dir = os.path.join(out_dir, "c") results["ir2c"] = ir2c.ir2c.compile( hv_ir_path=os.path.join(results["hv2ir"]["out_dir"], results["hv2ir"]["out_file"]), - static_dir=os.path.join(os.path.dirname(__file__), "generators/ir2c/static"), + static_dir=os.path.join(application_path, "generators/ir2c/static"), output_dir=c_src_dir, externs=externs, copyright=copyright, diff --git a/hvcc/core/hv2ir/HeavyLangObject.py b/hvcc/core/hv2ir/HeavyLangObject.py index f8d3b40f..0a60df45 100644 --- a/hvcc/core/hv2ir/HeavyLangObject.py +++ b/hvcc/core/hv2ir/HeavyLangObject.py @@ -242,7 +242,7 @@ def remove_connection(self, c: Connection) -> None: else: raise HeavyException(f"Connection {c} does not connect to this object {self}.") - def replace_connection(self, c: Connection, n_list: list) -> None: + def replace_connection(self, c: Connection, n_list: List) -> None: """ Replaces connection c with connection list n_list, maintaining connection order """ if c.from_object is self: diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..f6afe73a --- /dev/null +++ b/poetry.lock @@ -0,0 +1,775 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.6.1" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, + {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, + {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, + {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, + {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "flake8" +version = "7.1.1" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"}, + {file = "flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.12.0,<2.13.0" +pyflakes = ">=3.2.0,<3.3.0" + +[[package]] +name = "importlib-resources" +version = "6.4.5" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717"}, + {file = "importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065"}, +] + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy" +version = "1.11.2" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"}, + {file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"}, + {file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"}, + {file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"}, + {file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"}, + {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"}, + {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"}, + {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"}, + {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"}, + {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, + {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, + {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, + {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, + {file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"}, + {file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"}, + {file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"}, + {file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"}, + {file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"}, + {file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"}, + {file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"}, + {file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"}, + {file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"}, + {file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"}, + {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, + {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "numpy" +version = "1.24.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, + {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, + {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, + {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, + {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, + {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, + {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, + {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, + {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, + {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, + {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, +] + +[[package]] +name = "numpy" +version = "2.0.2" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"}, + {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"}, + {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a"}, + {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669"}, + {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951"}, + {file = "numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9"}, + {file = "numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15"}, + {file = "numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4"}, + {file = "numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c"}, + {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692"}, + {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a"}, + {file = "numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c"}, + {file = "numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded"}, + {file = "numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5"}, + {file = "numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729"}, + {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1"}, + {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd"}, + {file = "numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d"}, + {file = "numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d"}, + {file = "numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa"}, + {file = "numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385"}, + {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"}, +] + +[[package]] +name = "packaging" +version = "24.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pycodestyle" +version = "2.12.1" +description = "Python style guide checker" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"}, + {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"}, +] + +[[package]] +name = "pydantic" +version = "2.9.2" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, + {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.23.4" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] + +[[package]] +name = "pydantic-core" +version = "2.23.4" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, + {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, + {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, + {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, + {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, + {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, + {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, + {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, + {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, + {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, + {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, + {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, + {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, + {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pyflakes" +version = "3.2.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, +] + +[[package]] +name = "pytest" +version = "8.3.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "5.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "scipy" +version = "1.10.1" +description = "Fundamental algorithms for scientific computing in Python" +optional = false +python-versions = "<3.12,>=3.8" +files = [ + {file = "scipy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7354fd7527a4b0377ce55f286805b34e8c54b91be865bac273f527e1b839019"}, + {file = "scipy-1.10.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4b3f429188c66603a1a5c549fb414e4d3bdc2a24792e061ffbd607d3d75fd84e"}, + {file = "scipy-1.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1553b5dcddd64ba9a0d95355e63fe6c3fc303a8fd77c7bc91e77d61363f7433f"}, + {file = "scipy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c0ff64b06b10e35215abce517252b375e580a6125fd5fdf6421b98efbefb2d2"}, + {file = "scipy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:fae8a7b898c42dffe3f7361c40d5952b6bf32d10c4569098d276b4c547905ee1"}, + {file = "scipy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f1564ea217e82c1bbe75ddf7285ba0709ecd503f048cb1236ae9995f64217bd"}, + {file = "scipy-1.10.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d925fa1c81b772882aa55bcc10bf88324dadb66ff85d548c71515f6689c6dac5"}, + {file = "scipy-1.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaea0a6be54462ec027de54fca511540980d1e9eea68b2d5c1dbfe084797be35"}, + {file = "scipy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15a35c4242ec5f292c3dd364a7c71a61be87a3d4ddcc693372813c0b73c9af1d"}, + {file = "scipy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:43b8e0bcb877faf0abfb613d51026cd5cc78918e9530e375727bf0625c82788f"}, + {file = "scipy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5678f88c68ea866ed9ebe3a989091088553ba12c6090244fdae3e467b1139c35"}, + {file = "scipy-1.10.1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:39becb03541f9e58243f4197584286e339029e8908c46f7221abeea4b749fa88"}, + {file = "scipy-1.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bce5869c8d68cf383ce240e44c1d9ae7c06078a9396df68ce88a1230f93a30c1"}, + {file = "scipy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07c3457ce0b3ad5124f98a86533106b643dd811dd61b548e78cf4c8786652f6f"}, + {file = "scipy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:049a8bbf0ad95277ffba9b3b7d23e5369cc39e66406d60422c8cfef40ccc8415"}, + {file = "scipy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cd9f1027ff30d90618914a64ca9b1a77a431159df0e2a195d8a9e8a04c78abf9"}, + {file = "scipy-1.10.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:79c8e5a6c6ffaf3a2262ef1be1e108a035cf4f05c14df56057b64acc5bebffb6"}, + {file = "scipy-1.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51af417a000d2dbe1ec6c372dfe688e041a7084da4fdd350aeb139bd3fb55353"}, + {file = "scipy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b4735d6c28aad3cdcf52117e0e91d6b39acd4272f3f5cd9907c24ee931ad601"}, + {file = "scipy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ff7f37b1bf4417baca958d254e8e2875d0cc23aaadbe65b3d5b3077b0eb23ea"}, + {file = "scipy-1.10.1.tar.gz", hash = "sha256:2cf9dfb80a7b4589ba4c40ce7588986d6d5cebc5457cad2c2880f6bc2d42f3a5"}, +] + +[package.dependencies] +numpy = ">=1.19.5,<1.27.0" + +[package.extras] +dev = ["click", "doit (>=0.36.0)", "flake8", "mypy", "pycodestyle", "pydevtool", "rich-click", "typing_extensions"] +doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] +test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "scipy" +version = "1.13.1" +description = "Fundamental algorithms for scientific computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, + {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, + {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, + {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, + {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, + {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, + {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, + {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, + {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, + {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, + {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, +] + +[package.dependencies] +numpy = ">=1.22.4,<2.3" + +[package.extras] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] +doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] +test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "wstd2daisy" +version = "0.5.3" +description = "A utility for generating Daisy board support files from JSON descriptions" +optional = false +python-versions = ">=3.8" +files = [ + {file = "wstd2daisy-0.5.3-py3-none-any.whl", hash = "sha256:cd566d89bb36ec9fb245acff166f401a71374f044ec8db421a08eedd52bbe07b"}, + {file = "wstd2daisy-0.5.3.tar.gz", hash = "sha256:1cf6bbc6d08cf1f4d36c1aac2f1ca0c7a7b393c49308757bb3f91b05f8cf397a"}, +] + +[package.dependencies] +importlib-resources = {version = "*", markers = "python_version == \"3.8\""} +Jinja2 = ">=2.11" + +[[package]] +name = "zipp" +version = "3.20.2" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8.1" +content-hash = "55bb2a378eb654bbe16dee42ab2d4a286630aa700d3149a6bedfef6587d6205d" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..daa97284 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,57 @@ +[tool.poetry] +name = "hvcc" +version = "0.12.1" +description = "`hvcc` is a python-based dataflow audio programming language compiler that generates C/C++ code and a variety of specific framework wrappers." +authors = ["Enzien Audio, Wasted Audio"] +license = "GPLv3" +readme = "README.md" +documentation = "https://wasted-audio.github.io/hvcc/" +repository = "https://github.com/Wasted-Audio/hvcc" +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Topic :: Software Development :: Compilers", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" +] + +[tool.poetry.scripts] +hvcc = "hvcc:main" +hvutil = "hvcc.utils:main" + +[tool.poetry.dependencies] +python = "^3.8.1" +Jinja2 = ">=2.11" +importlib-resources = ">=5.1" +wstd2daisy = ">=0.5.3" +pydantic = ">=2.9.1" + +[tool.poetry.group.dev.dependencies] +numpy = [ + { version = "^2.0.1", python = "^3.9" }, + { version = "^1.24.3", python = "==3.8"} +] +scipy = [ + { version = "^1.13.1", python = "^3.9"}, + { version = "^1.9.1", python = "==3.8"} +] +pytest-cov = "^5.0.0" +flake8 = "^7.1.1" +mypy = "^1.11.2" +pytest = "^8.3.3" + +[tool.poetry-pyinstaller-plugin] +collect = { all = ["json2daisy"] } +include = { "hvcc/generators" = "hvcc/generators", "hvcc/core" = "hvcc/core", "hvcc/interpreters" = "hvcc/interpreters" } + + +[tool.poetry-pyinstaller-plugin.scripts] +Heavy = { source = "hvcc/__init__.py", type = "onefile", bundle = true, arch = "x86_64" } + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements-test.txt b/requirements-test.txt index ed061e2d..5505c681 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,3 +1,20 @@ -numpy -scipy -requests +colorama==0.4.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and sys_platform == "win32" +coverage[toml]==7.6.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +exceptiongroup==1.2.2 ; python_full_version >= "3.8.1" and python_version < "3.11" +flake8==7.1.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +iniconfig==2.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +mccabe==0.7.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +mypy-extensions==1.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +mypy==1.11.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +numpy==1.24.4 ; python_full_version >= "3.8.1" and python_version == "3.8" +numpy==2.0.2 ; python_version >= "3.9" and python_version < "4.0" +packaging==24.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pluggy==1.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pycodestyle==2.12.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pyflakes==3.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pytest-cov==5.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pytest==8.3.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +scipy==1.10.1 ; python_full_version >= "3.8.1" and python_version == "3.8" +scipy==1.13.1 ; python_version >= "3.9" and python_version < "4.0" +tomli==2.0.1 ; python_full_version >= "3.8.1" and python_full_version <= "3.11.0a6" +typing-extensions==4.12.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" diff --git a/requirements.txt b/requirements.txt index 9c558e35..3fa75315 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,9 @@ -. +annotated-types==0.7.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +importlib-resources==6.4.5 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +jinja2==3.1.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +markupsafe==2.1.5 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pydantic-core==2.23.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pydantic==2.9.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +typing-extensions==4.12.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +wstd2daisy==0.5.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +zipp==3.20.2 ; python_full_version >= "3.8.1" and python_version < "3.10" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 67457688..00000000 --- a/setup.cfg +++ /dev/null @@ -1,33 +0,0 @@ -[metadata] -name = hvcc -version = 0.12.1 -license = GPLv3 -author = Enzien Audio, Wasted Audio -description = `hvcc` is a python-based dataflow audio programming language compiler that generates C/C++ code and a variety of specific framework wrappers. -url = https://github.com/Wasted-Audio/hvcc -download_url = https://github.com/Wasted-Audio/hvcc/archive/refs/tags/v0.12.1.tar.gz -classifiers = - Development Status :: 4 - Beta - Intended Audience :: Developers - Topic :: Software Development :: Compilers - License :: OSI Approved :: GNU General Public License v3 (GPLv3) - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: 3.12 - -[options] -include_package_data = True -packages = find: -python_requires = >= 3.8 -install_requires = - Jinja2>=2.11 - importlib_resources>=5.1 - wstd2daisy>=0.5.3 - pydantic>=2.9.1 - -[options.entry_points] -console_scripts = - hvcc = hvcc:main - hvutil = hvcc.utils:main diff --git a/setup.py b/setup.py deleted file mode 100644 index 60684932..00000000 --- a/setup.py +++ /dev/null @@ -1,3 +0,0 @@ -from setuptools import setup - -setup() diff --git a/tests/test_unity.py b/tests/test_unity.py deleted file mode 100644 index 0c9dcfa4..00000000 --- a/tests/test_unity.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright (C) 2014-2018 Enzien Audio, Ltd. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import os -import requests -import shutil -import subprocess -import sys -import tempfile -import unittest -import zipfile - -# sys.path.append("../") -# import hvcc - -raise unittest.SkipTest() - -sys.path.append("../../../royal/tools") -import uploader # noqa - - -SCRIPT_DIR = os.path.dirname(__file__) -UNITY_TEST_DIR = os.path.join(os.path.dirname(__file__), "unity", "test") - - -class TestUnityPlugins(unittest.TestCase): - - __TEST_TOKEN = "VPwuY6XUCvPKbyjYK3OZ1z01nUbDg1lv" - - # called once before any tests are run - @classmethod - def setUpClass(clazz): - # make temporary directory for downloads - TestUnityPlugins.__OUT_DIR = tempfile.mkdtemp(prefix="TestUnity-") - - exit_code, reply_json = uploader.upload( - input_dir=os.path.join(UNITY_TEST_DIR, "Assets", "Patch"), - output_dirs=[TestUnityPlugins.__OUT_DIR], - name="heavy", - generators="c", - release="dev", - token=TestUnityPlugins.__TEST_TOKEN, - x=False) - - # unittest asserts can only be called on instances - assert exit_code == 0, f"Uploader returned with non-zero exit code: {exit_code}" - assert len(reply_json.get("errors", [])) == 0, reply_json["errors"][0]["detail"] - - TestUnityPlugins.__JOB_URL = reply_json["data"]["links"]["files"]["self"] - - # called once when all tests are done - @classmethod - def tearDownClass(self): - # when everythign is done, delete the temporary output directory - shutil.rmtree(TestUnityPlugins.__OUT_DIR) - - def generate_plugin(self, generator, platform, architecture=None): - """ Ensure that an asset can be downloaded. - """ - - if platform == "src": - url = f"{TestUnityPlugins.__JOB_URL}/{generator}/src/archive.zip" - out_path = os.path.join(TestUnityPlugins.__OUT_DIR, generator, platform, "out.zip") - else: - self.assertIsNotNone(architecture) - url = f"{TestUnityPlugins.__JOB_URL}/{generator}/{platform}/{architecture}/archive.zip" - out_path = os.path.join(TestUnityPlugins.__OUT_DIR, generator, platform, architecture, "out.zip") - - try: - r = requests.get( - url, - cookies={"token": TestUnityPlugins.__TEST_TOKEN}, - timeout=30.0) # maximum request time of 30 seconds - except requests.exceptions.Timeout: - self.fail(f"Request {url} has timed out. Why is it taking so long?") - - # assert that the file could be downloaded - self.assertEqual( - r.status_code, - 200, # assert that we receive HTTPS status code 200 OK - f"Received HTTPS {r.status_code} for {url}. Could not download asset.") - - # make an output directory and write the asset to disk - os.makedirs(os.path.dirname(out_path)) - with open(out_path, "wb") as f: - f.write(r.content) - - return out_path - - def check_unity_log(self, log_file): - """ Checks for and prints certain compiler output messages from a unity generated build log file (-logFile) - """ - with open(log_file, "r") as f: - should_print = False - for line in f.readlines(): - if line.startswith("-----CompilerOutput:"): - should_print = True - - if should_print: - print(line), - - if line.startswith("-----EndCompilerOutput"): - break - - def test_unity(self): - # set up output directory - out_dir = os.path.join(UNITY_TEST_DIR, "Assets", "Plugins") - if os.path.exists(out_dir): - shutil.rmtree(out_dir) - os.makedirs(out_dir) - - # compile patch and extract build results - platform = sys.platform - if platform in ["darwin", "Darwin"]: - unity_app_path = "/Applications/Unity/Unity.app/Contents/MacOS/Unity" - zip_path = self.generate_plugin("unity", "osx", "x86_64") - elif platform in ["windows", "Windows"]: - unity_app_path = "unknown" - zip_path = self.generate_plugin("unity", "win", "x86_64") - else: - self.fail(f"Unsupported test platform ({platform})") - - with (zipfile.ZipFile(zip_path, "r")) as z: - z.extractall(out_dir) - z.close() - - # build unity project - log_file = os.path.join(out_dir, "unity_test_build.log") - cmd = [ - unity_app_path, - "-quit", - "-batchmode", - "-logFile", log_file, - "-projectPath", UNITY_TEST_DIR, - "-executeMethod", "HeavyTestScript.Perform", - "-buildOSXUniversalPlayer", os.path.join(UNITY_TEST_DIR, "build") - ] - try: - subprocess.check_output(cmd) - except subprocess.CalledProcessError as e: - self.check_unity_log(log_file) - self.fail(f"Unity Build failed: ExitCode={e.returncode}, check {log_file} for more info.") - - -if __name__ == "__main__": - print("Usage: $ nose2 test_unity.TestUnityPlugins") diff --git a/tox.ini b/tox.ini index 812a253b..e8864f5e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,7 @@ ; Tox config [tox] envlist = flake8, mypy, py38, py39, py310, py311, py312 +; envlist = py312 skipsdist = true [gh-actions] @@ -14,26 +15,31 @@ python = ; Test config [testenv] deps = - -rrequirements.txt + . -rrequirements-test.txt - pytest-cov commands = python -m pytest --cov-config=tox.ini --cov=hvcc tests/ [testenv:flake8] deps = + -rrequirements-test.txt flake8 basepython = python3 +allowlist_externals = + flake8 commands = flake8 [testenv:mypy] deps = - -rrequirements.txt + . + -rrequirements-test.txt mypy basepython = python3 +allowlist_externals = + mypy commands = mypy hvcc From 344d1083f374cf4ab8751809c1c45394964e203c Mon Sep 17 00:00:00 2001 From: dromer Date: Mon, 30 Sep 2024 12:20:37 +0200 Subject: [PATCH 04/38] document sinesum limitation --- docs/02.getting_started.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/02.getting_started.md b/docs/02.getting_started.md index aa01e25f..36851e50 100644 --- a/docs/02.getting_started.md +++ b/docs/02.getting_started.md @@ -101,6 +101,7 @@ This list will be continuously epanded to document differences in object behavio * Heavy does not accept arguments and control connections to: `[rzero~]`, `[rzero_rev~]`, `[czero~]`, `[czero_rev~]`. In Heavy, these objects accept only signal inputs. Arguments and control connections are ignored. * On the `[select]` object it is currently not possible to set the arguments via the right inlet (internally a hardcoded switch_case is used). * Heavy supports remote/send messages, however empty messages are currently removed. So the typical `[; bla 1(` multiline message needs to contain at least something on the first line: `[_; bla 1(`. +* Remote/send messages with `sinesum` argument to fill tables are not supported. * `[metro]` and `[timer]` objects do not accept tempo messages or unit arguments. * `[snapshot~]` does not respond within the same control flow as it executes in signal context. Its output happens on the next audio cycle, so additional care for this control flow needs to be taken into account if you depend on synchronous execution. It also doesn't accept `[set(` messages. * Certain filters are sensitive to ‘blowing up’ at very low or very high cutoff frequencies and/or resonances, due to the filter coefficients not being perfectly represented with a finite number of bits. While Pure data natively uses 64 bits, platforms like `OWL` and `Daisy` that use 32 bit float are more sensitive to this. For example, the Pure data `[bp~]` filter is implemented with a biquad which is prone to fail or distort with cutoff frequencies less than around 200 Hz (at 48kHz sample rate). From 44ebd6d20d24fff8501f7b5fbc65b01c2d4fde28 Mon Sep 17 00:00:00 2001 From: dreamer Date: Sat, 12 Oct 2024 22:45:17 +0200 Subject: [PATCH 05/38] daisy Makefile template fix --- CHANGELOG.md | 6 +++++- hvcc/generators/c2daisy/templates/Makefile | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ca81b72..ab75b2eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ Features: * migrating to poetry for project management +Bugfixes: + +* Daisy template newline. + 0.12.1 ----- @@ -18,7 +22,7 @@ Features: * DPF: CV flag in portgroups * DPF: flag to disable scoped denormals -Bugfixes +Bugfixes: * wwise: allow Bang messages in OnSendMessageCallback() * Improve `[cos~]` precision. diff --git a/hvcc/generators/c2daisy/templates/Makefile b/hvcc/generators/c2daisy/templates/Makefile index e7327c2c..0b454a74 100644 --- a/hvcc/generators/c2daisy/templates/Makefile +++ b/hvcc/generators/c2daisy/templates/Makefile @@ -4,9 +4,9 @@ TARGET = HeavyDaisy_{{name}} # Library Locations LIBDAISY_DIR = {{libdaisy_path}} -{%- if linker_script != '' %} +{% if linker_script != '' %} LDSCRIPT = {{linker_script}} -{%- endif %} +{% endif %} {% if bootloader != None %} APP_TYPE = {{bootloader}} From bbc19fc2041731f01bc4183d80a133dc041036ec Mon Sep 17 00:00:00 2001 From: dreamer <1185977+dromer@users.noreply.github.com> Date: Sun, 13 Oct 2024 11:52:40 +0200 Subject: [PATCH 06/38] add poetry build step (#201) * add poetry build step * set explicit name to artifact --- .github/workflows/build.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 088a0bcc..e4e8bc10 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,6 +31,32 @@ jobs: - name: Run tox run: tox + binary: + + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + lfs: true + submodules: true + - name: Initialize lfs + run: git lfs pull + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: 3.12 + - name: Install dependencies + run: | + python -m pip install --upgrade pip setuptools wheel + pip install poetry poetry-pyinstaller-plugin + - name: Build binaries + run: poetry build + + - uses: actions/upload-artifact@v4 + with: + name: heavy-binary-linux-x86_64 + path: dist/pyinstaller/manylinux_2_31_x86_64/Heavy + dispatch: needs: build strategy: From 1c6947e42e702729dbfa8f58b53e9b5c9cc4e9a3 Mon Sep 17 00:00:00 2001 From: dreamer Date: Sun, 13 Oct 2024 13:35:06 +0200 Subject: [PATCH 07/38] allow modgui on desktop --- CHANGELOG.md | 5 +++-- hvcc/generators/c2dpf/templates/DistrhoPluginInfo.h | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab75b2eb..23f1e680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,12 @@ Next Release Features: -* migrating to poetry for project management +* Migrating to poetry for project management +* Allow modgui on desktop Bugfixes: -* Daisy template newline. +* Daisy template newline 0.12.1 ----- diff --git a/hvcc/generators/c2dpf/templates/DistrhoPluginInfo.h b/hvcc/generators/c2dpf/templates/DistrhoPluginInfo.h index 16efa07f..a923014f 100644 --- a/hvcc/generators/c2dpf/templates/DistrhoPluginInfo.h +++ b/hvcc/generators/c2dpf/templates/DistrhoPluginInfo.h @@ -52,8 +52,6 @@ {%- endif %} {%- if meta.enable_modgui is sameas true %} -#ifdef __MOD_DEVICES__ #undef DISTRHO_PLUGIN_USES_MODGUI #define DISTRHO_PLUGIN_USES_MODGUI 1 -#endif {%- endif %} From 250a1a1c63ffec7dd45dc55db6f3feccf1044a6e Mon Sep 17 00:00:00 2001 From: dreamer <1185977+dromer@users.noreply.github.com> Date: Sun, 13 Oct 2024 18:37:09 +0200 Subject: [PATCH 08/38] move host transport events to separate template and allow without midi input (#207) * move host transport events to separate template and allow without midi input * make sure we use a float --- CHANGELOG.md | 3 +- hvcc/generators/c2dpf/templates/HeavyDPF.cpp | 2 + hvcc/generators/c2dpf/templates/HeavyDPF.hpp | 1 + .../c2dpf/templates/hostTransportEvents.cpp | 66 +++++++++++++++++++ hvcc/generators/c2dpf/templates/midiInput.cpp | 61 ----------------- .../pd2hv/libs/pd/midirealtimein.pd | 8 +-- 6 files changed, 74 insertions(+), 67 deletions(-) create mode 100644 hvcc/generators/c2dpf/templates/hostTransportEvents.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 23f1e680..a1ceb868 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ Next Release Features: * Migrating to poetry for project management -* Allow modgui on desktop +* DPF: Allow modgui on desktop +* DPF: Allow host transport events without midi input Bugfixes: diff --git a/hvcc/generators/c2dpf/templates/HeavyDPF.cpp b/hvcc/generators/c2dpf/templates/HeavyDPF.cpp index 0d73340c..39844417 100644 --- a/hvcc/generators/c2dpf/templates/HeavyDPF.cpp +++ b/hvcc/generators/c2dpf/templates/HeavyDPF.cpp @@ -193,6 +193,7 @@ void {{class_name}}::setOutputParameter(uint32_t sendHash, const HvMessage *m) #endif {% endif %} +{% include 'hostTransportEvents.cpp' %} // ------------------------------------------------------------------- @@ -206,6 +207,7 @@ void {{class_name}}::run(const float** inputs, float** outputs, uint32_t frames, void {{class_name}}::run(const float** inputs, float** outputs, uint32_t frames) { #endif + hostTransportEvents(frames); {% if meta.denormals is sameas false %} const ScopedDenormalDisable sdd; {% endif %} diff --git a/hvcc/generators/c2dpf/templates/HeavyDPF.hpp b/hvcc/generators/c2dpf/templates/HeavyDPF.hpp index 3ea3aec0..eaeb03d6 100644 --- a/hvcc/generators/c2dpf/templates/HeavyDPF.hpp +++ b/hvcc/generators/c2dpf/templates/HeavyDPF.hpp @@ -47,6 +47,7 @@ class {{class_name}} : public Plugin void handleMidiInput(uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount); void handleMidiSend(uint32_t sendHash, const HvMessage *m); + void hostTransportEvents(uint32_t frames); void setOutputParameter(uint32_t sendHash, const HvMessage *m); protected: diff --git a/hvcc/generators/c2dpf/templates/hostTransportEvents.cpp b/hvcc/generators/c2dpf/templates/hostTransportEvents.cpp new file mode 100644 index 00000000..5e39f313 --- /dev/null +++ b/hvcc/generators/c2dpf/templates/hostTransportEvents.cpp @@ -0,0 +1,66 @@ +// ------------------------------------------------------------------- +// Host Transport Events handler + +void {{class_name}}::hostTransportEvents(uint32_t frames) +{ + // Realtime events + const TimePosition& timePos(getTimePosition()); + bool reset = false; + + if (timePos.playing) + { + if (timePos.frame == 0) + { + _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, + "ff", (float) MIDI_RT_RESET, 0.0); + reset = true; + } + + if (! this->wasPlaying) + { + if (timePos.frame == 0) + { + _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, + "ff", (float) MIDI_RT_START, 0.0); + } + if (! reset) + { + _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, + "ff", (float) MIDI_RT_CONTINUE, 0.0); + } + } + } + else if (this->wasPlaying) + { + _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, + "ff", (float) MIDI_RT_STOP, 0.0); + } + this->wasPlaying = timePos.playing; + + // sending clock ticks + if (timePos.playing && timePos.bbt.valid) + { + float samplesPerBeat = 60 * getSampleRate() / timePos.bbt.beatsPerMinute; + float samplesPerTick = samplesPerBeat / 24.0; + + /* get state */ + double nextClockTick = this->nextClockTick; + double sampleAtCycleStart = this->sampleAtCycleStart; + double sampleAtCycleEnd = sampleAtCycleStart + frames; + + if (nextClockTick >= 0 && sampleAtCycleStart >= 0 && sampleAtCycleEnd > sampleAtCycleStart) { + while (nextClockTick < sampleAtCycleEnd) { + double delayMs = 1000*(nextClockTick - sampleAtCycleStart)/getSampleRate(); + if (delayMs >= 0.0) { + _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, delayMs, + "ff", (float) MIDI_RT_CLOCK, 0.0); + } + nextClockTick += samplesPerTick; + } + } + + /* save variables for next cycle */ + this->sampleAtCycleStart = sampleAtCycleEnd; + this->nextClockTick = nextClockTick; + } +} diff --git a/hvcc/generators/c2dpf/templates/midiInput.cpp b/hvcc/generators/c2dpf/templates/midiInput.cpp index 0fe3ba4c..537333fc 100644 --- a/hvcc/generators/c2dpf/templates/midiInput.cpp +++ b/hvcc/generators/c2dpf/templates/midiInput.cpp @@ -3,67 +3,6 @@ void {{class_name}}::handleMidiInput(uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) { - // Realtime events - const TimePosition& timePos(getTimePosition()); - bool reset = false; - - if (timePos.playing) - { - if (timePos.frame == 0) - { - _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, - "ff", (float) MIDI_RT_RESET); - reset = true; - } - - if (! this->wasPlaying) - { - if (timePos.frame == 0) - { - _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, - "ff", (float) MIDI_RT_START); - } - if (! reset) - { - _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, - "ff", (float) MIDI_RT_CONTINUE); - } - } - } - else if (this->wasPlaying) - { - _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, - "ff", (float) MIDI_RT_STOP); - } - this->wasPlaying = timePos.playing; - - // sending clock ticks - if (timePos.playing && timePos.bbt.valid) - { - float samplesPerBeat = 60 * getSampleRate() / timePos.bbt.beatsPerMinute; - float samplesPerTick = samplesPerBeat / 24.0; - - /* get state */ - double nextClockTick = this->nextClockTick; - double sampleAtCycleStart = this->sampleAtCycleStart; - double sampleAtCycleEnd = sampleAtCycleStart + frames; - - if (nextClockTick >= 0 && sampleAtCycleStart >= 0 && sampleAtCycleEnd > sampleAtCycleStart) { - while (nextClockTick < sampleAtCycleEnd) { - double delayMs = 1000*(nextClockTick - sampleAtCycleStart)/getSampleRate(); - if (delayMs >= 0.0) { - _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, delayMs, - "ff", (float) MIDI_RT_CLOCK); - } - nextClockTick += samplesPerTick; - } - } - - /* save variables for next cycle */ - this->sampleAtCycleStart = sampleAtCycleEnd; - this->nextClockTick = nextClockTick; - } - // Midi events for (uint32_t i=0; i < midiEventCount; ++i) { diff --git a/hvcc/interpreters/pd2hv/libs/pd/midirealtimein.pd b/hvcc/interpreters/pd2hv/libs/pd/midirealtimein.pd index b4579970..6f3d1c68 100644 --- a/hvcc/interpreters/pd2hv/libs/pd/midirealtimein.pd +++ b/hvcc/interpreters/pd2hv/libs/pd/midirealtimein.pd @@ -1,11 +1,9 @@ #N canvas 951 312 204 190 12; -#X obj 87 127 outlet; +#X obj 86 148 outlet; #X obj 20 148 outlet; #X text 23 13 data port; #X obj 20 61 unpack f f; -#X obj 87 94 + 1; #X obj 20 37 r __hv_midirealtimein; #X connect 3 0 1 0; -#X connect 3 1 4 0; -#X connect 4 0 0 0; -#X connect 5 0 3 0; +#X connect 3 1 0 0; +#X connect 4 0 3 0; From 8759c498ed1f6076a1fa18905b21c234d6e4a202 Mon Sep 17 00:00:00 2001 From: dreamer <1185977+dromer@users.noreply.github.com> Date: Mon, 14 Oct 2024 09:23:09 +0200 Subject: [PATCH 09/38] c2js - midi output and device select (#204) * update c2js template for midi device selection * wasm midi_out implemented, no test * scriptprocessornode * clean up shared code * midi_utils * consistency * revert attempt to remove dublicate code, channel bugfix, cleanup * consistency * consistency * changelog and channel --------- Co-authored-by: Reinissance --- CHANGELOG.md | 2 + hvcc/generators/c2js/template/hv_worklet.js | 221 ++++++++++++------ .../c2js/template/hv_worklet_start.js | 2 +- hvcc/generators/c2js/template/hv_wrapper.js | 221 ++++++++++++------ hvcc/generators/c2js/template/index.html | 193 ++++++++++----- 5 files changed, 438 insertions(+), 201 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1ceb868..ad9db6c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ Bugfixes: * Daisy template newline +* JS: midi out and device select + 0.12.1 ----- diff --git a/hvcc/generators/c2js/template/hv_worklet.js b/hvcc/generators/c2js/template/hv_worklet.js index c043f1a4..ab7d597b 100644 --- a/hvcc/generators/c2js/template/hv_worklet.js +++ b/hvcc/generators/c2js/template/hv_worklet.js @@ -108,13 +108,22 @@ class {{name}}_AudioLibWorklet extends AudioWorkletProcessor { var self = this; // typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg); var sendHook = addFunction(function(context, sendName, sendHash, msg) { + // Filter out MIDI messages + const midiMessage = sendMidiOut(UTF8ToString(sendName), msg); + if (midiMessage.length > 0) { + self.port.postMessage({ + type: 'midiOut', + payload: midiMessage + }); + } else { // Converts sendhook callback to (sendName, float) message self.port.postMessage({ type: 'sendHook', payload: [UTF8ToString(sendName), _hv_msg_getFloat(msg, 0)] }); - }, - "viiii" + } + }, + "viiii" ); _hv_setSendHook(this.heavyContext, sendHook); } @@ -132,73 +141,7 @@ class {{name}}_AudioLibWorklet extends AudioWorkletProcessor { } sendMidi(message) { - if (this.heavyContext) { - var command = message[0] & 0xF0; - var channel = message[0] & 0x0F; - var data1 = message[1]; - var data2 = message[2]; - - // all events to [midiin] - for (var i = 1; i <= 2; i++) { - _hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_MIDIIN, 0, - message[i], - channel - ); - } - - // realtime events to [midirealtimein] - if (MIDI_REALTIME.includes(message[0])) { - _hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_MIDIREALTIMEIN, 0, - message[0] - ); - } - - switch(command) { - case 0x80: // note off - _hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_NOTEIN, 0, - data1, - 0, - channel); - break; - case 0x90: // note on - _hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_NOTEIN, 0, - data1, - data2, - channel); - break; - case 0xA0: // polyphonic aftertouch - _hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_POLYTOUCHIN, 0, - data2, // pressure - data1, // note - channel); - break; - case 0xB0: // control change - _hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_CTLIN, 0, - data2, // value - data1, // cc number - channel); - break; - case 0xC0: // program change - _hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_PGMIN, 0, - data1, - channel); - break; - case 0xD0: // aftertouch - _hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_TOUCHIN, 0, - data1, - channel); - break; - case 0xE0: // pitch bend - // combine 7bit lsb and msb into 32bit int - var value = (data2 << 7) | data1; - _hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_BENDIN, 0, - value, - channel); - break; - default: - // console.error('No handler for midi message: ', message); - } - } + sendMidiIn(this.heavyContext, message); } sendStringToReceiver(name, message) { @@ -265,9 +208,145 @@ var tableHashes = { registerProcessor("{{name}}_AudioLibWorklet", {{name}}_AudioLibWorklet); +// midi_utils + +function sendMidiIn(hv_context, message) { + if (hv_context) { + var command = message[0] & 0xF0; + var channel = message[0] & 0x0F; + var data1 = message[1]; + var data2 = message[2]; + + // all events to [midiin] + for (var i = 1; i <= 2; i++) { + _hv_sendMessageToReceiverFF(hv_context, HV_HASH_MIDIIN, 0, + message[i], + channel + ); + } + + // realtime events to [midirealtimein] + if (MIDI_REALTIME.includes(message[0])) { + _hv_sendMessageToReceiverFF(hv_context, HV_HASH_MIDIREALTIMEIN, 0, + message[0] + ); + } + + switch(command) { + case 0x80: // note off + _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_NOTEIN, 0, + data1, + 0, + channel); + break; + case 0x90: // note on + _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_NOTEIN, 0, + data1, + data2, + channel); + break; + case 0xA0: // polyphonic aftertouch + _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_POLYTOUCHIN, 0, + data2, // pressure + data1, // note + channel); + break; + case 0xB0: // control change + _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_CTLIN, 0, + data2, // value + data1, // cc number + channel); + break; + case 0xC0: // program change + _hv_sendMessageToReceiverFF(hv_context, HV_HASH_PGMIN, 0, + data1, + channel); + break; + case 0xD0: // aftertouch + _hv_sendMessageToReceiverFF(hv_context, HV_HASH_TOUCHIN, 0, + data1, + channel); + break; + case 0xE0: // pitch bend + // combine 7bit lsb and msb into 32bit int + var value = (data2 << 7) | data1; + _hv_sendMessageToReceiverFF(hv_context, HV_HASH_BENDIN, 0, + value, + channel); + break; + default: + // console.error('No handler for midi message: ', message); + } + } + } + +function sendMidiOut(sendName, msg) { + switch (sendName) { + case "__hv_noteout": + var note = _hv_msg_getFloat(msg, 0); + var velocity = _hv_msg_getFloat(msg, 1); + var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports + return [ + ((velocity > 0) ? 144 : 128) | channel, + note, + velocity + ] + case "__hv_ctlout": + var value = _hv_msg_getFloat(msg, 0); + var cc = _hv_msg_getFloat(msg, 1); + var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports + return [ + 176 | channel, + cc, + value + ] + case "__hv_pgmout": + var program = _hv_msg_getFloat(msg, 0); + var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports + return [ + 192 | channel, + program + ] + case "__hv_touchout": + var pressure = _hv_msg_getFloat(msg, 0); + var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports + return [ + 208 | channel, + pressure, + ] + case "__hv_polytouchout": + var value = _hv_msg_getFloat(msg, 0); + var note = _hv_msg_getFloat(msg, 1); + var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports + return[ + 160 | channel, + note, + value + ] + case "__hv_bendout": + var value = _hv_msg_getFloat(msg, 0); + let lsb = value & 0x7F; + let msb = (value >> 7) & 0x7F; + var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports + return [ + 224 | channel, + lsb, + msb + ] + case "__hv_midiout": + let firstByte = _hv_msg_getFloat(msg, 0); + return (firstByte === 192 || firstByte === 208) ? + [_hv_msg_getFloat(msg, 0), _hv_msg_getFloat(msg, 1)] : + [_hv_msg_getFloat(msg, 0), _hv_msg_getFloat(msg, 1), _hv_msg_getFloat(msg, 2)]; + default: + console.warn(`Unhandled sendName: ${sendName}`); + return []; + } +} + /* - * MIDI Constants - */ +* MIDI Constants +*/ const HV_HASH_NOTEIN = 0x67E37CA3; const HV_HASH_CTLIN = 0x41BE0f9C; diff --git a/hvcc/generators/c2js/template/hv_worklet_start.js b/hvcc/generators/c2js/template/hv_worklet_start.js index e9cff20d..cb90a8ae 100644 --- a/hvcc/generators/c2js/template/hv_worklet_start.js +++ b/hvcc/generators/c2js/template/hv_worklet_start.js @@ -8,4 +8,4 @@ var self = { function importScripts(){ console.warn('importScripts should not be called in an AudioWorklet', arguments); -} \ No newline at end of file +} diff --git a/hvcc/generators/c2js/template/hv_wrapper.js b/hvcc/generators/c2js/template/hv_wrapper.js index 3b2f85e0..0c4fd981 100644 --- a/hvcc/generators/c2js/template/hv_wrapper.js +++ b/hvcc/generators/c2js/template/hv_wrapper.js @@ -22,6 +22,7 @@ var AudioLibLoader = function() { * @param options.sendHook (Function) callback that gets triggered for messages sent via @hv_param/@hv_event */ AudioLibLoader.prototype.init = function(options) { + // use provided web audio context or create a new one this.webAudioContext = options.webAudioContext || (new (window.AudioContext || window.webkitAudioContext || null)); @@ -43,6 +44,8 @@ AudioLibLoader.prototype.init = function(options) { options.printHook(event.data.payload); } else if (event.data.type === 'sendHook' && options.sendHook) { options.sendHook(event.data.payload[0], event.data.payload[1]); + } else if (event.data.type === 'midiOut' && options.sendHook) { + options.sendHook("midiOutMessage", event.data.payload); } else { console.log('Unhandled message from {{name}}_AudioLibWorklet:', event.data); } @@ -244,8 +247,13 @@ var tableHashes = { if (hook) { // typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg); var sendHook = addFunction(function(context, sendName, sendHash, msg) { - // Converts sendhook callback to (sendName, float) message - hook(UTF8ToString(sendName), _hv_msg_getFloat(msg, 0)); + const midiMessage = sendMidiOut(UTF8ToString(sendName), msg); + if (midiMessage.length > 0) { + hook("midiOutMessage", midiMessage); + } else { + // Converts sendhook callback to (sendName, float) message + hook(UTF8ToString(sendName), _hv_msg_getFloat(msg, 0)); + } }, "viiii" ); @@ -260,73 +268,7 @@ var tableHashes = { } {{name}}_AudioLib.prototype.sendMidi = function(message) { - if (this.heavyContext) { - var command = message[0] & 0xF0; - var channel = message[0] & 0x0F; - var data1 = message[1]; - var data2 = message[2]; - - // all events to [midiin] - for (var i = 1; i <= 2; i++) { - _hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_MIDIIN, 0, - message[i], - channel - ); - } - - // realtime events to [midirealtimein] - if (MIDI_REALTIME.includes(message[0])) { - _hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_MIDIREALTIMEIN, 0, - message[0] - ); - } - - switch(command) { - case 0x80: // note off - _hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_NOTEIN, 0, - data1, - 0, - channel); - break; - case 0x90: // note on - _hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_NOTEIN, 0, - data1, - data2, - channel); - break; - case 0xA0: // polyphonic aftertouch - _hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_POLYTOUCHIN, 0, - data2, // pressure - data1, // note - channel); - break; - case 0xB0: // control change - _hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_CTLIN, 0, - data2, // value - data1, // cc number - channel); - break; - case 0xC0: // program change - _hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_PGMIN, 0, - data1, - channel); - break; - case 0xD0: // aftertouch - _hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_TOUCHIN, 0, - data1, - channel); - break; - case 0xE0: // pitch bend - // combine 7bit lsb and msb into 32bit int - var value = (data2 << 7) | data1; - _hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_BENDIN, 0, - value, - channel); - break; - default: - // console.error('No handler for midi message: ', message); - } - } + sendMidiIn(this.heavyContext, message); } {{name}}_AudioLib.prototype.setFloatParameter = function(name, floatValue) { @@ -368,9 +310,146 @@ var tableHashes = { Module.{{name}}_AudioLib = {{name}}_AudioLib; + +// midi_utils + +function sendMidiIn(hv_context, message) { + if (hv_context) { + var command = message[0] & 0xF0; + var channel = message[0] & 0x0F; + var data1 = message[1]; + var data2 = message[2]; + + // all events to [midiin] + for (var i = 1; i <= 2; i++) { + _hv_sendMessageToReceiverFF(hv_context, HV_HASH_MIDIIN, 0, + message[i], + channel + ); + } + + // realtime events to [midirealtimein] + if (MIDI_REALTIME.includes(message[0])) { + _hv_sendMessageToReceiverFF(hv_context, HV_HASH_MIDIREALTIMEIN, 0, + message[0] + ); + } + + switch(command) { + case 0x80: // note off + _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_NOTEIN, 0, + data1, + 0, + channel); + break; + case 0x90: // note on + _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_NOTEIN, 0, + data1, + data2, + channel); + break; + case 0xA0: // polyphonic aftertouch + _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_POLYTOUCHIN, 0, + data2, // pressure + data1, // note + channel); + break; + case 0xB0: // control change + _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_CTLIN, 0, + data2, // value + data1, // cc number + channel); + break; + case 0xC0: // program change + _hv_sendMessageToReceiverFF(hv_context, HV_HASH_PGMIN, 0, + data1, + channel); + break; + case 0xD0: // aftertouch + _hv_sendMessageToReceiverFF(hv_context, HV_HASH_TOUCHIN, 0, + data1, + channel); + break; + case 0xE0: // pitch bend + // combine 7bit lsb and msb into 32bit int + var value = (data2 << 7) | data1; + _hv_sendMessageToReceiverFF(hv_context, HV_HASH_BENDIN, 0, + value, + channel); + break; + default: + // console.error('No handler for midi message: ', message); + } + } + } + +function sendMidiOut(sendName, msg) { + switch (sendName) { + case "__hv_noteout": + var note = _hv_msg_getFloat(msg, 0); + var velocity = _hv_msg_getFloat(msg, 1); + var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports + return [ + ((velocity > 0) ? 144 : 128) | channel, + note, + velocity + ] + case "__hv_ctlout": + var value = _hv_msg_getFloat(msg, 0); + var cc = _hv_msg_getFloat(msg, 1); + var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports + return [ + 176 | channel, + cc, + value + ] + case "__hv_pgmout": + var program = _hv_msg_getFloat(msg, 0); + var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports + return [ + 192 | channel, + program + ] + case "__hv_touchout": + var pressure = _hv_msg_getFloat(msg, 0); + var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports + return [ + 208 | channel, + pressure, + ] + case "__hv_polytouchout": + var value = _hv_msg_getFloat(msg, 0); + var note = _hv_msg_getFloat(msg, 1); + var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports + return[ + 160 | channel, + note, + value + ] + case "__hv_bendout": + var value = _hv_msg_getFloat(msg, 0); + let lsb = value & 0x7F; + let msb = (value >> 7) & 0x7F; + var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports + return [ + 224 | channel, + lsb, + msb + ] + case "__hv_midiout": + let firstByte = _hv_msg_getFloat(msg, 0); + return (firstByte === 192 || firstByte === 208) ? + [_hv_msg_getFloat(msg, 0), _hv_msg_getFloat(msg, 1)] : + [_hv_msg_getFloat(msg, 0), _hv_msg_getFloat(msg, 1), _hv_msg_getFloat(msg, 2)]; + default: + console.warn(`Unhandled sendName: ${sendName}`); + return []; + } +} + /* - * MIDI Constants - */ +* MIDI Constants +*/ const HV_HASH_NOTEIN = 0x67E37CA3; const HV_HASH_CTLIN = 0x41BE0f9C; diff --git a/hvcc/generators/c2js/template/index.html b/hvcc/generators/c2js/template/index.html index da6cbf82..aadcfc47 100644 --- a/hvcc/generators/c2js/template/index.html +++ b/hvcc/generators/c2js/template/index.html @@ -10,6 +10,7 @@ {% endfor -%}