Skip to content

Commit 3766178

Browse files
committed
initial toy
1 parent 54f2ffe commit 3766178

9 files changed

+4566
-0
lines changed

CMakeLists.txt

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
cmake_minimum_required (VERSION 3.4)
3+
project(LabSynthToy)
4+
5+
# Don't report that sample file installation up to date
6+
set(CMAKE_INSTALL_MESSAGE LAZY)
7+
8+
set(LABSYNTHTOY_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
9+
configure_file("${LABSYNTHTOY_ROOT}/LabSynthToy.config.h" "${LABSYNTHTOY_ROOT}/LabSynthToy.h" @ONLY)
10+
11+
add_subdirectory(LabSound)
12+
13+
if (APPLE)
14+
set(PLATFORM_LIBS
15+
"-framework AudioToolbox"
16+
"-framework AudioUnit"
17+
"-framework Accelerate"
18+
"-framework Cocoa"
19+
"-framework CoreAudio"
20+
# "-framework Metal"
21+
# "-framework MetalKit"
22+
# "-framework QuartzCore"
23+
)
24+
endif()
25+
26+
add_executable(LabSynthToy
27+
TinySoundFont/tml.h
28+
TinySoundFont/tsf.h
29+
TinySoundFontNode.h
30+
TinySoundFontNode.cpp
31+
LabSoundTemplateNode.h
32+
LabSoundTemplateNode.cpp
33+
LabSynthToy.cpp)
34+
35+
target_link_libraries(LabSynthToy Lab::Sound ${PLATFORM_LIBS})
36+
target_include_directories(LabSynthToy PRIVATE "${LABSYNTHTOY_ROOT}")
37+
install(TARGETS LabSynthToy RUNTIME DESTINATION bin)
38+
39+
install(FILES
40+
"${LABSYNTHTOY_ROOT}/TinySoundFont/examples/florestan-subset.sf2"
41+
"${LABSYNTHTOY_ROOT}/TinySoundFont/examples/venture.mid"
42+
DESTINATION share/LabSynthToy)

LabSoundTemplateNode.cpp

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
2+
#include "LabSoundTemplateNode.h"
3+
#include <LabSound/core/AudioBus.h>
4+
#include <LabSound/core/AudioContext.h>
5+
#include <LabSound/core/AudioNodeOutput.h>
6+
#include <LabSound/extended/AudioContextLock.h>
7+
#include <LabSound/extended/Registry.h>
8+
9+
#include "concurrentqueue.h"
10+
#include <algorithm>
11+
#include <queue>
12+
13+
using namespace lab;
14+
15+
struct LabSoundTemplateNodeEvent
16+
{
17+
double when;
18+
int id;
19+
20+
bool operator<(const LabSoundTemplateNodeEvent& rhs) const
21+
{
22+
if (when > rhs.when)
23+
return true;
24+
if (when < rhs.when)
25+
return false;
26+
return id > rhs.id;
27+
}
28+
};
29+
30+
31+
32+
struct LabSoundTemplateNode::Detail
33+
{
34+
std::priority_queue<LabSoundTemplateNodeEvent> queue;
35+
moodycamel::ConcurrentQueue<LabSoundTemplateNodeEvent> incoming;
36+
lab::AudioContext* ac = nullptr;
37+
38+
Detail() = default;
39+
~Detail() = default;
40+
41+
void clearSchedules()
42+
{
43+
LabSoundTemplateNodeEvent s;
44+
while (incoming.try_dequeue(s)) {}
45+
while (!queue.empty())
46+
queue.pop();
47+
}
48+
};
49+
50+
LabSoundTemplateNode::LabSoundTemplateNode(AudioContext& ac)
51+
: AudioNode(ac)
52+
, _detail(new Detail())
53+
{
54+
_detail->ac = &ac;
55+
addOutput(std::unique_ptr<AudioNodeOutput>(new AudioNodeOutput(this, 1)));
56+
57+
if (s_registered)
58+
initialize();
59+
}
60+
61+
bool LabSoundTemplateNode::s_registered = NodeRegistry::Register(LabSoundTemplateNode::static_name(),
62+
[](AudioContext& ac)->AudioNode* { return new LabSoundTemplateNode(ac); },
63+
[](AudioNode* n) { delete n; });
64+
65+
LabSoundTemplateNode::~LabSoundTemplateNode()
66+
{
67+
_detail->clearSchedules();
68+
uninitialize();
69+
delete _detail;
70+
}
71+
72+
void LabSoundTemplateNode::realtimeEvent(float when, int identifier)
73+
{
74+
double now = _detail->ac->currentTime();
75+
_detail->incoming.enqueue({when + now, identifier});
76+
}
77+
78+
void LabSoundTemplateNode::process(ContextRenderLock &r, int bufferSize)
79+
{
80+
AudioBus * outputBus = output(0)->bus(r);
81+
82+
if (!isInitialized())
83+
{
84+
if (outputBus)
85+
outputBus->zero();
86+
87+
_detail->clearSchedules();
88+
return;
89+
}
90+
91+
// move incoming commands to the internal schedule
92+
{
93+
LabSoundTemplateNodeEvent s;
94+
while (_detail->incoming.try_dequeue(s))
95+
{
96+
_detail->queue.push(s);
97+
}
98+
}
99+
100+
auto& ac = *r.context();
101+
double quantumStart = ac.currentTime();
102+
double quantumEnd = quantumStart + (double) bufferSize / ac.sampleRate();
103+
104+
// any events to service now?
105+
106+
int events = 0;
107+
outputBus->zero();
108+
while (!_detail->queue.empty() && _detail->queue.top().when < quantumEnd)
109+
{
110+
auto& top = _detail->queue.top();
111+
112+
// compute the exact sample the event occurs at
113+
int offset = (top.when < quantumStart) ? 0 : static_cast<int>((top.when - quantumStart) * ac.sampleRate());
114+
115+
// sanity to guard against rounding problems
116+
if (offset > bufferSize - 1)
117+
offset = bufferSize - 1;
118+
119+
// make a little popping sound
120+
float* data = outputBus->channel(0)->mutableData();
121+
for (int i = std::max(0, offset - 4); i < std::min(offset + 4, bufferSize); ++i)
122+
data[i] = 1;
123+
124+
_detail->queue.pop();
125+
++events;
126+
}
127+
128+
if (events > 0)
129+
outputBus->clearSilentFlag();
130+
}
131+
132+
void LabSoundTemplateNode::reset(ContextRenderLock&)
133+
{
134+
_detail->clearSchedules();
135+
}

LabSoundTemplateNode.h

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
#ifndef LABSOUND_TEMPLATE_NODE
3+
#define LABSOUND_TEMPLATE_NODE
4+
5+
#include <LabSound/core/AudioNode.h>
6+
7+
class LabSoundTemplateNode : public lab::AudioNode
8+
{
9+
struct Detail;
10+
Detail* _detail = nullptr;
11+
static bool s_registered;
12+
13+
public:
14+
LabSoundTemplateNode(lab::AudioContext & ac);
15+
virtual ~LabSoundTemplateNode();
16+
17+
static const char* static_name() { return "LabSoundTemplateNode"; }
18+
virtual const char* name() const override { return static_name(); }
19+
20+
// AudioNode
21+
virtual void process(lab::ContextRenderLock &, int bufferSize) override;
22+
virtual void reset(lab::ContextRenderLock &) override;
23+
24+
void realtimeEvent(float when, int identifier);
25+
26+
private:
27+
virtual bool propagatesSilence(lab::ContextRenderLock& r) const override { return false; }
28+
virtual double tailTime(lab::ContextRenderLock & r) const override { return 0; }
29+
virtual double latencyTime(lab::ContextRenderLock & r) const override { return 0; }
30+
};
31+
32+
#endif

LabSynthToy.config.h

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef LABSYNTHTOYCONFIG_H
2+
#define LABSYNTHTOYCONFIG_H
3+
4+
const char* synth_toy_asset_base = "@CMAKE_INSTALL_PREFIX@/share/LabSynthToy/";
5+
6+
#endif

0 commit comments

Comments
 (0)