Commit fff6bf48 authored by Stefan Westerfeld's avatar Stefan Westerfeld

Support new format (--format wav-pipe) for wav pipes without size limit.

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent 0dd38668
......@@ -7,7 +7,7 @@ COMMON_SRC = utils.hh utils.cc convcode.hh convcode.cc random.hh random.cc wavda
rawconverter.cc rawconverter.hh mp3inputstream.cc mp3inputstream.hh wmcommon.cc wmcommon.hh fft.cc fft.hh \
limiter.cc limiter.hh shortcode.cc shortcode.hh mpegts.cc mpegts.hh hls.cc hls.hh audiobuffer.hh \
wmget.cc wmadd.cc syncfinder.cc syncfinder.hh wmspeed.cc wmspeed.hh threadpool.cc threadpool.hh \
resample.cc resample.hh
resample.cc resample.hh wavpipeinputstream.cc wavpipeinputstream.hh
COMMON_LIBS = $(SNDFILE_LIBS) $(FFTW_LIBS) $(LIBGCRYPT_LIBS) $(LIBMPG123_LIBS) $(FFMPEG_LIBS) $(LTLIBZITA_RESAMPLER)
AM_CXXFLAGS = $(SNDFILE_CFLAGS) $(FFTW_CFLAGS) $(LIBGCRYPT_CFLAGS) $(LIBMPG123_CFLAGS) $(FFMPEG_CFLAGS)
......
......@@ -23,6 +23,7 @@
#include "rawconverter.hh"
#include "rawoutputstream.hh"
#include "stdoutwavoutputstream.hh"
#include "wavpipeinputstream.hh"
using std::string;
......@@ -52,7 +53,7 @@ AudioInputStream::create (const string& filename, Error& err)
else if (err)
return nullptr;
}
else
else if (Params::input_format == Format::RAW)
{
RawInputStream *ristream = new RawInputStream();
in_stream.reset (ristream);
......@@ -61,6 +62,20 @@ AudioInputStream::create (const string& filename, Error& err)
if (err)
return nullptr;
}
else if (Params::input_format == Format::WAV_PIPE)
{
WavPipeInputStream *wistream = new WavPipeInputStream();
in_stream.reset (wistream);
err = wistream->open (filename);
if (err)
return nullptr;
}
else
{
err = Error ("selected format is not supported as input format");
return nullptr;
}
return in_stream;
}
......@@ -79,9 +94,11 @@ AudioOutputStream::create (const string& filename, int n_channels, int sample_ra
}
else if (filename == "-")
{
bool wav_pipe = Params::output_format == Format::WAV_PIPE;
StdoutWavOutputStream *swstream = new StdoutWavOutputStream();
out_stream.reset (swstream);
err = swstream->open (n_channels, sample_rate, bit_depth, n_frames);
err = swstream->open (n_channels, sample_rate, bit_depth, n_frames, wav_pipe);
if (err)
return nullptr;
}
......
......@@ -119,6 +119,8 @@ parse_format (const string& str)
return Format::AUTO;
if (str == "rf64")
return Format::RF64;
if (str == "wav-pipe")
return Format::WAV_PIPE;
error ("audiowmark: unsupported format '%s'\n", str.c_str());
exit (1);
......
......@@ -71,7 +71,7 @@ header_append_u16 (vector<unsigned char>& bytes, uint16_t u)
}
Error
StdoutWavOutputStream::open (int n_channels, int sample_rate, int bit_depth, size_t n_frames)
StdoutWavOutputStream::open (int n_channels, int sample_rate, int bit_depth, size_t n_frames, bool wav_pipe)
{
assert (m_state == State::NEW);
......@@ -79,7 +79,7 @@ StdoutWavOutputStream::open (int n_channels, int sample_rate, int bit_depth, siz
{
return Error ("StdoutWavOutputStream::open: unsupported bit depth");
}
if (n_frames == AudioInputStream::N_FRAMES_UNKNOWN)
if (n_frames == AudioInputStream::N_FRAMES_UNKNOWN && !wav_pipe)
{
return Error ("unable to write wav format to standard out without input length information");
}
......@@ -100,7 +100,10 @@ StdoutWavOutputStream::open (int n_channels, int sample_rate, int bit_depth, siz
size_t aligned_data_size = data_size + m_close_padding;
header_append_str (header_bytes, "RIFF");
header_append_u32 (header_bytes, 36 + aligned_data_size);
if (wav_pipe)
header_append_u32 (header_bytes, -1);
else
header_append_u32 (header_bytes, 36 + aligned_data_size);
header_append_str (header_bytes, "WAVE");
// subchunk 1
......@@ -115,7 +118,10 @@ StdoutWavOutputStream::open (int n_channels, int sample_rate, int bit_depth, siz
// subchunk 2
header_append_str (header_bytes, "data");
header_append_u32 (header_bytes, data_size);
if (wav_pipe)
header_append_u32 (header_bytes, -1);
else
header_append_u32 (header_bytes, data_size);
fwrite (&header_bytes[0], 1, header_bytes.size(), stdout);
if (ferror (stdout))
......
......@@ -42,7 +42,7 @@ class StdoutWavOutputStream : public AudioOutputStream
public:
~StdoutWavOutputStream();
Error open (int n_channels, int sample_rate, int bit_depth, size_t n_frames);
Error open (int n_channels, int sample_rate, int bit_depth, size_t n_frames, bool wav_pipe);
Error write_frames (const std::vector<float>& frames) override;
Error close() override;
int sample_rate() const override;
......
......@@ -41,7 +41,7 @@ main (int argc, char **argv)
fprintf (stderr, "teststream: open input failed: %s\n", err.message());
return 1;
}
err = out.open (in.n_channels(), in.sample_rate(), 16, in.n_frames());
err = out.open (in.n_channels(), in.sample_rate(), 16, in.n_frames(), false);
if (err)
{
fprintf (stderr, "teststream: open output failed: %s\n", err.message());
......
/*
* Copyright (C) 2018-2020 Stefan Westerfeld
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "wavpipeinputstream.hh"
#include "rawconverter.hh"
#include <assert.h>
#include <string.h>
#include <errno.h>
using std::string;
using std::vector;
using std::min;
WavPipeInputStream::~WavPipeInputStream()
{
close();
}
string
header_get_4cc (unsigned char *bytes)
{
string s;
s += bytes[0];
s += bytes[1];
s += bytes[2];
s += bytes[3];
return s;
}
static uint16_t
header_get_u16 (unsigned char *bytes)
{
return bytes[0] + (bytes[1] << 8);
}
static uint32_t
header_get_u32 (unsigned char *bytes)
{
return bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24);
}
Error
WavPipeInputStream::open (const string& filename)
{
assert (m_state == State::NEW);
Error err = Error::Code::NONE;
if (err)
return err;
if (filename == "-")
{
m_input_file = stdin;
m_close_file = false;
}
else
{
m_input_file = fopen (filename.c_str(), "r");
if (!m_input_file)
return Error (strerror (errno));
m_close_file = true;
}
RawFormat format;
unsigned char riff_buffer[12];
size_t riff_ok = fread (riff_buffer, sizeof (riff_buffer), 1, m_input_file);
if (!riff_ok ||
(header_get_4cc (riff_buffer) != "RIFF" &&
header_get_4cc (riff_buffer) != "RF64") ||
header_get_4cc (riff_buffer + 8) != "WAVE")
return Error ("input file is not a valid wav file");
bool in_data_chunk = false;
do
{
unsigned char chunk[8];
size_t rc = fread (chunk, sizeof (chunk), 1, m_input_file);
if (rc == 0)
return Error ("wav input is incomplete (no data chunk found)");
uint32_t chunk_size = header_get_u32 (chunk + 4);
if (header_get_4cc (chunk) == "fmt " && chunk_size >= 16)
{
vector<unsigned char> buffer (chunk_size);
fread (buffer.data(), buffer.size(), 1, m_input_file);
format.set_channels (header_get_u16 (&buffer[2]));
format.set_sample_rate (header_get_u32 (&buffer[4]));
format.set_bit_depth (header_get_u16 (&buffer[14]));
}
else if (header_get_4cc (chunk) == "data")
{
in_data_chunk = true;
}
else // skip unknown chunk
{
char junk[1024];
while (chunk_size)
{
uint32_t todo = min<uint32_t> (chunk_size, sizeof (junk));
fread (junk, todo, 1, m_input_file);
chunk_size -= todo;
}
}
} while (!in_data_chunk);
m_raw_converter.reset (RawConverter::create (format, err));
if (err)
return err;
m_format = format;
m_state = State::OPEN;
return Error::Code::NONE;
}
int
WavPipeInputStream::sample_rate() const
{
return m_format.sample_rate();
}
int
WavPipeInputStream::bit_depth() const
{
return m_format.bit_depth();
}
size_t
WavPipeInputStream::n_frames() const
{
return N_FRAMES_UNKNOWN;
}
int
WavPipeInputStream::n_channels() const
{
return m_format.n_channels();
}
Error
WavPipeInputStream::read_frames (vector<float>& samples, size_t count)
{
assert (m_state == State::OPEN);
const int n_channels = m_format.n_channels();
const int sample_width = m_format.bit_depth() / 8;
vector<unsigned char> input_bytes (count * n_channels * sample_width);
size_t r_count = fread (input_bytes.data(), n_channels * sample_width, count, m_input_file);
if (ferror (m_input_file))
return Error ("error reading sample data");
input_bytes.resize (r_count * n_channels * sample_width);
m_raw_converter->from_raw (input_bytes, samples);
return Error::Code::NONE;
}
void
WavPipeInputStream::close()
{
if (m_state == State::OPEN)
{
if (m_close_file && m_input_file)
{
fclose (m_input_file);
m_input_file = nullptr;
m_close_file = false;
}
m_state = State::CLOSED;
}
}
/*
* Copyright (C) 2018-2020 Stefan Westerfeld
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef AUDIOWMARK_WAV_PIPE_INPUT_STREAM_HH
#define AUDIOWMARK_WAV_PIPE_INPUT_STREAM_HH
#include <string>
#include <memory>
#include <sndfile.h>
#include "audiostream.hh"
#include "rawinputstream.hh"
class WavPipeInputStream : public AudioInputStream
{
enum class State {
NEW,
OPEN,
CLOSED
};
State m_state = State::NEW;
RawFormat m_format;
FILE *m_input_file = nullptr;
bool m_close_file = false;
std::unique_ptr<RawConverter> m_raw_converter;
public:
~WavPipeInputStream();
Error open (const std::string& filename);
Error read_frames (std::vector<float>& samples, size_t count) override;
void close();
int bit_depth() const override;
int sample_rate() const override;
size_t n_frames() const override;
int n_channels() const override;
};
#endif /* AUDIOWMARK_WAV_PIPE_INPUT_STREAM_HH */
......@@ -28,7 +28,7 @@
#include <assert.h>
enum class Format { AUTO = 1, RAW = 2, RF64 = 3 };
enum class Format { AUTO = 1, RAW, RF64, WAV_PIPE };
class Params
{
......
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