Skip to content

Instantly share code, notes, and snippets.

@planaria
Last active September 3, 2016 03:32
Show Gist options
  • Save planaria/e51e92d406f73c4994526cfa162b6726 to your computer and use it in GitHub Desktop.
Save planaria/e51e92d406f73c4994526cfa162b6726 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <fstream>
#include <array>
#include <map>
#include <algorithm>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/numeric/odeint.hpp>
namespace cvcpp
{
double lerp(double x1, double x2, double ratio)
{
return x1 + (x2 - x1) * ratio;
}
double pow2(double x)
{
return x * x;
}
static const std::size_t num_vocal_tracts = 46;
struct key_frame
{
double pressure = 0.0;
double tension = 0.0;
std::array<double, num_vocal_tracts> tract_widths = {};
};
key_frame lerp(const key_frame& k1, const key_frame& k2, double ratio)
{
key_frame result;
result.pressure = lerp(k1.pressure, k2.pressure, ratio);
result.tension = lerp(k1.tension, k2.tension, ratio);
for (std::size_t i = 0; i < num_vocal_tracts; ++i)
result.tract_widths[i] = lerp(k1.tract_widths[i], k2.tract_widths[i], ratio);
return result;
}
struct cord_state
{
double x1;
double x2;
double x1v;
double x2v;
double ug;
std::array<double, num_vocal_tracts> u;
std::array<double, num_vocal_tracts> p;
};
class cord_system
{
public:
static const int num_variables = sizeof(cord_state) / sizeof(double);
static_assert(sizeof(cord_state) == sizeof(double) * num_variables, "");
cord_system(const key_frame& begin_key, const key_frame& end_key, double end_time)
: begin_key_(begin_key)
, end_key_(end_key)
, end_time_(end_time)
{
}
template <class state_type>
void operator ()(const state_type& x_, state_type& dxdt_, double t) const
{
const cord_state& x = state(x_);
cord_state& dxdt = state(dxdt_);
double ratio = t / end_time_;
key_frame key = lerp(begin_key_, end_key_, ratio);
double ps = key.pressure * 5.0;
double k1 = 5000000.0 * key.tension;
double k2 = 3900000.0 * key.tension;
double k12 = 2000000.0 * key.tension;
static const double length1 = 1.0;
static const double length2 = 1.0;
static const double mass_fluid = 0.02;
static const double mass1 = 1.0;
static const double mass2 = 1.0;
static const double c1 = 30.0;
static const double c2 = 30.0;
static const double density = 100000.0;
static const double x1_base = 0.1;
static const double x2_base = 0.1;
static const double x1_min = 0.01;
static const double x2_min = 0.01;
static const double x1_max = 10.0;
static const double x2_max = 10.0;
static const double friction1 = 1.0;
static const double friction2 = 1.0;
double x1_shift = std::max(x1_min, std::min(x1_max, x.x1 + x1_base));
double x2_shift = std::max(x2_min, std::min(x2_max, x.x2 + x2_base));
double velocity1 = x.ug / x1_shift;
double velocity2 = x.ug / x2_shift;
double pressure1 = ps - length1 * pow2(velocity1) * density;
double pressure2 = ps - length2 * pow2(velocity2) * density;
dxdt.x1v = (pressure1 - x.x1 * k1 - x.x1v * c1 + (x.x2 - x.x1) * k12) / mass1;
dxdt.x2v = (pressure2 - x.x2 * k2 - x.x2v * c2 + (x.x1 - x.x2) * k12) / mass2;
dxdt.x1 = x.x1v;
dxdt.x2 = x.x2v;
double resistance1 = length1 * friction1 * velocity1;
double resistance2 = length2 * friction2 * velocity2;
double dp = ps - x.p[0] - resistance1 - resistance2;
dxdt.ug = dp / mass_fluid;
static const double tract_length = 3.2;
static const double tract_friction = 0.01;
static const double rho = 0.0001;
static const double speed_of_sound = 340290.0;
static const double width_min = 0.01;
double r = tract_friction * tract_length;
double inv_l_base = 1.0 / (rho * tract_length);
double inv_c_base = rho * pow2(speed_of_sound) / tract_length;
for (std::size_t i = 0; i < num_vocal_tracts; ++i)
{
double width = key.tract_widths[i];
if (width < width_min)
{
double inv_l = inv_l_base * width_min;
dxdt.u[i] = (-x.u[i] * r) * inv_l;
dxdt.p[i] = 0.0;
}
else
{
double inv_l = inv_l_base * width;
double inv_c = inv_c_base / width;
if (i != num_vocal_tracts - 1)
dxdt.u[i] = (x.p[i] - x.p[i + 1] - x.u[i] * r) * inv_l;
else
dxdt.u[i] = (x.p[i] - x.u[i] * r) * inv_l;
if (i == 0)
dxdt.p[i] = (x.ug - x.u[i]) * inv_c;
else
dxdt.p[i] = (x.u[i - 1] - x.u[i]) * inv_c;
}
}
}
template <class state_type>
const cord_state& state(const state_type& x) const
{
return *reinterpret_cast<const cord_state*>(&x[0]);
}
template <class state_type>
cord_state& state(state_type& x) const
{
return *reinterpret_cast<cord_state*>(&x[0]);
}
private:
key_frame begin_key_;
key_frame end_key_;
double end_time_;
};
void normalize(std::vector<double>& values, double volume)
{
if (values.empty())
return;
auto begin = boost::make_transform_iterator(values.begin(), &std::abs<double>);
auto end = boost::make_transform_iterator(values.end(), &std::abs<double>);
double maximum = *std::max_element(begin, end);
double magnify = volume / maximum;
for (double& value : values)
value *= magnify;
}
#pragma pack(push, 1)
struct wav_header
{
static const std::uint16_t format_linear = 1;
static const std::uint16_t bytes_per_sample = 2;
wav_header(
std::uint16_t num_channels_,
std::uint32_t sampling_rate_)
: riff({ 'R', 'I', 'F', 'F' })
, file_size()
, wave({ 'W', 'A', 'V', 'E' })
, fmt({ 'f', 'm', 't', ' ' })
, fmt_size(16)
, format_id(format_linear)
, num_channels(num_channels_)
, sampling_rate(sampling_rate_)
, bytes_per_sec(num_channels_ * sampling_rate_ * bytes_per_sample)
, block_size(num_channels_ * bytes_per_sample)
, bits_per_sample(bytes_per_sample * 8)
, data({ 'd', 'a', 't', 'a' })
, data_size()
{
}
std::array<char, 4> riff;
std::uint32_t file_size;
std::array<char, 4> wave;
std::array<char, 4> fmt;
std::uint32_t fmt_size;
std::uint16_t format_id;
std::uint16_t num_channels;
std::uint32_t sampling_rate;
std::uint32_t bytes_per_sec;
std::uint16_t block_size;
std::uint16_t bits_per_sample;
std::array<char, 4> data;
std::uint32_t data_size;
};
#pragma pack(pop)
void write_wav(
std::ostream& os,
const std::vector<double>& wave,
std::uint16_t num_channels,
std::uint32_t sampling_rate)
{
wav_header header(num_channels, sampling_rate);
std::size_t data_size = wave.size() * wav_header::bytes_per_sample;
header.file_size = boost::numeric_cast<std::uint32_t>(sizeof(header) + data_size - 8);
header.data_size = boost::numeric_cast<std::uint32_t>(data_size);
os.write(reinterpret_cast<const char*>(&header), sizeof(header));
for (double value : wave)
{
double f = std::max(-32768.0, std::min(32767.0, std::round(value * 32767.0)));
std::int16_t v = static_cast<std::int16_t>(f);
os.write(reinterpret_cast<const char*>(&v), sizeof(v));
}
}
void output(const std::map<double, cvcpp::key_frame>& key_frames, std::uint32_t sampling_rate)
{
namespace odeint = boost::numeric::odeint;
std::vector<double> values;
for (auto it = key_frames.begin(); it != std::prev(key_frames.end()); ++it)
{
auto next_it = std::next(it);
std::size_t num_steps = static_cast<std::size_t>(std::ceil((next_it->first - it->first) * static_cast<double>(sampling_rate)));
double dt = 1.0 / static_cast<double>(sampling_rate);
double end_time = static_cast<double>(num_steps) * dt;
typedef std::array<double, cord_system::num_variables> state_type;
state_type state = {};
static const double abs_error = 0.00001;
static const double rel_error = 0.00001;
typedef odeint::runge_kutta_dopri5<state_type> base_stepper_type;
auto stepper = odeint::make_controlled(abs_error, rel_error, base_stepper_type());
cord_system system(it->second, next_it->second, end_time);
std::size_t index = 0;
odeint::integrate_n_steps(stepper, system, state, 0.0, dt, num_steps,
[&](const state_type& x, double t)
{
if (index++ < num_steps)
values.push_back(system.state(x).u.back());
});
}
normalize(values, 0.1);
{
std::fstream os("output.wav", std::ios_base::out | std::ios_base::binary);
write_wav(os, values, 1, sampling_rate);
os.flush();
}
}
key_frame base_i(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 3.3, 3.0, 3.6, 3.4, 6.8, 5.0, 24.3, 31.5, 26.6, 24.9, 33.9, 38.0, 37.8, 43.5, 45.0, 44.3, 46.8, 45.2, 41.5, 40.9, 35.1, 29.5, 20.3, 16.6, 13.8, 10.5, 6.0, 3.5, 3.2, 1.2, 1.0, 1.6, 2.5, 2.4, 3.8, 2.8, 3.6, 6.5, 15.8, 20.5, 20.1, 15.8, 100.0, 100.0, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_e1(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 2.0, 1.7, 1.8, 1.8, 1.0, 10.8, 16.6, 16.4, 11.9, 9.2, 11.3, 24.8, 27.6, 29.7, 34.3, 33.2, 34.8, 39.6, 37.9, 38.8, 34.7, 29.8, 26.2, 23.7, 19.9, 19.0, 17.0, 14.4, 14.5, 10.6, 8.7, 7.5, 10.6, 12.9, 17.8, 18.3, 17.0, 19.7, 19.2, 16.2, 13.6, 11.8, 100.0, 100.0, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_e2(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 2.1, 1.3, 1.6, 1.4, 0.6, 7.8, 12.5, 12.4, 9.9, 7.2, 7.3, 10.6, 17.7, 19.7, 24.6, 27.0, 29.2, 30.3, 28.4, 28.4, 28.3, 23.6, 21.4, 20.0, 17.8, 18.1, 17.9, 15.0, 13.7, 13.6, 14.3, 18.3, 20.8, 25.9, 25.4, 21.1, 23.4, 27.4, 21.9, 16.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_e3(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 2.2, 2.6, 2.6, 1.6, 1.3, 2.1, 8.3, 15.0, 13.5, 9.9, 6.9, 13.5, 23.2, 21.3, 19.4, 21.7, 28.5, 32.6, 37.3, 38.0, 36.9, 38.7, 36.8, 32.0, 32.6, 32.9, 31.9, 32.3, 32.3, 34.0, 37.8, 38.4, 39.8, 44.1, 45.6, 47.9, 43.9, 44.2, 42.3, 45.6, 43.1, 39.4, 100.0, 100.0, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_a1(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 3.3, 2.8, 2.3, 1.5, 1.7, 3.3, 3.9, 10.2, 12.2, 11.4, 8.2, 7.6, 6.6, 8.0, 7.2, 6.6, 10.8, 9.1, 10.9, 10.6, 10.9, 11.7, 13.9, 15.5, 18.9, 21.7, 24.6, 26.5, 31.3, 38.1, 43.0, 45.7, 49.4, 55.8, 57.9, 55.1, 54.9, 46.9, 45.0, 32.1, 27.9, 21.1, 19.8, 11.7, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_a2(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 4.5, 2.0, 2.6, 2.1, 3.2, 3.0, 3.3, 10.5, 11.2, 8.5, 6.3, 3.9, 2.6, 2.8, 2.3, 3.2, 2.9, 2.8, 4.0, 6.6, 12.0, 10.5, 16.2, 20.9, 25.6, 27.8, 28.6, 30.2, 37.5, 46.0, 50.9, 60.2, 65.5, 62.9, 62.7, 59.4, 52.8, 47.0, 38.7, 41.3, 42.5, 42.7, 46.9, 50.3, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_a3(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 6.1, 2.8, 1.9, 1.0, 0.7, 3.0, 1.8, 11.3, 14.2, 12.1, 6.9, 5.1, 4.3, 6.6, 5.7, 3.2, 4.3, 4.5, 5.3, 6.0, 7.7, 6.5, 5.8, 9.4, 20.2, 25.0, 24.1, 26.2, 32.9, 43.4, 47.8, 52.4, 60.7, 70.8, 68.1, 62.0, 58.9, 50.4, 42.9, 24.9, 18.4, 13.3, 11.9, 8.8, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_o1(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 1.8, 1.7, 2.3, 2.8, 5.9, 14.6, 16.0, 11.1, 8.2, 10.1, 27.2, 27.1, 19.6, 19.2, 17.0, 16.6, 15.2, 12.8, 14.4, 12.8, 8.9, 12.5, 13.8, 10.9, 7.1, 4.6, 3.9, 3.2, 5.7, 10.6, 13.8, 22.9, 29.9, 37.4, 43.9, 53.8, 72.5, 70.0, 45.7, 27.5, 14.8, 6.8, 3.9, 1.4, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_o2(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 3.2, 3.9, 3.9, 4.3, 5.6, 14.6, 22.0, 20.6, 15.8, 11.1, 11.1, 12.6, 13.0, 9.8, 9.3, 8.3, 6.1, 9.7, 7.5, 9.3, 5.3, 6.5, 9.5, 9.9, 10.7, 13.9, 14.7, 17.9, 23.4, 26.8, 33.6, 39.8, 47.4, 54.8, 56.9, 55.7, 49.9, 44.8, 30.7, 16.7, 11.3, 6.4, 1.5, 2.2, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_u(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 4.0, 3.8, 2.8, 4.3, 5.5, 17.2, 29.1, 28.8, 23.7, 21.0, 36.3, 58.6, 56.3, 54.3, 48.0, 45.6, 42.9, 36.3, 33.7, 31.6, 33.1, 32.2, 23.3, 20.7, 20.7, 15.2, 7.4, 2.3, 1.5, 2.2, 2.2, 3.7, 6.0, 7.6, 8.6, 18.2, 23.5, 25.5, 37.3, 54.7, 44.6, 23.9, 11.0, 7.7, 4.1, 8.6 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_e4(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 4.1, 3.8, 4.0, 2.9, 1.3, 5.3, 15.8, 15.6, 12.2, 11.9, 10.0, 7.7, 9.2, 11.9, 12.7, 13.5, 14.8, 15.6, 16.1, 18.7, 21.0, 20.1, 26.2, 29.6, 30.7, 31.1, 27.7, 26.7, 24.7, 23.4, 22.5, 19.0, 13.2, 7.6, 4.4, 4.5, 9.2, 20.5, 32.5, 36.3, 35.9, 30.7, 22.5, 12.0, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_l(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 5.5, 6.3, 7.5, 18.0, 29.8, 35.6, 34.5, 32.2, 32.0, 26.7, 30.2, 35.5, 37.6, 35.3, 26.2, 24.0, 23.2, 24.3, 21.3, 22.7, 22.8, 22.6, 23.3, 24.3, 24.4, 25.4, 26.4, 26.7, 31.6, 36.8, 43.0, 51.4, 58.3, 64.4, 65.4, 69.1, 67.2, 56.1, 40.8, 27.3, 4.5, 9.0, 39.2, 49.9, 45.7, 37.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_m(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 5.7, 5.7, 2.1, 5.8, 21.8, 31.5, 29.6, 28.9, 37.0, 42.1, 35.7, 35.9, 29.7, 31.7, 32.5, 25.8, 27.4, 27.7, 24.9, 29.3, 33.3, 22.7, 25.7, 21.7, 18.4, 19.8, 17.3, 14.3, 17.3, 20.8, 23.2, 28.4, 35.1, 42.5, 47.9, 46.1, 40.7, 36.4, 28.4, 14.2, 2.9, 0.0, 0.0, 0.0, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_n(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 2.6, 2.4, 1.7, 2.1, 1.5, 3.6, 13.7, 16.6, 13.5, 9.0, 7.1, 9.3, 14.1, 20.7, 21.2, 20.4, 21.6, 23.6, 25.2, 28.8, 23.0, 19.3, 17.7, 9.6, 8.9, 12.2, 13.0, 13.0, 11.4, 7.7, 3.4, 1.5, 2.2, 2.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 15.9, 16.0, 16.9, 11.7, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_ou(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 5.1, 4.7, 4.5, 3.0, 4.8, 6.7, 8.3, 9.6, 14.3, 11.4, 8.4, 6.9, 8.2, 8.6, 5.7, 8.1, 10.0, 6.6, 8.0, 9.7, 7.8, 5.8, 4.6, 4.4, 4.7, 4.1, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 21.8, 47.2, 68.6, 85.8, 87.6, 72.1, 49.2, 32.1, 21.7, 14.1, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_p(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 3.1, 3.9, 4.2, 7.1, 12.8, 18.0, 17.0, 14.3, 12.5, 9.0, 20.6, 27.7, 21.9, 23.5, 26.7, 21.7, 17.7, 20.9, 21.6, 22.6, 22.6, 22.9, 21.7, 21.3, 26.4, 26.5, 23.0, 21.2, 16.7, 14.4, 11.6, 15.1, 17.6, 19.3, 19.8, 22.1, 23.5, 24.5, 23.7, 24.7, 17.5, 10.9, 7.0, 0.0, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_t(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 3.8, 5.0, 4.0, 10.7, 13.8, 16.5, 12.9, 10.1, 9.2, 8.6, 10.3, 16.0, 24.6, 22.4, 24.7, 28.6, 27.4, 33.2, 38.3, 39.7, 41.6, 44.1, 41.1, 39.5, 36.4, 33.7, 28.9, 26.1, 26.9, 23.2, 20.4, 16.4, 13.9, 12.6, 8.7, 6.0, 1.0, 0.0, 0.0, 1.3, 1.8, 14.8, 16.0, 14.3, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_k(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 3.4, 3.5, 4.9, 7.8, 13.1, 13.4, 11.9, 9.4, 6.9, 9.2, 14.5, 17.3, 16.7, 21.3, 16.1, 15.6, 15.4, 11.8, 14.4, 11.2, 7.6, 9.6, 10.9, 7.9, 2.5, 0.0, 0.6, 0.3, 0.9, 1.0, 0.6, 0.3, 4.8, 12.7, 22.8, 23.5, 24.0, 24.1, 42.1, 33.7, 24.6, 24.6, 21.4, 15.0, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
key_frame base_c(double tension = 1.0, double pressure = 1.0)
{
key_frame result;
std::array<double, num_vocal_tracts> widths = { 3.3, 3.0, 3.6, 3.4, 6.8, 5.0, 24.3, 31.5, 26.6, 24.9, 33.9, 38.0, 37.8, 43.5, 45.0, 44.3, 46.8, 45.2, 41.5, 40.9, 35.1, 29.5, 20.3, 16.6, 13.8, 10.5, 6.0, 3.5, 3.2, 1.2, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.6, 6.5, 15.8, 20.5, 20.1, 15.8, 100.0, 100.0, 100.0, 100.0 };
result.tension = tension;
result.pressure = pressure;
result.tract_widths = widths;
return result;
}
}
int main(int /*argc*/, char* /*argv*/[])
{
cvcpp::key_frame rest;
std::map<double, cvcpp::key_frame> key_frames =
{
{ 0.0, rest },
{ 1.0, rest },
{ 1.03, cvcpp::base_a1() },
{ 1.97, cvcpp::base_a1() },
{ 2.0, rest },
{ 3.0, rest },
{ 3.03, cvcpp::base_i() },
{ 3.97, cvcpp::base_i() },
{ 4.0, rest },
{ 5.0, rest },
{ 5.03, cvcpp::base_u() },
{ 5.97, cvcpp::base_u() },
{ 6.0, rest },
{ 7.0, rest },
{ 7.03, cvcpp::base_e1() },
{ 7.97, cvcpp::base_e1() },
{ 8.0, rest },
{ 9.0, rest },
{ 9.03, cvcpp::base_o1() },
{ 9.97, cvcpp::base_o1() },
{ 10.0, rest },
{ 11.0, rest },
};
std::int32_t sampling_rate = 44100;
cvcpp::output(key_frames, sampling_rate);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment