Skip to content

Commit 82a2376

Browse files
authored
Added support for HART audio buffers (#21)
* Added support for HART audio buffers * Improved implementation for HART audio buffers * More robust, due to use of an existing template for a vector * Added example for HART AudioBuffer
1 parent 4a90165 commit 82a2376

File tree

4 files changed

+123
-0
lines changed

4 files changed

+123
-0
lines changed

dave/server/languages/c_cpp/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
from .std_2D import *
33
from .juce import *
44
from .choc import *
5+
from .hart import *
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from __future__ import annotations
2+
3+
import re
4+
from typing import Tuple
5+
6+
from ...container import SampleType, Container2D
7+
from ...debuggers.value import AbstractValue
8+
from dave.server.languages import c_cpp
9+
10+
class HartAudioBuffer(Container2D):
11+
__REGEX = rf"^(?:const\s+)?hart::AudioBuffer<{SampleType.regex()}>\s*$"
12+
13+
def __init__(self, dbg_value: AbstractValue, name: str, _):
14+
typename = dbg_value.typename()
15+
sample_type, *_ = self._parse_typename(typename)
16+
super().__init__(dbg_value, name, sample_type)
17+
18+
@property
19+
def __inner(self) -> c_cpp.StdVector1D:
20+
return c_cpp.StdVector1D(self._value.attr("m_frames"), self.name + ".m_frames")
21+
22+
@classmethod
23+
def typename_matcher(cls) -> re.Pattern:
24+
return re.compile(cls.__REGEX)
25+
26+
@classmethod
27+
def _parse_typename(cls, typename: str, **_) -> Tuple[SampleType, None, None]:
28+
re_match = cls.typename_matcher().match(typename)
29+
if re_match is None:
30+
raise TypeError(
31+
f"HartAudioBuffer could not parse {typename} as a valid type"
32+
)
33+
34+
return (SampleType.parse(re_match.group(1)), None, None)
35+
36+
def shape(self) -> Tuple[int, int]:
37+
assert isinstance(self._value, AbstractValue)
38+
try:
39+
return (
40+
int(self._value.attr("m_numChannels")),
41+
int(self._value.attr("m_numFrames"))
42+
)
43+
except:
44+
raise RuntimeError(f"Failed to retrieve shape of {self._value.typename()}")
45+
46+
def read_from_debugger(self) -> bytearray:
47+
return self.__inner.read_from_debugger()
48+
49+
HartAudioBuffer.register()

examples/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ FetchContent_Declare(
2626
FetchContent_MakeAvailable(GSL)
2727

2828

29+
set(HART_BUILD_TESTS OFF)
30+
FetchContent_Declare(
31+
HART
32+
GIT_REPOSITORY "https://github.com/daleonov/HART.git"
33+
GIT_TAG 0.1.0
34+
GIT_SHALLOW ON
35+
)
36+
37+
FetchContent_MakeAvailable(HART)
38+
2939
################################################################################
3040
### stdlib
3141
################################################################################
@@ -89,6 +99,17 @@ add_executable(
8999
)
90100
set_target_properties(choc PROPERTIES CXX_STANDARD 17)
91101

102+
################################################################################
103+
### HART
104+
################################################################################
105+
106+
add_executable(
107+
hart
108+
${CMAKE_CURRENT_SOURCE_DIR}/hart.cpp
109+
)
110+
set_target_properties(hart PROPERTIES CXX_STANDARD 11)
111+
target_link_libraries(hart PRIVATE HART::HART)
112+
92113
################################################################################
93114
### Custom containers example
94115
################################################################################

examples/hart.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#define HART_IMPLEMENTATION
2+
#include "hart.hpp"
3+
4+
HART_DECLARE_ALIASES_FOR_FLOAT;
5+
using AudioBuffer = hart::AudioBuffer<float>;
6+
using hart::roundToSizeT;
7+
8+
int main()
9+
{
10+
constexpr double sampleRateHz = 44100.0;
11+
12+
// Sine sweep
13+
const size_t sineSweepDurationFrames = roundToSizeT (sampleRateHz * 1.0_s);
14+
AudioBuffer bufferA (1, sineSweepDurationFrames);
15+
auto sineSweepSignalA = SineSweep();
16+
sineSweepSignalA.prepare (
17+
sampleRateHz,
18+
1, // numOutputChannels
19+
sineSweepDurationFrames // maxBlockSizeFrames
20+
);
21+
sineSweepSignalA.renderNextBlock (bufferA);
22+
23+
// A different sweep, overwrites the same buffer
24+
auto sineSweepSignalB = SineSweep()
25+
.withType (SineSweep::SweepType::linear)
26+
.withStartFrequency (100_Hz)
27+
.withEndFrequency (1_Hz)
28+
.withDuration (500_ms)
29+
.withLoop (SineSweep::Loop::yes);
30+
sineSweepSignalB.prepare (
31+
sampleRateHz,
32+
1, // numOutputChannels
33+
sineSweepDurationFrames // maxBlockSizeFrames
34+
);
35+
sineSweepSignalB.renderNextBlock (bufferA);
36+
37+
// Multi-channel noise
38+
constexpr size_t multiChannelNoiseNumChannels = 5;
39+
const size_t multiChannelNoiseDurationFrames = hart::roundToSizeT (sampleRateHz * 10_ms);
40+
AudioBuffer bufferB (multiChannelNoiseNumChannels, multiChannelNoiseDurationFrames);
41+
auto multiChannelNoiseSignal = WhiteNoise();
42+
multiChannelNoiseSignal.prepare (
43+
sampleRateHz,
44+
multiChannelNoiseNumChannels, // numOutputChannels
45+
multiChannelNoiseDurationFrames // maxBlockSizeFrames
46+
);
47+
multiChannelNoiseSignal.renderNextBlock (bufferB);
48+
multiChannelNoiseSignal.renderNextBlock (bufferB); // Some more noise...
49+
multiChannelNoiseSignal.renderNextBlock (bufferB); // ...and more noise
50+
51+
return 0;
52+
}

0 commit comments

Comments
 (0)