Created
December 3, 2012 12:39
-
-
Save bolero-MURAKAMI/4194789 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef APP_WAVE_IO_HPP | |
#define APP_WAVE_IO_HPP | |
#include <cstddef> | |
#include <cstdint> | |
#include <climits> | |
#include <string> | |
#include <algorithm> | |
#include <iostream> | |
#include <fstream> | |
#include <type_traits> | |
#include <sprout/compost/sources.hpp> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <sys/types.h> | |
#include <sys/ioctl.h> | |
#include <linux/soundcard.h> | |
// | |
// gnuplot 用の出力 | |
// | |
template<typename Elem, typename Traits, typename InputRange> | |
std::basic_ostream<Elem, Traits>& output_plot(std::basic_ostream<Elem, Traits>& os, InputRange const& range) { | |
os << std::fixed; | |
unsigned x = 0; | |
for (auto const& e : range) { | |
os << x++ << ',' << e << '\n'; | |
} | |
return os; | |
} | |
template<typename InputRange> | |
void output_plot(std::string const& filename, InputRange const& range) { | |
std::ofstream os(filename); | |
output_plot(os, range); | |
} | |
// | |
// gnuplot 用の出力 (複素数の実数成分のみ) | |
// | |
template<typename Elem, typename Traits, typename InputRange> | |
std::basic_ostream<Elem, Traits>& output_plot_real(std::basic_ostream<Elem, Traits>& os, InputRange const& range) { | |
os << std::fixed; | |
unsigned x = 0; | |
for (auto const& e : range) { | |
os << x++ << ',' << real(e) << '\n'; | |
} | |
return os; | |
} | |
template<typename InputRange> | |
void output_plot_real(std::string const& filename, InputRange const& range) { | |
std::ofstream os(filename); | |
output_plot_real(os, range); | |
} | |
// | |
// wave 形式の書き込み | |
// | |
template<typename OutputIterator> | |
void write_chunk(OutputIterator& it, std::string const& s) { | |
it = std::copy(s.begin(), s.end(), it); | |
} | |
template<typename IntType, typename OutputIterator> | |
void write_int(OutputIterator& it, IntType const& n) { | |
for (std::size_t i = 0; i != sizeof(IntType); ++i, ++it) { | |
*it = static_cast<char>((static_cast<typename std::make_unsigned<IntType>::type>(n) >> (i * CHAR_BIT)) & 0xFF); | |
} | |
} | |
template<typename OutputIterator> | |
void write_wav_header(OutputIterator& it, sprout::compost::sources::info_type const& info) { | |
std::size_t data_size = info.size * info.bits_per_sample; | |
write_chunk(it, "RIFF"); | |
write_int(it, 36 + data_size); | |
write_chunk(it, "WAVE"); | |
write_chunk(it, "fmt "); | |
write_int(it, 16); | |
write_int(it, info.format_tag); | |
write_int(it, info.channels); | |
write_int(it, info.samples_per_sec); | |
write_int(it, info.bytes_per_sec); | |
write_int(it, info.block_size); | |
write_int(it, info.bits_per_sample); | |
write_chunk(it, "data"); | |
write_int(it, data_size); | |
} | |
template<typename OutputIterator, typename InputRange> | |
void write_wav_data(OutputIterator& it, sprout::compost::sources::info_type const& info, InputRange const& data) { | |
if (info.bits_per_sample == 16) { | |
for (auto e : data) { | |
write_int<std::int16_t>(it, e); | |
} | |
} else if (info.bits_per_sample == 8) { | |
for (auto e : data) { | |
write_int<std::uint8_t>(it, e); | |
} | |
} | |
} | |
template<typename OutputIterator, typename InputRange> | |
void write_wav(OutputIterator& it, sprout::compost::sources::info_type const& info, InputRange const& data) { | |
write_wav_header(it, info); | |
write_wav_data(it, info, data); | |
} | |
// | |
// wave 形式の出力 | |
// | |
template<typename Elem, typename Traits, typename InputRange> | |
void output_wav(std::basic_ostream<Elem, Traits>& os, sprout::compost::sources::info_type const& info, InputRange const& data) { | |
std::ostreambuf_iterator<Elem> it(os); | |
write_wav(it, info, data); | |
} | |
template<typename InputRange> | |
void output_wav(std::string const& filename, sprout::compost::sources::info_type const& info, InputRange const& data) { | |
std::ofstream os(filename, std::ios_base::out | std::ios_base::binary); | |
output_wav(os, info, data); | |
} | |
template<typename Elem, typename Traits, typename InputRanges> | |
void output_wav_blocks(std::basic_ostream<Elem, Traits>& os, sprout::compost::sources::info_type const& info, InputRanges const& data) { | |
std::ostreambuf_iterator<Elem> it(os); | |
write_wav_header(it, info); | |
for (auto const& e : data) { | |
write_wav_data(it, info, e); | |
} | |
} | |
template<typename InputRanges> | |
void output_wav_blocks(std::string const& filename, sprout::compost::sources::info_type const& info, InputRanges const& data) { | |
std::ofstream os(filename, std::ios_base::out | std::ios_base::binary); | |
output_wav_blocks(os, info, data); | |
} | |
// | |
// dsp デバイスのセットアップ | |
// | |
int setup_dev_dsp(sprout::compost::sources::info_type const& info) { | |
// dsp デバイスのオープン | |
int fd = open("/dev/dsp", O_RDWR); | |
if (fd < 0) { | |
std::cerr << "open of /dev/dsp failed" << std::endl; | |
return -1; | |
} | |
// dsp デバイスの各種初期化 | |
int arg = 0; | |
int status = 0; | |
// サンプリングビット | |
arg = info.bits_per_sample; | |
status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg); | |
if (status == -1 || arg != info.bits_per_sample) { | |
return -1; | |
} | |
// データの種類 ステレオ or モノラル | |
arg = info.channels; | |
status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg); | |
if (status == -1 || arg != info.channels) { | |
return -1; | |
} | |
// サンプリング周波数 | |
arg = info.samples_per_sec; | |
status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg); | |
if (status == -1 || arg != static_cast<int>(info.samples_per_sec)) { | |
return -1; | |
} | |
return fd; | |
} | |
// | |
// dsp デバイスの書き込み | |
// | |
ssize_t write_dev_dsp(int fd, void const* buf, std::size_t n) { | |
return write(fd, buf, n); | |
} | |
#endif // #ifndef APP_WAVE_IO_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment