Commit 570e2923 authored by Stefan Westerfeld's avatar Stefan Westerfeld

Move stream API to public headers, started to use it in audiowmark add.

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent a8f37a47
bin_PROGRAMS = audiowmark
COMMON_SRC = utils.hh utils.cc convcode.hh convcode.cc random.hh random.cc mp3.cc mp3.hh wavdata.cc wavdata.hh
COMMON_SRC = utils.hh utils.cc convcode.hh convcode.cc random.hh random.cc mp3.cc mp3.hh wavdata.cc wavdata.hh \
audiostream.cc audiostream.hh sfinputstream.cc sfinputstream.hh
COMMON_LIBS = $(SNDFILE_LIBS) $(FFTW_LIBS) $(LIBGCRYPT_LIBS) $(LIBMPG123_LIBS)
audiowmark_SOURCES = audiowmark.cc fft.cc fft.hh $(COMMON_SRC)
......
#ifndef AUDIOWMARK_AUDIO_STREAM_HH
#define AUDIOWMARK_AUDIO_STREAM_HH
#include <vector>
class AudioStream
{
public:
virtual int sample_rate() const = 0;
virtual size_t n_frames() const = 0;
virtual ~AudioStream();
};
class AudioInputStream : public AudioStream
{
virtual std::vector<float> read_frames (size_t count) = 0;
};
class AudioOutputStream : public AudioStream
{
};
#endif /* AUDIOWMARK_AUDIO_STREAM_HH */
......@@ -4,12 +4,14 @@
#include <random>
#include <complex>
#include <algorithm>
#include <memory>
#include "fft.hh"
#include "wavdata.hh"
#include "utils.hh"
#include "convcode.hh"
#include "random.hh"
#include "sfinputstream.hh"
#include <zita-resampler/resampler.h>
#include <zita-resampler/vresampler.h>
......@@ -664,17 +666,23 @@ add_watermark (const string& infile, const string& outfile, const string& bits)
auto bitvec_a = randomize_bit_order (conv_encode (ConvBlockType::a, bitvec), /* encode */ true);
auto bitvec_b = randomize_bit_order (conv_encode (ConvBlockType::b, bitvec), /* encode */ true);
WavData orig_wav_data;
if (!orig_wav_data.load (infile))
auto in_stream = std::make_unique<SFInputStream> (); // FIXME: need virtual constructor
if (!in_stream->open (infile))
{
fprintf (stderr, "audiowmark: error loading %s: %s\n", infile.c_str(), orig_wav_data.error_blurb());
fprintf (stderr, "audiowmark: error opening %s: %s\n", infile.c_str(), in_stream->error_blurb());
return 1;
}
int orig_seconds = orig_wav_data.n_values() / orig_wav_data.sample_rate() / orig_wav_data.n_channels();
if (in_stream->sample_rate() != Params::mark_sample_rate)
{
fprintf (stderr, "FIXME resampling support\n");
return 1;
}
int orig_seconds = in_stream->n_frames() / in_stream->sample_rate();
printf ("Time: %d:%02d\n", orig_seconds / 60, orig_seconds % 60);
printf ("Sample Rate: %d\n", orig_wav_data.sample_rate());
printf ("Channels: %d\n", orig_wav_data.n_channels());
printf ("Sample Rate: %d\n", in_stream->sample_rate());
printf ("Channels: %d\n", in_stream->n_channels());
#if 0
vector<float> in_signal;
if (orig_wav_data.sample_rate() != Params::mark_sample_rate)
{
......@@ -692,7 +700,9 @@ add_watermark (const string& infile, const string& outfile, const string& bits)
*/
while (in_signal.size() % (orig_wav_data.n_channels() * Params::frame_size))
in_signal.push_back (0);
#endif
#if 0
WavData wav_data (in_signal, orig_wav_data.n_channels(), Params::mark_sample_rate, orig_wav_data.bit_depth());
/* we have extra space for the padded wave data -> truncated before save */
......@@ -842,6 +852,7 @@ add_watermark (const string& infile, const string& outfile, const string& bits)
fprintf (stderr, "audiowmark: error saving %s: %s\n", outfile.c_str(), out_wav_data.error_blurb());
return 1;
}
#endif
return 0;
}
......
#include "sfinputstream.hh"
#include <assert.h>
using std::string;
using std::vector;
SFInputStream::~SFInputStream()
{
close();
}
bool
SFInputStream::open (const string& filename)
{
assert (m_state == State::NEW);
SF_INFO sfinfo = { 0, };
m_sndfile = sf_open (filename.c_str(), SFM_READ, &sfinfo);
int error = sf_error (m_sndfile);
if (error)
{
m_error_blurb = sf_strerror (m_sndfile);
if (m_sndfile)
{
m_sndfile = nullptr;
sf_close (m_sndfile);
}
return false;
}
m_n_channels = sfinfo.channels;
m_n_values = sfinfo.frames * sfinfo.channels;
m_sample_rate = sfinfo.samplerate;
m_state = State::OPEN;
return true;
}
int
SFInputStream::sample_rate() const
{
return m_sample_rate;
}
vector<float>
SFInputStream::read_frames (size_t count)
{
assert (m_state == State::OPEN);
vector<int> isamples (count * m_n_channels);
sf_count_t r_count = sf_readf_int (m_sndfile, &isamples[0], count);
/* reading a wav file and saving it again with the libsndfile float API will
* change some values due to normalization issues:
* http://www.mega-nerd.com/libsndfile/FAQ.html#Q010
*
* to avoid the problem, we use the int API and do the conversion beween int
* and float manually - the important part is that the normalization factors
* used during read and write are identical
*/
vector<float> result (r_count * m_n_channels);;
const double norm = 1.0 / 0x80000000LL;
for (size_t i = 0; i < result.size(); i++)
result[i] = isamples[i] * norm;
return result;
}
void
SFInputStream::close()
{
if (m_state == State::OPEN)
{
assert (m_sndfile);
sf_close (m_sndfile);
m_state = State::CLOSED;
}
}
#ifndef AUDIOWMARK_SF_INPUT_STREAM_HH
#define AUDIOWMARK_SF_INPUT_STREAM_HH
#include <string>
#include <sndfile.h>
#include "audiostream.hh"
class SFInputStream : public AudioInputStream
{
SNDFILE *m_sndfile = nullptr;
std::string m_error_blurb;
int m_n_channels = 0;
int m_n_values = 0;
int m_sample_rate = 0;
enum class State {
NEW,
OPEN,
CLOSED
};
State m_state = State::NEW;
public:
~SFInputStream();
bool open (const std::string& filename);
std::vector<float> read_frames (size_t count);
void close();
int
n_channels() const
{
return m_n_channels;
}
int sample_rate() const;
size_t
n_values() const
{
return m_n_values;
}
size_t
n_frames() const override
{
return m_n_values / m_n_channels;
}
const char *error_blurb() const
{
return m_error_blurb.c_str();
}
};
#endif /* AUDIOWMARK_SF_INPUT_STREAM_HH */
......@@ -4,66 +4,15 @@
#include <assert.h>
#include <math.h>
#include "wavdata.hh"
#include "sfinputstream.hh"
#include "utils.hh"
class AudioInputStream
{
virtual std::vector<float> read_frames (size_t count) = 0;
};
class AudioOutputStream
{
};
class SFInputStream : public AudioInputStream
{
SNDFILE *m_sndfile = nullptr;
std::string m_error_blurb;
int m_n_channels = 0;
int m_n_values = 0;
int m_sample_rate = 0;
enum class State {
NEW,
OPEN,
CLOSED
};
State m_state = State::NEW;
public:
~SFInputStream();
bool open (const std::string& filename);
std::vector<float> read_frames (size_t count);
void close();
int
n_channels() const
{
return m_n_channels;
}
int sample_rate() const;
size_t
n_values() const
{
return m_n_values;
}
size_t
n_frames() const
{
return m_n_values / m_n_channels;
}
const char *error_blurb() const
{
return m_error_blurb.c_str();
}
};
class StdoutWavOutputStream : public AudioOutputStream
{
std::string m_error_blurb;
int m_bit_depth = 0;
int m_sample_rate = 0;
size_t m_n_frames = 0;
size_t m_close_padding = 0;
enum class State {
......@@ -79,6 +28,11 @@ public:
bool open (int n_channels, int sample_rate, int bit_depth, size_t n_frames);
bool write_frames (const std::vector<float>& frames);
void close();
int sample_rate() const override;
size_t n_frames() const override
{
return m_n_frames;
}
const char *error_blurb() const
{
......@@ -89,86 +43,17 @@ public:
using std::string;
using std::vector;
SFInputStream::~SFInputStream()
StdoutWavOutputStream::~StdoutWavOutputStream()
{
close();
}
bool
SFInputStream::open (const string& filename)
{
assert (m_state == State::NEW);
SF_INFO sfinfo = { 0, };
m_sndfile = sf_open (filename.c_str(), SFM_READ, &sfinfo);
int error = sf_error (m_sndfile);
if (error)
{
m_error_blurb = sf_strerror (m_sndfile);
if (m_sndfile)
{
m_sndfile = nullptr;
sf_close (m_sndfile);
}
return false;
}
m_n_channels = sfinfo.channels;
m_n_values = sfinfo.frames * sfinfo.channels;
m_sample_rate = sfinfo.samplerate;
m_state = State::OPEN;
return true;
}
int
SFInputStream::sample_rate() const
StdoutWavOutputStream::sample_rate() const
{
return m_sample_rate;
}
vector<float>
SFInputStream::read_frames (size_t count)
{
assert (m_state == State::OPEN);
vector<int> isamples (count * m_n_channels);
sf_count_t r_count = sf_readf_int (m_sndfile, &isamples[0], count);
/* reading a wav file and saving it again with the libsndfile float API will
* change some values due to normalization issues:
* http://www.mega-nerd.com/libsndfile/FAQ.html#Q010
*
* to avoid the problem, we use the int API and do the conversion beween int
* and float manually - the important part is that the normalization factors
* used during read and write are identical
*/
vector<float> result (r_count * m_n_channels);;
const double norm = 1.0 / 0x80000000LL;
for (size_t i = 0; i < result.size(); i++)
result[i] = isamples[i] * norm;
return result;
}
void
SFInputStream::close()
{
if (m_state == State::OPEN)
{
assert (m_sndfile);
sf_close (m_sndfile);
m_state = State::CLOSED;
}
}
StdoutWavOutputStream::~StdoutWavOutputStream()
{
close();
}
static void
header_append_str (vector<unsigned char>& bytes, const string& str)
{
......@@ -230,6 +115,7 @@ StdoutWavOutputStream::open (int n_channels, int sample_rate, int bit_depth, siz
fwrite (&header_bytes[0], 1, header_bytes.size(), stdout);
m_bit_depth = bit_depth;
m_n_frames = n_frames;
m_state = State::OPEN;
return true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment