Skip to content

Commit 1f512d7

Browse files
committed
More metaprogramming tests
1 parent bbcced0 commit 1f512d7

File tree

4 files changed

+189
-42
lines changed

4 files changed

+189
-42
lines changed

modules/juce_audio_devices/native/juce_AudioWorklet_emscripten.cpp

Lines changed: 37 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,23 @@
2222
namespace juce
2323
{
2424

25+
namespace
26+
{
27+
28+
template <class T>
29+
using hasAudioSampleFrameSamplesPerChannel = decltype(T::samplesPerChannel);
30+
31+
template <class T>
32+
int getNumSamplesPerChannel (const T& frame)
33+
{
34+
if constexpr (isDetected<hasAudioSampleFrameSamplesPerChannel, T>)
35+
return frame.samplesPerChannel;
36+
else
37+
return 128;
38+
}
39+
40+
} // namespace
41+
2542
//==============================================================================
2643
class AudioWorkletAudioIODevice final : public AudioIODevice
2744
{
@@ -94,11 +111,9 @@ class AudioWorkletAudioIODevice final : public AudioIODevice
94111
double sampleRate,
95112
int bufferSizeSamples) override
96113
{
97-
yup::Logger::outputDebugString ("open");
98-
99-
if (sampleRate != getDefaultSampleRate())
114+
if (sampleRate != getDefaultSampleRate() || bufferSizeSamples != getDefaultBufferSize())
100115
{
101-
lastError = "Browser audio outputs only support 44.1 kHz sample rate";
116+
lastError = "Browser audio outputs only support 44.1 kHz sample rate and 128 samples buffer size.";
102117
return lastError;
103118
}
104119

@@ -125,8 +140,6 @@ class AudioWorkletAudioIODevice final : public AudioIODevice
125140

126141
void close() override
127142
{
128-
yup::Logger::outputDebugString ("close");
129-
130143
stop();
131144

132145
if (isDeviceOpen)
@@ -155,17 +168,11 @@ class AudioWorkletAudioIODevice final : public AudioIODevice
155168

156169
void start (AudioIODeviceCallback* newCallback) override
157170
{
158-
yup::Logger::outputDebugString ("start 1");
159-
160171
if (! isDeviceOpen)
161172
return;
162173

163-
yup::Logger::outputDebugString ("start 2");
164-
165174
if (isRunning)
166175
{
167-
yup::Logger::outputDebugString ("start 3");
168-
169176
if (newCallback != callback)
170177
{
171178
if (newCallback != nullptr)
@@ -182,40 +189,27 @@ class AudioWorkletAudioIODevice final : public AudioIODevice
182189
}
183190
else
184191
{
185-
yup::Logger::outputDebugString ("start 4");
186-
187192
callback = newCallback;
188193
isRunning = emscripten_audio_context_state (context) == AUDIO_CONTEXT_STATE_RUNNING;
189194

190195
if (! isRunning && hasBeenActivatedAlreadyByUser)
191196
{
192-
yup::Logger::outputDebugString ("start 5");
193-
194197
emscripten_resume_audio_context_sync (context);
195198
isRunning = emscripten_audio_context_state (context) == AUDIO_CONTEXT_STATE_RUNNING;
196199
}
197200

198201
firstCallback = true;
199202

200-
yup::Logger::outputDebugString ("start 6");
201-
202203
if (callback != nullptr)
203204
{
204205
if (isRunning)
205-
{
206-
yup::Logger::outputDebugString ("start 7");
207206
callback->audioDeviceAboutToStart (this);
208-
}
209207
}
210-
211-
yup::Logger::outputDebugString ("start 8");
212208
}
213209
}
214210

215211
void stop() override
216212
{
217-
yup::Logger::outputDebugString ("stop");
218-
219213
AudioIODeviceCallback* oldCallback = nullptr;
220214

221215
if (callback != nullptr)
@@ -260,12 +254,12 @@ class AudioWorkletAudioIODevice final : public AudioIODevice
260254
}
261255

262256
int getOutputLatencyInSamples() override
263-
{ /* TODO */
257+
{
264258
return 0;
265259
}
266260

267261
int getInputLatencyInSamples() override
268-
{ /* TODO */
262+
{
269263
return 0;
270264
}
271265

@@ -279,8 +273,6 @@ class AudioWorkletAudioIODevice final : public AudioIODevice
279273

280274
void audioThreadInitialized()
281275
{
282-
yup::Logger::outputDebugString ("audioThreadInitialized");
283-
284276
WebAudioWorkletProcessorCreateOptions opts =
285277
{
286278
.name = audioWorkletTypeName
@@ -292,8 +284,6 @@ class AudioWorkletAudioIODevice final : public AudioIODevice
292284

293285
void audioWorkletProcessorCreated()
294286
{
295-
yup::Logger::outputDebugString ("audioWorkletProcessorCreated");
296-
297287
int outputChannelCounts[1] = { actualNumberOfOutputs };
298288
EmscriptenAudioWorkletNodeCreateOptions options =
299289
{
@@ -307,7 +297,7 @@ class AudioWorkletAudioIODevice final : public AudioIODevice
307297
context, audioWorkletTypeName, &options, renderAudioCallback, this);
308298

309299
// Connect it to audio context destination
310-
//emscripten_audio_node_connect (audioWorkletNode, context, 0, 0);
300+
// emscripten_audio_node_connect (audioWorkletNode, context, 0, 0);
311301
EM_ASM ({
312302
emscriptenGetAudioObject ($0).connect (emscriptenGetAudioObject ($1).destination);
313303
}, audioWorkletNode, context);
@@ -319,10 +309,19 @@ class AudioWorkletAudioIODevice final : public AudioIODevice
319309
int numOutputs, AudioSampleFrame* outputs,
320310
int numParams, const AudioParamFrame* params)
321311
{
322-
const int audioFrames = 128;
312+
const int samplesPerChannel = [&]
313+
{
314+
if (numOutputs > 0)
315+
return getNumSamplesPerChannel (outputs[0]);
316+
317+
else if (numInputs > 0)
318+
return getNumSamplesPerChannel (inputs[0]);
319+
320+
return 128;
321+
}();
323322

324323
// check for xruns
325-
calculateXruns (audioFrames);
324+
calculateXruns (samplesPerChannel);
326325

327326
ScopedLock lock (callbackLock);
328327

@@ -334,17 +333,17 @@ class AudioWorkletAudioIODevice final : public AudioIODevice
334333

335334
// Setup channelOutBuffers (assume a single worklet output)
336335
for (int ch = 0; ch < actualNumberOfOutputs; ++ch)
337-
channelOutBuffer[ch] = &(outputs[0].data[ch * 128]); // outputs[0].samplesPerChannel / outputs[0].quantumSize
336+
channelOutBuffer[ch] = &(outputs[0].data[ch * samplesPerChannel]);
338337

339338
callback->audioDeviceIOCallbackWithContext (channelInBuffer.getData(),
340339
actualNumberOfInputs,
341340
channelOutBuffer.getData(),
342341
actualNumberOfOutputs,
343-
audioFrames,
342+
samplesPerChannel,
344343
{});
345-
}
346344

347-
audioFramesElapsed += audioFrames;
345+
audioFramesElapsed += samplesPerChannel;
346+
}
348347

349348
return EM_TRUE; // keep going !
350349
}
@@ -353,8 +352,6 @@ class AudioWorkletAudioIODevice final : public AudioIODevice
353352
{
354353
if (emscripten_audio_context_state (context) != AUDIO_CONTEXT_STATE_RUNNING)
355354
{
356-
yup::Logger::outputDebugString ("canvasClick");
357-
358355
emscripten_resume_audio_context_sync (context);
359356

360357
isRunning = true;

modules/juce_core/misc/juce_MetaProgramming.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,67 @@
2222
namespace juce
2323
{
2424

25+
//==============================================================================
2526
template <bool Value, auto... Args>
2627
inline constexpr bool dependentBoolValue = Value;
2728

2829
template <auto... Args>
2930
inline constexpr bool dependentFalse = dependentBoolValue<false, Args...>;
3031

32+
//==============================================================================
33+
struct NoneSuch
34+
{
35+
NoneSuch() = delete;
36+
~NoneSuch() = delete;
37+
NoneSuch(NoneSuch const&) = delete;
38+
void operator=(NoneSuch const&) = delete;
39+
NoneSuch(NoneSuch&&) = delete;
40+
void operator=(NoneSuch&&) = delete;
41+
};
42+
43+
namespace detail {
44+
template <class Default, class AlwaysVoid, template <class...> class Op, class... Args>
45+
struct Detector
46+
{
47+
using ValueType = std::false_type;
48+
using Type = Default;
49+
};
50+
51+
template <class Default, template <class...> class Op, class... Args>
52+
struct Detector<Default, std::void_t<Op<Args...>>, Op, Args...>
53+
{
54+
using ValueType = std::true_type;
55+
using Type = Op<Args...>;
56+
};
57+
58+
template <template <class...> class Op, class... Args>
59+
using isDetected = typename Detector<NoneSuch, void, Op, Args...>::ValueType;
60+
61+
template <class Default, template <class...> class Op, class... Args>
62+
using detectedOr = Detector<Default, void, Op, Args...>;
63+
} // namespace detail
64+
65+
template <template <class...> class Op, class... Args>
66+
inline constexpr bool isDetected = detail::isDetected<Op, Args...>::value;
67+
68+
template <template <class...> class Op, class... Args>
69+
using detectedType = typename detail::Detector<NoneSuch, void, Op, Args...>::Type;
70+
71+
template <class Default, template <class...> class Op, class... Args>
72+
using detectedOr = typename detail::detectedOr<Default, Op, Args...>::Type;
73+
74+
namespace detail {
75+
template <class Expected, template <class...> class Op, class... Args>
76+
using isDetectedExact = std::is_same<Expected, detectedType<Op, Args...>>;
77+
78+
template <class To, template <class...> class Op, class... Args>
79+
using isDetectedConvertible = std::is_convertible<detectedType<Op, Args...>, To>;
80+
} // namespace detail
81+
82+
template <class Expected, template <class...> class Op, class... Args>
83+
inline constexpr bool isDetectedExact = detail::isDetectedExact<Expected, Op, Args...>::value;
84+
85+
template <class To, template <class...> class Op, class... Args>
86+
inline constexpr bool isDetectedConvertible = detail::isDetectedConvertible<To, Op, Args...>::value;
87+
3188
} // namespace juce

modules/juce_core/native/juce_Files_wasm.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,7 @@ bool Process::openDocument (const String& fileName, const String& parameters)
226226
document.body.appendChild (elem);
227227
elem.click();
228228
document.body.removeChild (elem);
229-
},
230-
cmdString.toRawUTF8());
229+
}, cmdString.toRawUTF8());
231230

232231
return true;
233232
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
==============================================================================
3+
4+
This file is part of the YUP library.
5+
Copyright (c) 2024 - [email protected]
6+
7+
YUP is an open source library subject to open-source licensing.
8+
9+
The code included in this file is provided under the terms of the ISC license
10+
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
11+
to use, copy, modify, and/or distribute this software for any purpose with or
12+
without fee is hereby granted provided that the above copyright notice and
13+
this permission notice appear in all copies.
14+
15+
YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
16+
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
17+
DISCLAIMED.
18+
19+
==============================================================================
20+
*/
21+
22+
#include <gtest/gtest.h>
23+
24+
#include <juce_core/juce_core.h>
25+
26+
#include <string>
27+
28+
using namespace juce;
29+
30+
namespace {
31+
32+
struct HaveIt
33+
{
34+
bool existingMethod(int, float);
35+
bool existingMethod2(int, float, int);
36+
37+
std::string field;
38+
};
39+
40+
struct DontHaveIt
41+
{
42+
uint32_t field;
43+
};
44+
45+
template <class T>
46+
using hasExistingMethod = decltype(&T::existingMethod);
47+
48+
template <class T>
49+
using hasExistingMethod2 = decltype(&T::existingMethod2);
50+
51+
template <class T>
52+
using hasField = decltype(T::field);
53+
54+
} // namespace
55+
56+
TEST (MetaProgrammingTests, DependentBoolValue)
57+
{
58+
static_assert (dependentBoolValue<true>);
59+
static_assert (! dependentBoolValue<false>);
60+
static_assert (! dependentFalse<>);
61+
}
62+
63+
TEST (MetaProgrammingTests, IsDetected)
64+
{
65+
static_assert (isDetected<hasExistingMethod, HaveIt>);
66+
static_assert (! isDetected<hasExistingMethod, DontHaveIt>);
67+
}
68+
69+
TEST (MetaProgrammingTests, IsDetectedExact)
70+
{
71+
static_assert (isDetectedExact<decltype(&HaveIt::existingMethod), hasExistingMethod, HaveIt>);
72+
static_assert (! isDetectedExact<decltype(&HaveIt::existingMethod), hasExistingMethod2, HaveIt>);
73+
static_assert (! isDetectedExact<decltype(&HaveIt::existingMethod), hasExistingMethod, DontHaveIt>);
74+
}
75+
76+
TEST (MetaProgrammingTests, IsDetectedConvertible)
77+
{
78+
static_assert (isDetectedConvertible<std::string_view, hasField, HaveIt>);
79+
static_assert (! isDetectedConvertible<std::size_t, hasField, HaveIt>);
80+
static_assert (! isDetectedConvertible<std::string_view, hasField, DontHaveIt>);
81+
static_assert (isDetectedConvertible<std::size_t, hasField, DontHaveIt>);
82+
}
83+
84+
TEST (MetaProgrammingTests, DetectedType)
85+
{
86+
static_assert (std::is_same_v<detectedType<hasExistingMethod, HaveIt>, decltype(&HaveIt::existingMethod)>);
87+
static_assert (std::is_same_v<detectedType<hasExistingMethod, DontHaveIt>, yup::NoneSuch>);
88+
}
89+
90+
TEST (MetaProgrammingTests, DetectedOr)
91+
{
92+
static_assert (std::is_same_v<detectedOr<int, hasExistingMethod, HaveIt>, decltype(&HaveIt::existingMethod)>);
93+
static_assert (std::is_same_v<detectedOr<int, hasExistingMethod, DontHaveIt>, int>);
94+
}

0 commit comments

Comments
 (0)