Skip to content

Commit 561ef2d

Browse files
committed
Add an offline starter app
1 parent 7532390 commit 561ef2d

File tree

2 files changed

+117
-0
lines changed

2 files changed

+117
-0
lines changed

Diff for: CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ target_link_libraries(LabSoundStarter Lab::Sound ${PLATFORM_LIBS})
2828
target_include_directories(LabSoundStarter PRIVATE "${LABSOUNDDEMO_ROOT}")
2929
install(TARGETS LabSoundStarter RUNTIME DESTINATION bin)
3030

31+
add_executable(LabSoundOfflineStarter LabSoundOfflineStarter.cpp)
32+
target_link_libraries(LabSoundOfflineStarter Lab::Sound ${PLATFORM_LIBS})
33+
target_include_directories(LabSoundOfflineStarter PRIVATE "${LABSOUNDDEMO_ROOT}")
34+
install(TARGETS LabSoundOfflineStarter RUNTIME DESTINATION bin)
35+
3136
add_executable(LabSoundDemo LabSoundDemo.cpp)
3237
target_link_libraries(LabSoundDemo Lab::Sound ${PLATFORM_LIBS})
3338
target_include_directories(LabSoundDemo PRIVATE "${LABSOUNDDEMO_ROOT}")

Diff for: LabSoundOfflineStarter.cpp

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// SPDX-License-Identifier: BSD-2-Clause
2+
// Copyright (C) 2020, The LabSound Authors. All rights reserved.
3+
4+
#if defined(_MSC_VER)
5+
#if !defined(_CRT_SECURE_NO_WARNINGS)
6+
#define _CRT_SECURE_NO_WARNINGS
7+
#endif
8+
#if !defined(NOMINMAX)
9+
#define NOMINMAX
10+
#endif
11+
#endif
12+
13+
#include "LabSound/LabSound.h"
14+
#include "LabSoundDemo.h"
15+
16+
#include <chrono>
17+
#include <string>
18+
#include <thread>
19+
#include <vector>
20+
21+
using namespace lab;
22+
\
23+
24+
std::shared_ptr<AudioBus> MakeBusFromSampleFile(char const* const name, int argc, char** argv)
25+
{
26+
std::string path_prefix = asset_base;
27+
const std::string path = path_prefix + name;
28+
std::shared_ptr<AudioBus> bus = MakeBusFromFile(path, false);
29+
if (!bus)
30+
throw std::runtime_error("couldn't open " + path);
31+
32+
return bus;
33+
}
34+
35+
template <typename Duration>
36+
void Wait(Duration duration)
37+
{
38+
std::this_thread::sleep_for(duration);
39+
}
40+
41+
42+
int main(int argc, char *argv[]) try
43+
{
44+
AudioStreamConfig offlineConfig;
45+
offlineConfig.device_index = 0;
46+
offlineConfig.desired_samplerate = LABSOUND_DEFAULT_SAMPLERATE;
47+
offlineConfig.desired_channels = LABSOUND_DEFAULT_CHANNELS;
48+
49+
const float recording_time_ms = 1000.f;
50+
51+
std::unique_ptr<lab::AudioContext> context = lab::MakeOfflineAudioContext(offlineConfig, recording_time_ms);
52+
lab::AudioContext& ac = *context.get();
53+
54+
std::shared_ptr<OscillatorNode> oscillator;
55+
std::shared_ptr<AudioBus> musicClip = MakeBusFromSampleFile("samples/stereo-music-clip.wav", argc, argv);
56+
std::shared_ptr<SampledAudioNode> musicClipNode;
57+
std::shared_ptr<GainNode> gain;
58+
59+
auto recorder = std::make_shared<RecorderNode>(ac, offlineConfig);
60+
61+
context->addAutomaticPullNode(recorder);
62+
63+
recorder->startRecording();
64+
65+
{
66+
ContextRenderLock r(context.get(), "ex_offline_rendering");
67+
68+
gain = std::make_shared<GainNode>(ac);
69+
gain->gain()->setValue(0.125f);
70+
71+
// osc -> gain -> recorder
72+
oscillator = std::make_shared<OscillatorNode>(ac);
73+
context->connect(gain, oscillator, 0, 0);
74+
context->connect(recorder, gain, 0, 0);
75+
oscillator->frequency()->setValue(880.f);
76+
oscillator->setType(OscillatorType::SINE);
77+
oscillator->start(0.0f);
78+
79+
musicClipNode = std::make_shared<SampledAudioNode>(ac);
80+
context->connect(recorder, musicClipNode, 0, 0);
81+
musicClipNode->setBus(r, musicClip);
82+
musicClipNode->schedule(0.0);
83+
}
84+
85+
// the completion callback will be called when the 1000ms sample buffer has been filled.
86+
bool complete = false;
87+
context->offlineRenderCompleteCallback = [&context, &recorder, &complete]() {
88+
recorder->stopRecording();
89+
90+
printf("Recorded %f seconds of audio\n", recorder->recordedLengthInSeconds());
91+
92+
context->removeAutomaticPullNode(recorder);
93+
recorder->writeRecordingToWav("ex_offline_rendering.wav", false);
94+
complete = true;
95+
};
96+
97+
// Offline rendering happens in a separate thread and blocks until complete.
98+
// It needs to acquire the graph + render locks, so it must
99+
// be outside the scope of where we make changes to the graph.
100+
context->startOfflineRendering();
101+
102+
while (!complete)
103+
{
104+
Wait(std::chrono::milliseconds(100));
105+
}
106+
}
107+
catch (const std::exception & e)
108+
{
109+
std::cerr << "unhandled fatal exception: " << e.what() << std::endl;
110+
return EXIT_FAILURE;
111+
}
112+

0 commit comments

Comments
 (0)