|
| 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