21WaveWriter::~WaveWriter ()
 
   26wav_header (
const uint8_t n_bits, 
const uint32_t n_channels, 
const uint32_t sample_freq, 
const uint32_t n_samples)
 
   33    puts (
const char *str)
 
   40  const uint32_t byte_per_sample = n_channels * n_bits / 8;
 
   41  const uint32_t byte_per_second = byte_per_sample * sample_freq;
 
   42  const uint32_t n_data_bytes = (n_samples * byte_per_sample + 1) / 2 * 2; 
 
   45  ByteStream b { &buffer[0] };
 
   47  const ByteStream lpos = b;
 
   49  const ByteStream cpos = b;            
 
   52  const uint16_t fmt = n_bits == 32 ? 3 : 1;
 
   53  const bool extensible = n_channels > 2 || fmt == 3;
 
   54  const uint32_t fmtsz = extensible ? 18 : 16;
 
   55  *b.u32++ = htole32 (fmtsz);           
 
   56  *b.u16++ = htole16 (fmt);             
 
   57  *b.u16++ = htole16 (n_channels);
 
   58  *b.u32++ = htole32 (sample_freq);
 
   59  *b.u32++ = htole32 (byte_per_second);
 
   60  *b.u16++ = htole16 (byte_per_sample); 
 
   61  *b.u16++ = htole16 (n_bits);
 
   63    *b.u16++ = htole16 (0);             
 
   67      *b.u32++ = htole32 (4);           
 
   68      *b.u32++ = htole32 (n_samples);   
 
   71  *b.u32++ = htole32 (n_data_bytes);
 
   72  const uint32_t length = b.c - cpos.c + n_data_bytes;
 
   73  *lpos.u32 = htole32 (length);         
 
   74  buffer.resize (b.u8 - &buffer[0]);
 
   79wav_write (
int fd, uint8_t n_bits, uint32_t n_channels, uint32_t sample_freq, 
const float *samples, 
size_t n_frames)
 
   81  const size_t n_samples = n_channels * n_frames;
 
   84      uint8_t buffer[16384], *
const e = buffer + 
sizeof (buffer) / 
sizeof (buffer[0]), *b = buffer;
 
   85      for (
size_t n = 0; n < n_samples; )
 
   87          const uint8_t u8 = 127.5 + 127.5 * samples[n++];
 
   89          if (b + 1 >= e || n >= n_samples)
 
   91              if (n >= n_samples && (n_channels & 1) && (n_samples & 1)) 
 
   93              if (write (fd, buffer, (b - buffer) * 
sizeof (buffer[0])) < 0)
 
  101      uint8_t buffer[16384], *
const e = buffer + 
sizeof (buffer) / 
sizeof (buffer[0]), *b = buffer;
 
  102      for (
size_t n = 0; n < n_samples; )
 
  104          const int32_t i24 = samples[n++] * 8388607.5 - 0.5;
 
  108          if (b + 4 >= e || n >= n_samples)
 
  110              if (n >= n_samples && (n_channels & 1) && (n_samples & 1)) 
 
  112              if (write (fd, buffer, (b - buffer) * 
sizeof (buffer[0])) < 0)
 
  120      uint16_t buffer[16384], *
const e = buffer + 
sizeof (buffer) / 
sizeof (buffer[0]), *b = buffer;
 
  121      for (
size_t n = 0; n < n_samples; )
 
  123          const int16_t i16 = samples[n++] * 32767.5 - 0.5;
 
  124          *b++ = htole16 (i16);
 
  125          if (b >= e || n >= n_samples)
 
  127              if (write (fd, buffer, (b - buffer) * 
sizeof (buffer[0])) < 0)
 
  135      uint32_t buffer[16384], *
const e = buffer + 
sizeof (buffer) / 
sizeof (buffer[0]), *b = buffer;
 
  136      for (
size_t n = 0; n < n_samples; )
 
  138          union { 
float f; 
uint32_t u32; } u { samples[n++] };
 
  139          *b++ = htole32 (u.u32);
 
  140          if (b >= e || n >= n_samples)
 
  142              if (write (fd, buffer, (b - buffer) * 
sizeof (buffer[0])) < 0)
 
  157  size_t   n_samples_ = 0;
 
  162    flush_atquit = [
this] () { close(); };
 
  163    atquit_add (&flush_atquit);
 
  167    atquit_del (&flush_atquit);
 
  175    assert_return (n_bits == 8 || n_bits == 16 || n_bits == 24 || n_bits == 32, 
false);
 
  179    fd_ = ::open (filename.
c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
 
  182    if (
lseek (fd_, 0, SEEK_SET) < 0)
 
  189    filename_ = filename;
 
  191    n_channels_ = n_channels;
 
  192    sample_freq_ = sample_freq;
 
  196    if (::write (fd_, header.data(), header.size()) < 0)
 
  205  name ()
 const override 
  210  write (
const float *frames, 
size_t n_frames)
 override 
  216    n_samples_ += n_frames * n_channels_;
 
  218    return wav_write (fd_, n_bits_, n_channels_, sample_freq_, frames, n_frames) >= 0;
 
  226    if (
lseek (fd_, 0, SEEK_SET) >= 0)
 
  227      ok &= ::write (fd_, header.data(), header.size()) >= 0;
 
  228    ok &=::close (fd_) >= 0;
 
 
  235wave_writer_create_wav (
int rate, 
int channels, 
const String &filename, 
int mode, uint8_t n_bits)
 
  238  if (wavw->open (filename, n_bits, channels, rate) == 
false)
 
  245wave_writer_opus_version()
 
  247  return opus_get_version_string();
 
  252  OpusEncoder *enc_ = 
nullptr;
 
  254  float *bmark_ = 
nullptr;
 
  256  ogg_stream_state ostream_ = { 0, };
 
  267    flush_atquit = [
this] () { finish_and_close (
true); };
 
  268    atquit_add (&flush_atquit);
 
  272    atquit_del (&flush_atquit);
 
  274    opus_encoder_destroy (enc_);
 
  276    ogg_stream_clear (&ostream_);
 
  279  name()
 const override 
  288    fd_ = 
open (name_.c_str(), O_CREAT | O_TRUNC | O_WRONLY, mode);
 
  292  setup_encoder (
int rate, 
int channels, 
int complexity, 
float bitrate)
 
  301    n_channels_ = channels;
 
  302    enc_ = opus_encoder_create (rate_, n_channels_, OPUS_APPLICATION_AUDIO, &error);
 
  303    if (error == OPUS_OK)
 
  305        bitrate = n_channels_ * bitrate * 1000;
 
  307        if (OPUS_OK == opus_encoder_ctl (enc_, OPUS_SET_BITRATE (
MIN (256000 * n_channels_, bitrate))) &&
 
  308            OPUS_OK == opus_encoder_ctl (enc_, OPUS_SET_VBR (1)) &&
 
  309            OPUS_OK == opus_encoder_ctl (enc_, OPUS_SET_VBR_CONSTRAINT (0)) &&
 
  310            OPUS_OK == opus_encoder_ctl (enc_, OPUS_SET_FORCE_CHANNELS (n_channels_)) &&
 
  311            OPUS_OK == opus_encoder_ctl (enc_, OPUS_SET_COMPLEXITY (complexity)) &&
 
  312            ogg_stream_init (&ostream_, serialno) >= 0)
 
  314            const int std_fragment_size = 20 * 48000 / 1000; 
 
  315            int fragment_size = std_fragment_size * rate_ / 48000;
 
  316            buffer_.resize (fragment_size * n_channels_);
 
  317            bmark_ = buffer_.data();
 
  318            if (write_header() > 0)
 
  322    finish_and_close (
false);
 
  327  write_packet (ogg_packet *op, 
bool force_flush)
 
  329    ogg_stream_packetin (&ostream_, op);
 
  331    auto stream_pageout = force_flush ? ogg_stream_flush : ogg_stream_pageout;
 
  332    while (stream_pageout (&ostream_, &opage))
 
  336          n = ::write (fd_, opage.header, opage.header_len);
 
  338        if (n != opage.header_len) 
return -1;
 
  340          n = ::write (fd_, opage.body, opage.body_len);
 
  342        if (n != opage.body_len) 
return -1;
 
  350    if (OPUS_OK != opus_encoder_ctl (enc_, OPUS_GET_LOOKAHEAD (&lookahead)))
 
  355      char     magic[8] = { 
'O', 
'p', 
'u', 
's', 
'H', 
'e', 
'a', 
'd' };
 
  363    } __attribute__ ((packed));
 
  365      .channels = n_channels_,
 
  366      .pre_skip_le = htole16 (lookahead),
 
  367      .rate_le = htole32 (rate_),
 
  369    static_assert (
sizeof (oh) == 19);
 
  372      .bytes = 
sizeof (oh),
 
  373      .b_o_s = 0, .e_o_s = 0,
 
  375      .packetno = packetno_++
 
  377    if (write_packet (&op0, 
true) < 0)
 
  382    cmtheader += 
"OpusTags";                            
 
  383    const String opus_version = opus_get_version_string();
 
  384    u32_le = htole32 (opus_version.
size());
 
  385    cmtheader += 
String ((
char*) &u32_le, 4);           
 
  386    cmtheader += opus_version;                          
 
  390    u32_le = htole32 (tags.
size());
 
  391    cmtheader += 
String ((
char*) &u32_le, 4);           
 
  392    for (
const auto &tag : tags)
 
  394        u32_le = htole32 (tag.size());
 
  395        cmtheader += 
String ((
char*) &u32_le, 4);       
 
  401      .b_o_s = 0, .e_o_s = 0,
 
  403      .packetno = packetno_++
 
  405    if (write_packet (&op1, 
true) < 0)
 
  410  write_ogg (
uint8_t *data, 
long l, 
bool force_flush)
 
  415      .b_o_s = 0, .e_o_s = eos_,
 
  416      .granulepos = granulepos_,
 
  417      .packetno = packetno_++
 
  419    if (write_packet (&op, force_flush) < 0)
 
  424  write (
const float *frames, 
size_t n_frames)
 override 
  426    return write_opus (frames, n_frames, 
false);
 
  429  write_opus (
const float *frames, 
size_t n_frames, 
bool force_flush)
 
  436    const float *fend = frames + n_frames * n_channels_;
 
  437    const float *bmax = buffer_.data() + buffer_.size();
 
  438    while (frames < fend)
 
  440        ssize_t l = 
MIN (bmax - bmark_, fend - frames);
 
  447            bmark_ = buffer_.data();
 
  448            const uint n_frames = buffer_.size() / n_channels_;
 
  449            granulepos_ += n_frames;
 
  450            l = opus_encode_float (enc_, bmark_, n_frames, pmem, 
sizeof (pmem));
 
  453                printerr (
"%s: OpusWriter encoding error: %s\n", name_, opus_strerror (l));
 
  454                finish_and_close (
false);
 
  458            if (l > 0 && write_ogg (pmem, l, force_flush) < 0)
 
  460                const int serrno = 
errno;
 
  461                finish_and_close (
false);
 
  470  finish_and_close (
bool flush)
 
  476        const size_t n_filled = bmark_ - buffer_.data();
 
  478        const size_t n_floats = buffer_.size() - n_filled;
 
  479        float zeros[n_floats];
 
  482        err &= write_opus (zeros, n_floats / n_channels_, 
true) < 0;
 
  485    err &= ::close (fd_) < 0;
 
  494    return finish_and_close (
true);
 
 
  499wave_writer_create_opus (
int rate, 
int channels, 
const String &filename, 
int mode, 
int complexity, 
float bitrate)
 
  502  if (ow->create (mode) == 
false)
 
  504  if (!ow->setup_encoder (rate, channels, complexity, bitrate))
 
  511wave_writer_flac_version()
 
  513  return FLAC__VERSION_STRING;
 
  518  FLAC__StreamEncoder *enc_ = 
nullptr;
 
  519  FLAC__StreamMetadata *metadata_[2] = { 
nullptr, 
nullptr };
 
  528    ibuffer_.reserve (65536);
 
  529    flush_atquit = [
this] () { 
if (enc_) close(); };
 
  530    atquit_add (&flush_atquit);
 
  534    atquit_del (&flush_atquit);
 
  541      FLAC__stream_encoder_delete (enc_);
 
  544      FLAC__metadata_object_delete (metadata_[0]);
 
  545    metadata_[0] = 
nullptr;
 
  552    const bool ok = FLAC__stream_encoder_finish (enc_);
 
  553    const int saved_errno = 
errno;
 
  557      printerr (
"%s: FlacWriter error: %s\n", name_, 
strerror (saved_errno ? saved_errno : 
EIO));
 
  561  create (
int mode, 
int rate, 
int channels, 
int compresion)
 
  568    const int fd = 
open (name_.c_str(), O_CREAT | O_TRUNC | O_RDWR, mode);
 
  570    FILE *file = 
fdopen (fd, 
"w+b");
 
  576    enc_ = FLAC__stream_encoder_new();
 
  583    n_channels_ = channels;
 
  584    bool setup_ok = 
true;
 
  585    setup_ok &= FLAC__stream_encoder_set_channels (enc_, n_channels_);
 
  586    setup_ok &= FLAC__stream_encoder_set_bits_per_sample (enc_, 24);
 
  587    setup_ok &= FLAC__stream_encoder_set_sample_rate (enc_, rate_);
 
  588    setup_ok &= FLAC__stream_encoder_set_compression_level (enc_, compresion);
 
  591    metadata_[0] = FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
 
  592    for (
const auto &tag : tags)
 
  594        FLAC__StreamMetadata_VorbisComment_Entry entry = { 
uint32_t (tag.size()), (
uint8_t*) tag.data() };
 
  595        setup_ok &= FLAC__metadata_object_vorbiscomment_append_comment (metadata_[0], entry, 
true);
 
  597    setup_ok &= FLAC__stream_encoder_set_metadata (enc_, metadata_, 1);
 
  598    printerr (
"%s:%d: ok=%d\n", __FILE__, __LINE__, setup_ok);
 
  599    setup_ok &= FLAC__STREAM_ENCODER_INIT_STATUS_OK == FLAC__stream_encoder_init_FILE (enc_, file, 
nullptr, 
nullptr);
 
  600    printerr (
"%s:%d: ok=%d\n", __FILE__, __LINE__, setup_ok);
 
  608  write (
const float *frames, 
size_t n_frames)
 override 
  614    const size_t n_samples = n_frames * n_channels_;
 
  615    if (ibuffer_.size() < n_samples)
 
  616      ibuffer_.resize (n_samples);
 
  617    for (
size_t i = 0; i < n_samples; i++)
 
  619        int32_t v = frames[i] * 8388607.5 - 0.5;
 
  620        ibuffer_[i] = 
CLAMP (v, -8388608, +8388607);
 
  622    const bool ok = FLAC__stream_encoder_process_interleaved (enc_, ibuffer_.data(), n_frames);
 
  626  name()
 const override 
 
  633wave_writer_create_flac (
int rate, 
int channels, 
const String &filename, 
int mode, 
int compresion)
 
  636  if (ow->create (mode, rate, channels, compresion) == 
false)
 
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
 
#define MIN(a, b)
Yield minimum of a and b.
 
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
 
#define CLAMP(v, mi, ma)
Yield v clamped to [mi … ma].
 
The Anklang C++ API namespace.
 
void floatfill(float *dst, float f, size_t n)
Fill n values of dst with f.
 
std::string String
Convenience alias for std::string.
 
uint32_t uint
Provide 'uint' as convenience type.
 
void fast_copy(size_t n, float *d, const float *s)
Copy a block of floats.