Skip to content

Commit 27bb337

Browse files
committed
More work
1 parent cd21e91 commit 27bb337

31 files changed

+30131
-66
lines changed

cmake/yup_modules.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ macro (yup_add_default_modules modules_path)
620620
yup_add_module (${modules_path}/thirdparty/rive_renderer "${modules_definitions}" ${thirdparty_group})
621621
yup_add_module (${modules_path}/thirdparty/oboe_library "${modules_definitions}" ${thirdparty_group})
622622
yup_add_module (${modules_path}/thirdparty/pffft_library "${modules_definitions}" ${thirdparty_group})
623+
yup_add_module (${modules_path}/thirdparty/dr_libs "${modules_definitions}" ${thirdparty_group})
623624

624625
# ==== Yup modules
625626
set (modules_group "Modules")
@@ -647,6 +648,9 @@ macro (yup_add_default_modules modules_path)
647648
yup_add_module (${modules_path}/modules/yup_audio_devices "${modules_definitions}" ${modules_group})
648649
add_library (yup::yup_audio_devices ALIAS yup_audio_devices)
649650

651+
yup_add_module (${modules_path}/modules/yup_audio_formats "${modules_definitions}" ${modules_group})
652+
add_library (yup::yup_audio_formats ALIAS yup_audio_formats)
653+
650654
yup_add_module (${modules_path}/modules/yup_audio_processors "${modules_definitions}" ${modules_group})
651655
add_library (yup::yup_audio_processors ALIAS yup_audio_processors)
652656

examples/graphics/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ yup_standalone_app (
7272
yup::yup_gui
7373
yup::yup_audio_gui
7474
yup::yup_audio_processors
75+
yup::yup_audio_formats
7576
pffft_library
77+
dr_libs
7678
libpng
7779
libwebp
7880
${additional_modules}
1.76 MB
Binary file not shown.

examples/graphics/source/examples/CrossoverDemo.h

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#pragma once
2323

2424
#include <yup_dsp/yup_dsp.h>
25+
#include <yup_audio_formats/yup_audio_formats.h>
2526

2627
#include <memory>
2728
#include <random>
@@ -58,8 +59,10 @@ class CrossoverFrequencyResponseDisplay : public yup::Component
5859

5960
// Reserve space for labels
6061
auto titleBounds = bounds.removeFromTop (25);
62+
titleBounds.removeFromLeft (5);
6163
auto bottomLabelSpace = bounds.removeFromBottom (20);
6264
auto leftLabelSpace = bounds.removeFromLeft (50);
65+
leftLabelSpace.removeFromRight (5);
6366

6467
// Grid
6568
g.setStrokeColor (yup::Color (0xFF333333));
@@ -247,6 +250,9 @@ class CrossoverDemo : public yup::Component,
247250
, lowGainSlider (yup::Slider::LinearVertical)
248251
, highGainSlider (yup::Slider::LinearVertical)
249252
{
253+
// Load the audio file
254+
loadAudioFile();
255+
250256
// Audio device manager
251257
audioDeviceManager.initialiseWithDefaultDevices (0, 2);
252258

@@ -346,7 +352,7 @@ class CrossoverDemo : public yup::Component,
346352
yup::FloatVectorOperations::clear (outputChannelData[ch], numSamples);
347353
}
348354

349-
if (numOutputChannels < 2)
355+
if (numOutputChannels < 2 || audioBuffer.getNumSamples() == 0)
350356
return;
351357

352358
// Get the active filter
@@ -375,6 +381,9 @@ class CrossoverDemo : public yup::Component,
375381
}
376382

377383
// Process samples
384+
const int totalSamples = audioBuffer.getNumSamples();
385+
const int numChannels = audioBuffer.getNumChannels();
386+
378387
for (int i = 0; i < numSamples; ++i)
379388
{
380389
// Update crossover frequency smoothly
@@ -386,12 +395,30 @@ class CrossoverDemo : public yup::Component,
386395
filter8.setFrequency (freq);
387396
}
388397

389-
// Generate white noise
390-
float noise = noiseGenerator.getNextSample() * 0.2f;
398+
// Get the audio sample from the loaded file (mono to stereo if needed)
399+
float audioSample = 0.0f;
400+
401+
if (numChannels == 1)
402+
{
403+
// Mono file
404+
audioSample = audioBuffer.getSample (0, readPosition) * 0.3f;
405+
}
406+
else
407+
{
408+
// Stereo or multichannel - mix to mono
409+
for (int ch = 0; ch < yup::jmin(2, numChannels); ++ch)
410+
audioSample += audioBuffer.getSample (ch, readPosition) * 0.3f;
411+
audioSample /= yup::jmin(2, numChannels);
412+
}
413+
414+
// Increment read position and wrap around for looping
415+
readPosition++;
416+
if (readPosition >= totalSamples)
417+
readPosition = 0;
391418

392419
// Process through crossover
393420
float lowLeft, lowRight, highLeft, highRight;
394-
filterProcess (noise, noise, lowLeft, lowRight, highLeft, highRight);
421+
filterProcess (audioSample, audioSample, lowLeft, lowRight, highLeft, highRight);
395422

396423
// Apply gains
397424
float lowGainValue = lowGain.getNextValue();
@@ -409,12 +436,52 @@ class CrossoverDemo : public yup::Component,
409436
}
410437

411438
private:
439+
void loadAudioFile()
440+
{
441+
// Create the path to the audio file
442+
auto dataDir = yup::File (__FILE__)
443+
.getParentDirectory()
444+
.getParentDirectory()
445+
.getParentDirectory()
446+
.getChildFile ("data");
447+
448+
yup::File audioFile = dataDir.getChildFile ("break_boomblastic_92bpm.wav");
449+
if (! audioFile.existsAsFile())
450+
{
451+
std::cerr << "Could not find break_boomblastic_92bpm.wav" << std::endl;
452+
return;
453+
}
454+
455+
// Load the audio file
456+
yup::AudioFormatManager formatManager;
457+
formatManager.registerDefaultFormats();
458+
459+
if (auto reader = formatManager.createReaderFor (audioFile))
460+
{
461+
audioBuffer.setSize ((int) reader->numChannels, (int) reader->lengthInSamples);
462+
reader->read (&audioBuffer, 0, (int) reader->lengthInSamples, 0, true, true);
463+
464+
std::cout << "Loaded audio file: " << audioFile.getFileName() << std::endl;
465+
std::cout << "Sample rate: " << reader->sampleRate << " Hz" << std::endl;
466+
std::cout << "Channels: " << reader->numChannels << std::endl;
467+
std::cout << "Length: " << reader->lengthInSamples << " samples" << std::endl;
468+
}
469+
else
470+
{
471+
std::cerr << "Failed to create reader for audio file" << std::endl;
472+
}
473+
}
474+
412475
void createUI()
413476
{
414477
setOpaque (false);
415478

479+
// Get a 12pt font
480+
auto labelFont = yup::ApplicationTheme::getGlobalTheme()->getDefaultFont().withHeight (12.0f);
481+
416482
// Order selection
417483
orderLabel.setText ("Filter Order", yup::NotificationType::dontSendNotification);
484+
orderLabel.setFont (labelFont);
418485
addAndMakeVisible (orderLabel);
419486

420487
orderComboBox.addItem ("2nd Order", 1);
@@ -435,6 +502,7 @@ class CrossoverDemo : public yup::Component,
435502

436503
// Crossover frequency slider
437504
freqLabel.setText ("Crossover Frequency", yup::NotificationType::dontSendNotification);
505+
freqLabel.setFont (labelFont);
438506
addAndMakeVisible (freqLabel);
439507

440508
freqSlider.setRange (20.0, 20000.0);
@@ -450,7 +518,8 @@ class CrossoverDemo : public yup::Component,
450518

451519
// Low gain slider
452520
lowGainLabel.setText ("Low", yup::NotificationType::dontSendNotification);
453-
//lowGainLabel.setJustification (yup::Justification::center);
521+
lowGainLabel.setFont (labelFont);
522+
lowGainLabel.setJustification (yup::Justification::center);
454523
//lowGainLabel.setColour (yup::Label::textColourId, yup::Color (0xFF4488FF));
455524
addAndMakeVisible (lowGainLabel);
456525

@@ -465,7 +534,8 @@ class CrossoverDemo : public yup::Component,
465534

466535
// High gain slider
467536
highGainLabel.setText ("High", yup::NotificationType::dontSendNotification);
468-
//highGainLabel.setJustification (yup::Justification::center);
537+
highGainLabel.setFont (labelFont);
538+
highGainLabel.setJustification (yup::Justification::center);
469539
//highGainLabel.setColour (yup::Label::textColourId, yup::Color (0xFFFF8844));
470540
addAndMakeVisible (highGainLabel);
471541

@@ -546,7 +616,8 @@ class CrossoverDemo : public yup::Component,
546616

547617
// Audio
548618
yup::AudioDeviceManager audioDeviceManager;
549-
yup::WhiteNoise noiseGenerator;
619+
yup::AudioBuffer<float> audioBuffer;
620+
int readPosition = 0;
550621

551622
// Filters
552623
yup::LinkwitzRiley2Filter<float> filter2;
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
==============================================================================
3+
4+
This file is part of the YUP library.
5+
Copyright (c) 2025 - [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+
namespace yup
23+
{
24+
25+
AudioFormatManager::AudioFormatManager()
26+
{
27+
}
28+
29+
void AudioFormatManager::registerDefaultFormats()
30+
{
31+
// Register Wave format
32+
registerFormat (std::make_unique<WaveAudioFormat>());
33+
34+
// TODO: Add other formats like:
35+
// registerFormat (std::make_unique<AiffAudioFormat>());
36+
// registerFormat (std::make_unique<FlacAudioFormat>());
37+
// registerFormat (std::make_unique<OggVorbisAudioFormat>());
38+
// registerFormat (std::make_unique<MP3AudioFormat>());
39+
}
40+
41+
void AudioFormatManager::registerFormat (std::unique_ptr<AudioFormat> format)
42+
{
43+
if (format != nullptr)
44+
formats.push_back (std::move (format));
45+
}
46+
47+
std::unique_ptr<AudioFormatReader> AudioFormatManager::createReaderFor (const File& file)
48+
{
49+
// Try to open the file
50+
auto stream = file.createInputStream();
51+
52+
if (stream == nullptr)
53+
return nullptr;
54+
55+
// Try each format
56+
for (auto& format : formats)
57+
{
58+
if (format->canHandleFile (file))
59+
{
60+
stream->setPosition (0);
61+
62+
if (auto reader = format->createReaderFor (stream.release()))
63+
return reader;
64+
}
65+
}
66+
67+
return nullptr;
68+
}
69+
70+
std::unique_ptr<AudioFormatWriter> AudioFormatManager::createWriterFor (const File& file,
71+
int sampleRate,
72+
int numChannels,
73+
int bitsPerSample)
74+
{
75+
// Try to create the output file
76+
auto stream = file.createOutputStream();
77+
78+
if (stream == nullptr)
79+
return nullptr;
80+
81+
// Try each format
82+
for (auto& format : formats)
83+
{
84+
if (format->canHandleFile (file))
85+
{
86+
StringPairArray metadataValues;
87+
88+
if (auto writer = format->createWriterFor (stream.release(),
89+
sampleRate,
90+
numChannels,
91+
bitsPerSample,
92+
metadataValues,
93+
0))
94+
return writer;
95+
}
96+
}
97+
98+
return nullptr;
99+
}
100+
101+
} // namespace yup
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
==============================================================================
3+
4+
This file is part of the YUP library.
5+
Copyright (c) 2025 - [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+
namespace yup
23+
{
24+
25+
/** A class that manages audio formats. */
26+
class YUP_API AudioFormatManager
27+
{
28+
public:
29+
/** Constructor. */
30+
AudioFormatManager();
31+
32+
/** Register the default formats. */
33+
void registerDefaultFormats();
34+
35+
/** Register a format.
36+
37+
@param format The format to register.
38+
*/
39+
void registerFormat (std::unique_ptr<AudioFormat> format);
40+
41+
/** Create a reader for a file.
42+
43+
@param file The file to create a reader for.
44+
45+
@return A pointer to the reader, or nullptr if the format cannot handle the file.
46+
*/
47+
std::unique_ptr<AudioFormatReader> createReaderFor (const File& file);
48+
49+
/** Create a writer for a file.
50+
51+
@param file The file to create a writer for.
52+
@param sampleRate The sample rate to use.
53+
@param numChannels The number of channels to use.
54+
@param bitsPerSample The number of bits per sample to use.
55+
56+
@return A pointer to the writer, or nullptr if the format cannot handle the file.
57+
*/
58+
std::unique_ptr<AudioFormatWriter> createWriterFor (const File& file,
59+
int sampleRate,
60+
int numChannels,
61+
int bitsPerSample);
62+
63+
private:
64+
std::vector<std::unique_ptr<AudioFormat>> formats;
65+
};
66+
67+
} // namespace yup

0 commit comments

Comments
 (0)