Compare commits

..

No commits in common. "16f1d8656b68b5f46636f36824981368e86ed598" and "eb95032dfa68254768e91198bf82d1e9e41b9123" have entirely different histories.

21 changed files with 63 additions and 509 deletions

View File

@ -2,8 +2,8 @@
Signals Signals
======= =======
Signal primitives Signal Types
----------------- ------------
MuzGen use different kind of signals for sound design. MuzGen use different kind of signals for sound design.
@ -39,60 +39,3 @@ To generate a sine, we can use the ``sine`` command.
# sine signal with a frequency of 440 and an amplitude of 1 # sine signal with a frequency of 440 and an amplitude of 1
[sine 440 1] [sine 440 1]
Noise
^^^^^
The noise command generate uniform random frames.
.. code-block::
[noise]
Signal operations
-----------------
The signal operation commands allows us to combine signals in
different ways.
Add
^^^
The ``sum`` command takes two signals as input and outputs their sum.
.. code-block::
[sum [sine 220] [sine 220]]
Sub
^^^
The ``sub`` command takes two signals as input and outputs their
difference.
.. code-block::
[sub [sine 460] [sine 80]]
Mul
^^^
The ``mul`` command takes two signals as input and output their product.
.. code-block::
[mul 0.7 [sine 220]]
Div
^^^
The ``div`` command takes two signals as input and output their ratio.
.. code-block::
[div [sine 220] 2]

View File

@ -1,33 +0,0 @@
#include "Add.hpp"
namespace muz
{
/*explicit*/ Add::Add(AudioConf const& conf,
std::unique_ptr<Signal> lhs,
std::unique_ptr<Signal> rhs)
: m_conf { conf }
, m_out_left { std::vector<float>(m_conf.channels(), 0.0f) }
, m_out_right { std::vector<float>(m_conf.channels(), 0.0f) }
, m_lhs { std::move(lhs) }
, m_rhs { std::move(rhs) }
{
}
/*virtual*/ Add::~Add()
{
}
void Add::next(std::vector<float>& out) /*override*/
{
m_lhs->next(m_out_left);
m_rhs->next(m_out_right);
assert(m_out_left.size() == m_out_right.size());
assert(m_out_left.size() == static_cast<size_t>(m_conf.channels()));
for (int i=0; i<m_conf.channels(); i++)
{
out[i] = m_out_left[i] + m_out_right[i];
}
}
}

View File

@ -1,32 +0,0 @@
#ifndef muz_ADD_HPP
#define muz_ADD_HPP
#include "commons.hpp"
#include "Signal.hpp"
#include "AudioConf.hpp"
namespace muz
{
/**
* Sum of two input signals.
**/
class Add: public Signal
{
public:
explicit Add(AudioConf const& conf,
std::unique_ptr<Signal> lhs,
std::unique_ptr<Signal> rhs);
virtual ~Add();
void next(std::vector<float>& out) override;
private:
AudioConf m_conf;
std::vector<float> m_out_left;
std::vector<float> m_out_right;
std::unique_ptr<Signal> m_lhs;
std::unique_ptr<Signal> m_rhs;
};
}
#endif

View File

@ -5,7 +5,6 @@ namespace muz
{ {
/*explicit*/ AudioEngine::AudioEngine(AudioConf const& conf) /*explicit*/ AudioEngine::AudioEngine(AudioConf const& conf)
: m_conf { conf } : m_conf { conf }
, m_frame { std::vector<float>(m_conf.channels(), 0.0f) }
{ {
check_error(Pa_Initialize()); check_error(Pa_Initialize());
} }
@ -81,9 +80,15 @@ namespace muz
return {0.0f, 0.0f}; return {0.0f, 0.0f};
} }
m_sig_queue.back()->next(m_frame); auto frame = m_sig_queue.back()->next();
return m_frame; if (frame.empty())
{
pop_signal();
return next();
}
return frame;
} }
/*static*/ int AudioEngine::callback(void const*, void* output, /*static*/ int AudioEngine::callback(void const*, void* output,
@ -98,7 +103,7 @@ namespace muz
for (size_t i=0; i<frames_per_buffer; i++) for (size_t i=0; i<frames_per_buffer; i++)
{ {
auto const& frame = engine->next(); auto frame = engine->next();
for (float val: frame) for (float val: frame)
{ {

View File

@ -47,7 +47,6 @@ namespace muz
PaStream* m_stream = nullptr; PaStream* m_stream = nullptr;
std::vector<std::unique_ptr<Signal>> m_sig_queue; std::vector<std::unique_ptr<Signal>> m_sig_queue;
std::mutex m_sig_mtx; std::mutex m_sig_mtx;
std::vector<float> m_frame;
/** /**
* Throws an audio_error exception if err is an error. * Throws an audio_error exception if err is an error.

View File

@ -9,22 +9,13 @@ configure_file(
add_library(muz-lib OBJECT add_library(muz-lib OBJECT
# Audio # Audio
# =====
Signal.cpp Signal.cpp
AudioEngine.cpp AudioEngine.cpp
AudioConf.cpp AudioConf.cpp
# signals
# -------
Constant.cpp Constant.cpp
Sine.cpp Sine.cpp
Noise.cpp
Add.cpp
Sub.cpp
Mul.cpp
Div.cpp
# Language # Language
# ========
Node.cpp Node.cpp
Lexer.cpp Lexer.cpp
Parser.cpp Parser.cpp

View File

@ -1,14 +1,6 @@
#include "Compiler.hpp" #include "Compiler.hpp"
// signals
// -------
#include "Constant.hpp" #include "Constant.hpp"
#include "Sine.hpp" #include "Sine.hpp"
#include "Noise.hpp"
#include "Add.hpp"
#include "Sub.hpp"
#include "Mul.hpp"
#include "Div.hpp"
namespace muz namespace muz
{ {
@ -46,8 +38,23 @@ namespace muz
compile_node(node->child(i)); compile_node(node->child(i));
} }
execute_cmd(name, node); if (name == "sine")
{
check_cmd_arity(*node, 2);
auto one = pop();
auto signal = std::make_unique<Sine>(m_conf,
std::move(pop()),
std::move(one));
push(std::move(signal));
}
else
{
throw compile_error {
std::string()
+ "cannot compile unknown command '" + name + "'."
};
}
} break; } break;
case NODE_DIR: { case NODE_DIR: {
@ -60,10 +67,10 @@ namespace muz
} }
else else
{ {
format_error<compile_error>(node->line(), throw compile_error {
"cannot compile unknown directive '" std::string()
+ name + "cannot compile unknown directive '" + name + "'."
+ "'."); };
} }
} break; } break;
@ -77,82 +84,6 @@ namespace muz
} }
} }
void Compiler::execute_cmd(std::string const& name,
std::shared_ptr<Node> node)
{
if (name == "sine")
{
check_cmd_arity(*node, 2);
auto one = pop();
auto signal = std::make_unique<Sine>(m_conf,
pop(),
std::move(one));
push(std::move(signal));
}
else if (name == "noise")
{
check_cmd_arity(*node, 0);
auto signal = std::make_unique<Noise>(m_conf);
push(std::move(signal));
}
else if (name == "add")
{
check_cmd_arity(*node, 2);
auto rhs = pop();
auto lhs = pop();
auto signal = std::make_unique<Add>(m_conf,
std::move(lhs),
std::move(rhs));
push(std::move(signal));
}
else if (name == "sub")
{
check_cmd_arity(*node, 2);
auto rhs = pop();
auto lhs = pop();
auto signal = std::make_unique<Sub>(m_conf,
std::move(lhs),
std::move(rhs));
push(std::move(signal));
}
else if (name == "mul")
{
check_cmd_arity(*node, 2);
auto rhs = pop();
auto lhs = pop();
auto signal = std::make_unique<Mul>(m_conf,
std::move(lhs),
std::move(rhs));
push(std::move(signal));
}
else if (name == "div")
{
check_cmd_arity(*node, 2);
auto rhs = pop();
auto lhs = pop();
auto signal = std::make_unique<Div>(m_conf,
std::move(lhs),
std::move(rhs));
push(std::move(signal));
}
else
{
format_error<compile_error>(node->line(),
"cannot compile unknown command '"
+ name
+ "'.");
}
}
void Compiler::push(std::unique_ptr<Signal> signal) void Compiler::push(std::unique_ptr<Signal> signal)
{ {
m_signals.push_back(std::move(signal)); m_signals.push_back(std::move(signal));
@ -169,15 +100,15 @@ namespace muz
{ {
if (node.size() - 1 != static_cast<size_t>(arity)) if (node.size() - 1 != static_cast<size_t>(arity))
{ {
format_error<compile_error>(node.line(), throw compile_error {
"arity mismatch for '" std::string()
+ node.child(0)->value() + "arity mismatch for '"
+ "': expected <" + node.child(0)->value()
+ std::to_string(arity) + "': expected <"
+ ">, got <" + std::to_string(arity)
+ std::to_string(node.size() - 1) + ">, got <"
+ ">."); + std::to_string(node.size() - 1)
+ ">."};
} }
} }
} }

View File

@ -24,7 +24,6 @@ namespace muz
std::vector<std::unique_ptr<Signal>> compile(std::shared_ptr<Node> node); std::vector<std::unique_ptr<Signal>> compile(std::shared_ptr<Node> node);
void compile_node(std::shared_ptr<Node> node); void compile_node(std::shared_ptr<Node> node);
void execute_cmd(std::string const& name, std::shared_ptr<Node> node);
private: private:
AudioConf const& m_conf; AudioConf const& m_conf;

View File

@ -12,11 +12,15 @@ namespace muz
{ {
} }
void Constant::next(std::vector<float>& out) /*override*/ std::vector<float> Constant::next() /*override*/
{ {
std::vector<float> out;
for (int i=0; i<m_conf.channels(); i++) for (int i=0; i<m_conf.channels(); i++)
{ {
out[i] = m_value; out.push_back(m_value);
} }
return out;
} }
} }

View File

@ -15,11 +15,10 @@ namespace muz
explicit Constant(AudioConf const& conf, float value=0.0f); explicit Constant(AudioConf const& conf, float value=0.0f);
virtual ~Constant(); virtual ~Constant();
void next(std::vector<float>& out) override; std::vector<float> next() override;
private: private:
AudioConf m_conf; AudioConf m_conf;
float m_value; float m_value;
}; };
} }

View File

@ -1,33 +0,0 @@
#include "Div.hpp"
namespace muz
{
/*explicit*/ Div::Div(AudioConf const& conf,
std::unique_ptr<Signal> lhs,
std::unique_ptr<Signal> rhs)
: m_conf { conf }
, m_out_left { std::vector<float>(m_conf.channels(), 0.0f) }
, m_out_right { std::vector<float>(m_conf.channels(), 0.0f) }
, m_lhs { std::move(lhs) }
, m_rhs { std::move(rhs) }
{
}
/*virtual*/ Div::~Div()
{
}
void Div::next(std::vector<float>& out) /*override*/
{
m_lhs->next(m_out_left);
m_rhs->next(m_out_right);
assert(m_out_left.size() == m_out_right.size());
assert(m_out_left.size() == static_cast<size_t>(m_conf.channels()));
for (int i=0; i<m_conf.channels(); i++)
{
out[i] = m_out_left[i] / m_out_right[i];
}
}
}

View File

@ -1,33 +0,0 @@
#ifndef muz_DIV_HPP
#define muz_DIV_HPP
#include "commons.hpp"
#include "Signal.hpp"
#include "AudioConf.hpp"
namespace muz
{
/**
* Division of two input signals.
**/
class Div: public Signal
{
public:
explicit Div(AudioConf const& conf,
std::unique_ptr<Signal> lhs,
std::unique_ptr<Signal> rhs);
virtual ~Div();
void next(std::vector<float>& out) override;
private:
AudioConf m_conf;
std::vector<float> m_out_left;
std::vector<float> m_out_right;
std::unique_ptr<Signal> m_lhs;
std::unique_ptr<Signal> m_rhs;
};
}
#endif

View File

@ -1,33 +0,0 @@
#include "Mul.hpp"
namespace muz
{
/*explicit*/ Mul::Mul(AudioConf const& conf,
std::unique_ptr<Signal> lhs,
std::unique_ptr<Signal> rhs)
: m_conf { conf }
, m_out_left { std::vector<float>(m_conf.channels(), 0.0f) }
, m_out_right { std::vector<float>(m_conf.channels(), 0.0f) }
, m_lhs { std::move(lhs) }
, m_rhs { std::move(rhs) }
{
}
/*virtual*/ Mul::~Mul()
{
}
void Mul::next(std::vector<float>& out) /*override*/
{
m_lhs->next(m_out_left);
m_rhs->next(m_out_right);
assert(m_out_left.size() == m_out_right.size());
assert(m_out_left.size() == static_cast<size_t>(m_conf.channels()));
for (int i=0; i<m_conf.channels(); i++)
{
out[i] = m_out_left[i] * m_out_right[i];
}
}
}

View File

@ -1,32 +0,0 @@
#ifndef muz_MUL_HPP
#define muz_MUL_HPP
#include "commons.hpp"
#include "Signal.hpp"
#include "AudioConf.hpp"
namespace muz
{
/**
* Product of two input signals.
**/
class Mul: public Signal
{
public:
explicit Mul(AudioConf const& conf,
std::unique_ptr<Signal> lhs,
std::unique_ptr<Signal> rhs);
virtual ~Mul();
void next(std::vector<float>& out) override;
private:
AudioConf m_conf;
std::vector<float> m_out_left;
std::vector<float> m_out_right;
std::unique_ptr<Signal> m_lhs;
std::unique_ptr<Signal> m_rhs;
};
}
#endif

View File

@ -1,24 +0,0 @@
#include "Noise.hpp"
namespace muz
{
/*explicit*/ Noise::Noise(AudioConf const& conf)
: m_conf { conf }
{
m_rand.seed(std::chrono::steady_clock::now().time_since_epoch().count());
}
/*virtual*/ Noise::~Noise()
{
}
void Noise::next(std::vector<float>& out) /*override*/
{
float value = m_distribution(m_rand);
for (int i=0; i<m_conf.channels(); i++)
{
out[i] = value;
}
}
}

View File

@ -1,31 +0,0 @@
#ifndef muz_NOISE_HPP
#define muz_NOISE_HPP
#include <random>
#include <chrono>
#include "commons.hpp"
#include "AudioConf.hpp"
#include "Signal.hpp"
namespace muz
{
/**
* White noise signal.
* @see Signal
**/
class Noise: public Signal
{
public:
explicit Noise(AudioConf const& conf);
virtual ~Noise();
void next(std::vector<float>& out) override;
private:
AudioConf m_conf;
std::mt19937 m_rand;
std::uniform_real_distribution<float> m_distribution {-0.5f, 0.5f};
};
}
#endif

View File

@ -19,10 +19,11 @@ namespace muz
virtual ~Signal(); virtual ~Signal();
/** /**
* Get the next frame. * Get the next sample.
* @param out the output buffer that will contain the next frame. * @return std::vector<float> of size N for a sample of N channels or an empty vector at end.
*
**/ **/
virtual void next(std::vector<float>& out) = 0; virtual std::vector<float> next() = 0;
private: private:
}; };
} }

View File

@ -6,8 +6,6 @@ namespace muz
std::unique_ptr<Signal> freq, std::unique_ptr<Signal> freq,
std::unique_ptr<Signal> amplitude) std::unique_ptr<Signal> amplitude)
: m_conf { conf } : m_conf { conf }
, m_out_freq {std::vector<float> (m_conf.channels(), 0.0f)}
, m_out_amp {std::vector<float> (m_conf.channels(), 0.0f)}
, m_freq { std::move(freq) } , m_freq { std::move(freq) }
, m_amplitude { std::move(amplitude) } , m_amplitude { std::move(amplitude) }
{ {
@ -21,28 +19,31 @@ namespace muz
{ {
} }
void Sine::next(std::vector<float>& out) /*override*/ std::vector<float> Sine::next() /*override*/
{ {
assert(m_freq); assert(m_freq);
assert(m_amplitude); assert(m_amplitude);
m_freq->next(m_out_freq); std::vector<float> out;
m_amplitude->next(m_out_amp); auto freqs = m_freq->next();
auto amps = m_amplitude->next();
if (m_out_freq.size() != m_out_amp.size() if (freqs.size() != amps.size()
|| m_out_freq.size() != m_phases.size()) || freqs.size() != m_phases.size())
{ {
throw signal_error {"cannot generate sine: channel number mismatch"}; throw signal_error {"cannot generate sine: channel number mismatch"};
} }
for (size_t i=0; i<static_cast<size_t>(m_conf.channels()); i++) for (size_t i=0; i<static_cast<size_t>(m_conf.channels()); i++)
{ {
float const value = m_out_amp[i] * std::sin(m_phases[i]); float const value = amps[i] * std::sin(m_phases[i]);
m_phases[i] += 2 * M_PI * m_out_freq[i] m_phases[i] += 2 * M_PI * freqs[i]
/ static_cast<float>(m_conf.samplerate()); / static_cast<float>(m_conf.samplerate());
out[i] = value; out.push_back(value);
} }
return out;
} }
} }

View File

@ -18,12 +18,9 @@ namespace muz
std::unique_ptr<Signal> amplitude); std::unique_ptr<Signal> amplitude);
virtual ~Sine(); virtual ~Sine();
void next(std::vector<float>& out) override; std::vector<float> next() override;
private: private:
AudioConf const& m_conf; AudioConf const& m_conf;
std::vector<float> m_out_freq;
std::vector<float> m_out_amp;
std::unique_ptr<Signal> m_freq; std::unique_ptr<Signal> m_freq;
std::unique_ptr<Signal> m_amplitude; std::unique_ptr<Signal> m_amplitude;
std::vector<float> m_phases; std::vector<float> m_phases;

View File

@ -1,33 +0,0 @@
#include "Sub.hpp"
namespace muz
{
/*explicit*/ Sub::Sub(AudioConf const& conf,
std::unique_ptr<Signal> lhs,
std::unique_ptr<Signal> rhs)
: m_conf { conf }
, m_out_left { std::vector<float>(m_conf.channels(), 0.0f) }
, m_out_right { std::vector<float>(m_conf.channels(), 0.0f) }
, m_lhs { std::move(lhs) }
, m_rhs { std::move(rhs) }
{
}
/*virtual*/ Sub::~Sub()
{
}
void Sub::next(std::vector<float>& out) /*override*/
{
m_lhs->next(m_out_left);
m_rhs->next(m_out_right);
assert(m_out_left.size() == m_out_right.size());
assert(m_out_left.size() == static_cast<size_t>(m_conf.channels()));
for (int i=0; i<m_conf.channels(); i++)
{
out[i] = m_out_left[i] - m_out_right[i];
}
}
}

View File

@ -1,32 +0,0 @@
#ifndef muz_SUB_HPP
#define muz_SUB_HPP
#include "commons.hpp"
#include "Signal.hpp"
#include "AudioConf.hpp"
namespace muz
{
/**
* Substraction of two input signals.
**/
class Sub: public Signal
{
public:
explicit Sub(AudioConf const& conf,
std::unique_ptr<Signal> lhs,
std::unique_ptr<Signal> rhs);
virtual ~Sub();
void next(std::vector<float>& out) override;
private:
AudioConf m_conf;
std::vector<float> m_out_left;
std::vector<float> m_out_right;
std::unique_ptr<Signal> m_lhs;
std::unique_ptr<Signal> m_rhs;
};
}
#endif