Skip to content

Commit

Permalink
[examples] Add an audio particle generator
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed May 8, 2024
1 parent 7763a02 commit b187e9d
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 0 deletions.
96 changes: 96 additions & 0 deletions examples/Advanced/AudioParticles/AudioParticles.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include "AudioParticles.hpp"

#include <score/tools/RecursiveWatch.hpp>

#include <QDirIterator>
namespace ao
{
void AudioParticles::prepare(halp::setup info)
{
this->rate = info.rate;
// Initialization, this method will be called with buffer size, etc.
m_sounds.clear();
m_sounds.reserve(1000);

score::for_all_files(inputs.folder.value, [this](std::string_view v) {
if(!v.ends_with(".wav"))
return;

const QString& path = QString::fromUtf8(v.data(), v.size());

auto dec = Media::AudioDecoder::decode_synchronous(path, this->rate);
if(!dec)
return;

m_sounds.push_back(std::move(dec->second));
});
}

std::optional<int>
frame_in_interval(int start_frame, int end_frame, double rate, double freq)
{
if(rate <= 0.)
return std::nullopt;

int64_t start_ns = 1e9 * start_frame / rate;
int64_t end_ns = 1e9 * end_frame / rate;
int64_t itv_ns = 1e9 / freq;
auto start_div = std::div(start_ns, itv_ns);
auto end_div = std::div(end_ns, itv_ns);
if(end_div.quot > start_div.quot)
{
return 1;
}
return std::nullopt;
}
void AudioParticles::operator()(const halp::tick_musical& t)
{
if(this->outputs.audio.channels != this->inputs.channels.value)
{
this->outputs.audio.request_channels(this->inputs.channels.value);
return;
}

if(m_sounds.empty())
return;

// FIXME range is not respected

if(inputs.frequency > 0.)
// Trigger new sounds
if(frame_in_interval(
t.position_in_frames, t.position_in_frames + t.frames, rate,
1. / (1. - inputs.frequency)))
{
if((1. - inputs.density) < std::exponential_distribution<float>()(m_rng))
m_playheads.push_back(Playhead{
0, uint16_t(unsigned(rand()) % m_sounds.size()),
uint16_t(unsigned(rand()) % this->outputs.audio.channels)});
}

for(auto& playhead : m_playheads)
{
SCORE_ASSERT(m_sounds.size() > playhead.index);
auto& sound = m_sounds[playhead.index];
int sound_frames = sound[0].size();

SCORE_ASSERT(outputs.audio.channels > playhead.channel);
auto channel = outputs.audio.channel(playhead.channel, t.frames);

if(sound_frames - playhead.frame > t.frames)
for(int i = playhead.frame; i < playhead.frame + t.frames; i++)
channel[i - playhead.frame] += sound[0][i];
else
{
for(int i = playhead.frame; i < sound_frames; i++)
channel[i - playhead.frame] += sound[0][i];
}
playhead.frame += t.frames;
}

ossia::remove_erase_if(m_playheads, [this](const auto& playhead) {
auto& sound = m_sounds[playhead.index];
return playhead.frame >= sound[0].size();
});
}
}
62 changes: 62 additions & 0 deletions examples/Advanced/AudioParticles/AudioParticles.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once
#include <Media/AudioDecoder.hpp>

#include <QFile>

#include <halp/audio.hpp>
#include <halp/controls.hpp>
#include <halp/mappers.hpp>
#include <halp/meta.hpp>
#include <rnd/include/rnd/random.hpp>
namespace ao
{
class AudioParticles
{
public:
halp_meta(name, "Audio particles")
halp_meta(category, "Audio/Generator")
halp_meta(c_name, "avnd_audio_particles")
halp_meta(uuid, "e7f2b091-0de0-49cd-a581-d4087d901fbb")

struct ins
{
halp::lineedit<"Folder", ""> folder;
halp::spinbox_i32<"Channels", halp::range{.min = 0., .max = 128, .init = 16}>
channels;
struct : halp::time_chooser<"Frequency", halp::range{0.001, 30., 0.2}>
{
using mapper = halp::log_mapper<std::ratio<95, 100>>;
} frequency;
halp::knob_f32<"Density", halp::range{0.001, 1., 0.7}> density;
} inputs;

struct
{
halp::variable_audio_bus<"Output", double> audio;
} outputs;

using setup = halp::setup;
void prepare(halp::setup info);

// Do our processing for N samples
using tick = halp::tick_musical;

// Defined in the .cpp
void operator()(const halp::tick_musical& t);

std::vector<Media::audio_array> m_sounds;

struct Playhead
{
int frame{};
uint16_t index{};
uint16_t channel{};
};

std::vector<Playhead> m_playheads;
double rate{};
std::random_device m_rdev;
rnd::pcg m_rng{m_rdev};
};

}

0 comments on commit b187e9d

Please sign in to comment.