diff --git a/dave/server/languages/c_cpp/__init__.py b/dave/server/languages/c_cpp/__init__.py index 2757acc..457060a 100644 --- a/dave/server/languages/c_cpp/__init__.py +++ b/dave/server/languages/c_cpp/__init__.py @@ -2,3 +2,4 @@ from .std_2D import * from .juce import * from .choc import * +from .hart import * diff --git a/dave/server/languages/c_cpp/hart.py b/dave/server/languages/c_cpp/hart.py new file mode 100644 index 0000000..ab6e49c --- /dev/null +++ b/dave/server/languages/c_cpp/hart.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +import re +from typing import Tuple + +from ...container import SampleType, Container2D +from ...debuggers.value import AbstractValue +from dave.server.languages import c_cpp + +class HartAudioBuffer(Container2D): + __REGEX = rf"^(?:const\s+)?hart::AudioBuffer<{SampleType.regex()}>\s*$" + + def __init__(self, dbg_value: AbstractValue, name: str, _): + typename = dbg_value.typename() + sample_type, *_ = self._parse_typename(typename) + super().__init__(dbg_value, name, sample_type) + + @property + def __inner(self) -> c_cpp.StdVector1D: + return c_cpp.StdVector1D(self._value.attr("m_frames"), self.name + ".m_frames") + + @classmethod + def typename_matcher(cls) -> re.Pattern: + return re.compile(cls.__REGEX) + + @classmethod + def _parse_typename(cls, typename: str, **_) -> Tuple[SampleType, None, None]: + re_match = cls.typename_matcher().match(typename) + if re_match is None: + raise TypeError( + f"HartAudioBuffer could not parse {typename} as a valid type" + ) + + return (SampleType.parse(re_match.group(1)), None, None) + + def shape(self) -> Tuple[int, int]: + assert isinstance(self._value, AbstractValue) + try: + return ( + int(self._value.attr("m_numChannels")), + int(self._value.attr("m_numFrames")) + ) + except: + raise RuntimeError(f"Failed to retrieve shape of {self._value.typename()}") + + def read_from_debugger(self) -> bytearray: + return self.__inner.read_from_debugger() + +HartAudioBuffer.register() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 9be8d1b..ec6e1f9 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -26,6 +26,16 @@ FetchContent_Declare( FetchContent_MakeAvailable(GSL) +set(HART_BUILD_TESTS OFF) +FetchContent_Declare( + HART + GIT_REPOSITORY "https://github.com/daleonov/HART.git" + GIT_TAG 0.1.0 + GIT_SHALLOW ON +) + +FetchContent_MakeAvailable(HART) + ################################################################################ ### stdlib ################################################################################ @@ -89,6 +99,17 @@ add_executable( ) set_target_properties(choc PROPERTIES CXX_STANDARD 17) +################################################################################ +### HART +################################################################################ + +add_executable( + hart + ${CMAKE_CURRENT_SOURCE_DIR}/hart.cpp +) +set_target_properties(hart PROPERTIES CXX_STANDARD 11) +target_link_libraries(hart PRIVATE HART::HART) + ################################################################################ ### Custom containers example ################################################################################ diff --git a/examples/hart.cpp b/examples/hart.cpp new file mode 100644 index 0000000..74f7d5f --- /dev/null +++ b/examples/hart.cpp @@ -0,0 +1,52 @@ +#define HART_IMPLEMENTATION +#include "hart.hpp" + +HART_DECLARE_ALIASES_FOR_FLOAT; +using AudioBuffer = hart::AudioBuffer; +using hart::roundToSizeT; + +int main() +{ + constexpr double sampleRateHz = 44100.0; + + // Sine sweep + const size_t sineSweepDurationFrames = roundToSizeT (sampleRateHz * 1.0_s); + AudioBuffer bufferA (1, sineSweepDurationFrames); + auto sineSweepSignalA = SineSweep(); + sineSweepSignalA.prepare ( + sampleRateHz, + 1, // numOutputChannels + sineSweepDurationFrames // maxBlockSizeFrames + ); + sineSweepSignalA.renderNextBlock (bufferA); + + // A different sweep, overwrites the same buffer + auto sineSweepSignalB = SineSweep() + .withType (SineSweep::SweepType::linear) + .withStartFrequency (100_Hz) + .withEndFrequency (1_Hz) + .withDuration (500_ms) + .withLoop (SineSweep::Loop::yes); + sineSweepSignalB.prepare ( + sampleRateHz, + 1, // numOutputChannels + sineSweepDurationFrames // maxBlockSizeFrames + ); + sineSweepSignalB.renderNextBlock (bufferA); + + // Multi-channel noise + constexpr size_t multiChannelNoiseNumChannels = 5; + const size_t multiChannelNoiseDurationFrames = hart::roundToSizeT (sampleRateHz * 10_ms); + AudioBuffer bufferB (multiChannelNoiseNumChannels, multiChannelNoiseDurationFrames); + auto multiChannelNoiseSignal = WhiteNoise(); + multiChannelNoiseSignal.prepare ( + sampleRateHz, + multiChannelNoiseNumChannels, // numOutputChannels + multiChannelNoiseDurationFrames // maxBlockSizeFrames + ); + multiChannelNoiseSignal.renderNextBlock (bufferB); + multiChannelNoiseSignal.renderNextBlock (bufferB); // Some more noise... + multiChannelNoiseSignal.renderNextBlock (bufferB); // ...and more noise + + return 0; +}