Skip to content

Instantly share code, notes, and snippets.

@bolero-MURAKAMI
Created December 4, 2012 12:37
Show Gist options
  • Save bolero-MURAKAMI/4203389 to your computer and use it in GitHub Desktop.
Save bolero-MURAKAMI/4203389 to your computer and use it in GitHub Desktop.
// サンプル数 : デフォルト = 44100
#ifndef CMP_SAMPLE
# define CMP_SAMPLE 44100
#endif
// 長さの基準[sec] : デフォルト = 1
#ifndef CMP_LENGTH
# define CMP_LENGTH 1
#endif
// 基本音周波数[Hz] : デフォルト = 440(ラ音)
#ifndef CMP_BASE
# define CMP_BASE 440
#endif
#include <cstddef>
#include <cstdint>
#include <climits>
#include <sprout/compost.hpp>
#include <sprout/array.hpp>
#include <sprout/index_tuple.hpp>
#include "wave_io.hpp"
namespace cmp = sprout::compost;
static constexpr std::size_t sample_per_sec = CMP_SAMPLE;
static constexpr double length = CMP_LENGTH;
static constexpr double base = CMP_BASE;
static constexpr std::size_t one_size = static_cast<std::size_t>(length * sample_per_sec);
//
// 音符
//
struct note {
public:
double length;
double semitones;
double amplitude;
};
//
// 1音を生成
//
constexpr auto sounded_one(note const& n)
-> decltype(
cmp::waves::sinusoidal(cmp::equal_temperament_value(n.semitones) * base / sample_per_sec, n.amplitude)
| cmp::ranges::taken(static_cast<std::size_t>(n.length * one_size))
)
{
return cmp::waves::sinusoidal(cmp::equal_temperament_value(n.semitones) * base / sample_per_sec, n.amplitude)
| cmp::ranges::taken(static_cast<std::size_t>(n.length * one_size))
;
}
//
// 音を生成
//
template<typename Note>
constexpr auto sounded_x(Note const& note)
-> decltype(sounded_one(note))
{
return sounded_one(note);
}
template<typename Note, typename... Tail>
constexpr auto sounded_x(Note const& note, Tail const&... tail)
-> decltype(sounded_one(note) | cmp::ranges::jointed(sounded_x(tail...)))
{
return sounded_one(note) | cmp::ranges::jointed(sounded_x(tail...));
}
template<typename Score, sprout::index_t... Indexes>
constexpr auto sounded_i(Score const& score, sprout::index_tuple<Indexes...>)
-> decltype(sounded_x(score[Indexes]...))
{
return sounded_x(score[Indexes]...);
}
template<typename Score>
constexpr auto sounded(Score const& score)
-> decltype(sounded_i(score, sprout::index_range<0, Score::static_size>::make()))
{
return sounded_i(score, sprout::index_range<0, Score::static_size>::make());
}
int main(int argc, char* argv[]) {
namespace cmp = sprout::compost;
// スコア
constexpr sprout::array<note, CMP_SCORE0_NUM> score0{CMP_SCORE0};
constexpr sprout::array<note, CMP_SCORE1_NUM> score1{CMP_SCORE1};
// 波形の生成(変換前)
constexpr auto src = sounded(score0) | cmp::effects::superposed(sounded(score1));
constexpr std::size_t size = sprout::size(src);
typedef double src_elem_t;
typedef sprout::array<src_elem_t, size> src_t;
typedef std::int16_t wav_elem_t;
typedef sprout::array<wav_elem_t, size> wav_t;
// WAVE の情報
constexpr sprout::compost::sources::info_type wav_info{
1, // フォーマットID
1, // チャンネル数
sample_per_sec, // サンプリングレート
sample_per_sec * sizeof(wav_elem_t), // データ速度 (Byte/sec)
sizeof(wav_elem_t), // ブロックサイズ (Byte/sample*チャンネル数)
sizeof(wav_elem_t) * CHAR_BIT, // サンプルあたりのビット数 (bit/sample)
size // 要素数
};
// 波形の生成
constexpr wav_t wav_data =
src
| cmp::formats::as_pcm_wave16 // 16bitWAVE に変換
| cmp::ranges::copied // 任意のコンテナに変換可能にする
;
// ================ ここまでコンパイル時 ================
// WAVE ファイルに出力
char const* filename = argc >= 2 ? argv[1] : "sine_performer.wav";
output_wav(filename, wav_info, wav_data);
// dsp デバイスのセットアップ
int fd = setup_dev_dsp(wav_info);
if (fd < 0) {
return 0;
}
// dsp デバイスに書き込み
write_dev_dsp(fd, wav_data.data(), wav_data.size() * sizeof(wav_elem_t));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment