Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "audioengine.h"
24 :
25 : #include "global/defer.h"
26 :
27 : #include "audio/common/audiosanitizer.h"
28 : #include "audio/common/audioerrors.h"
29 :
30 : #include "audiocontext.h"
31 :
32 : #include "log.h"
33 :
34 : using namespace muse;
35 : using namespace muse::audio;
36 : using namespace muse::audio::engine;
37 :
38 : static constexpr int MAX_SUPPORTED_AUDIO_CHANNELS = 2;
39 :
40 0 : AudioEngine::AudioEngine()
41 : {
42 0 : }
43 :
44 0 : AudioEngine::~AudioEngine()
45 : {
46 : ONLY_AUDIO_MAIN_OR_ENGINE_THREAD;
47 0 : }
48 :
49 0 : Ret AudioEngine::init(const OutputSpec& outputSpec)
50 : {
51 : ONLY_AUDIO_ENGINE_THREAD;
52 :
53 0 : if (m_inited) {
54 0 : return make_ret(Ret::Code::Ok);
55 : }
56 :
57 0 : IF_ASSERT_FAILED(outputSpec.audioChannelCount <= MAX_SUPPORTED_AUDIO_CHANNELS) {
58 0 : return make_ret(Ret::Code::InternalError);
59 : }
60 :
61 0 : LOGI() << "[OutputSpec] sampleRate: " << outputSpec.sampleRate
62 0 : << ", samplesPerChannel: " << outputSpec.samplesPerChannel
63 0 : << ", audioChannelCount: " << outputSpec.audioChannelCount;
64 :
65 0 : m_outputSpec = outputSpec;
66 0 : m_operationType = OperationType::NoOperation;
67 :
68 0 : m_mixer = std::make_shared<MixerNode>();
69 0 : m_mixer->setOutputSpec(outputSpec);
70 :
71 0 : m_inited = true;
72 :
73 0 : return make_ret(Ret::Code::Ok);
74 : }
75 :
76 0 : void AudioEngine::deinit()
77 : {
78 : ONLY_AUDIO_ENGINE_THREAD;
79 0 : if (m_inited) {
80 0 : m_inited = false;
81 :
82 0 : for (auto& p : m_contexts) {
83 0 : p.second->deinit();
84 : }
85 0 : m_contexts.clear();
86 : }
87 0 : }
88 :
89 0 : RetVal<std::shared_ptr<IAudioContext> > AudioEngine::addAudioContext(const AudioCtxId& ctxId)
90 : {
91 : ONLY_AUDIO_ENGINE_THREAD;
92 :
93 : using RetType = RetVal<std::shared_ptr<IAudioContext> >;
94 :
95 0 : if (m_contexts.find(ctxId) != m_contexts.end()) {
96 0 : return RetType::make_ret(Err::AudioContextAlreadyExists);
97 : }
98 :
99 0 : auto ctx = std::make_shared<AudioContext>(ctxId, this);
100 0 : Ret ret = ctx->init();
101 0 : if (!ret) {
102 0 : return RetType::make_ret(ret);
103 : }
104 :
105 0 : ctx->setOutputSpec(m_outputSpec);
106 0 : ctx->setMode(ProcessMode::Idle);
107 :
108 0 : m_contexts[ctxId] = ctx;
109 :
110 0 : ctx->connect(m_mixer);
111 :
112 0 : return RetType::make_ok(ctx);
113 0 : }
114 :
115 0 : std::shared_ptr<IAudioContext> AudioEngine::context(const AudioCtxId& ctxId) const
116 : {
117 0 : auto it = m_contexts.find(ctxId);
118 0 : if (it != m_contexts.end()) {
119 0 : return it->second;
120 : }
121 0 : return nullptr;
122 : }
123 :
124 0 : void AudioEngine::destroyContext(const AudioCtxId& ctxId)
125 : {
126 0 : auto it = m_contexts.find(ctxId);
127 0 : if (it != m_contexts.end()) {
128 0 : auto& ctx = it->second;
129 0 : ctx->deinit();
130 0 : ctx->disconnect(m_mixer);
131 0 : m_contexts.erase(it);
132 : }
133 0 : }
134 :
135 0 : void AudioEngine::setOutputSpec(const OutputSpec& outputSpec)
136 : {
137 : ONLY_AUDIO_ENGINE_THREAD;
138 :
139 0 : IF_ASSERT_FAILED(outputSpec.audioChannelCount <= MAX_SUPPORTED_AUDIO_CHANNELS) {
140 0 : return;
141 : }
142 :
143 0 : if (m_outputSpec == outputSpec) {
144 0 : return;
145 : }
146 :
147 0 : LOGI() << "[OutputSpec] sampleRate: " << outputSpec.sampleRate
148 0 : << ", samplesPerChannel: " << outputSpec.samplesPerChannel
149 0 : << ", audioChannelCount: " << outputSpec.audioChannelCount;
150 :
151 0 : m_outputSpec = outputSpec;
152 :
153 0 : if (m_mixer) {
154 0 : m_mixer->setOutputSpec(outputSpec);
155 : }
156 :
157 0 : m_outputSpecChanged.send(outputSpec);
158 : }
159 :
160 0 : OutputSpec AudioEngine::outputSpec() const
161 : {
162 0 : return m_outputSpec;
163 : }
164 :
165 0 : async::Channel<OutputSpec> AudioEngine::outputSpecChanged() const
166 : {
167 0 : return m_outputSpecChanged;
168 : }
169 :
170 0 : void AudioEngine::execOperation(OperationType type, const Operation& func)
171 : {
172 : // wait end of processing
173 0 : while (m_processing) {
174 0 : LOGD() << "wait end of processing";
175 : using namespace std::chrono_literals;
176 0 : std::this_thread::sleep_for(1ms);
177 : }
178 :
179 0 : OperationType oldOperationType = m_operationType;
180 :
181 0 : m_operationType = type;
182 0 : AudioSanitizer::setOperationType(type);
183 :
184 0 : if (m_operationType == OperationType::QuickOperation) {
185 0 : m_quickOperationWaitMutex.lock();
186 : }
187 :
188 0 : func();
189 :
190 0 : if (m_operationType == OperationType::QuickOperation) {
191 0 : m_quickOperationWaitMutex.unlock();
192 : }
193 :
194 0 : m_operationType = oldOperationType;
195 0 : AudioSanitizer::setOperationType(oldOperationType);
196 0 : }
197 :
198 0 : samples_t AudioEngine::fillSilent(float* buffer, samples_t samplesPerChannel)
199 : {
200 0 : std::memset(buffer, 0, samplesPerChannel * sizeof(float) * m_outputSpec.audioChannelCount);
201 0 : return 0;
202 : }
203 :
204 0 : samples_t AudioEngine::process(float* buffer, samples_t samplesPerChannel)
205 : {
206 0 : m_processing = true;
207 0 : DEFER {
208 0 : m_processing = false;
209 0 : };
210 :
211 0 : fillSilent(buffer, samplesPerChannel); // clear buffer
212 :
213 0 : if (!m_inited) {
214 0 : return 0;
215 : }
216 :
217 : // check current operation
218 0 : switch (m_operationType) {
219 0 : case OperationType::Undefined: {
220 0 : UNREACHABLE;
221 : return 0;
222 : }
223 0 : case OperationType::NoOperation: {
224 : // normal playing
225 0 : m_mixer->process(buffer, samplesPerChannel);
226 0 : return samplesPerChannel;
227 : }
228 0 : case OperationType::QuickOperation: {
229 : // wait
230 0 : LOGD() << "wait end of quick operation";
231 0 : std::scoped_lock<std::mutex> lock(m_quickOperationWaitMutex);
232 0 : m_mixer->process(buffer, samplesPerChannel);
233 0 : return samplesPerChannel;
234 0 : }
235 0 : case OperationType::LongOperation: {
236 0 : return 0;
237 : }
238 : }
239 :
240 0 : return 0;
241 0 : }
|