mirror of
https://github.com/holub/mame
synced 2025-10-07 09:25:34 +03:00
netlist: nlwav now also converts log files to VCD format. [couriersud]
Please refer to nlwav --help for examples. There is also an example how to create multi-channel wav files.
This commit is contained in:
parent
95cd81e5fd
commit
83d558d096
@ -1064,7 +1064,7 @@ namespace netlist
|
|||||||
protected:
|
protected:
|
||||||
virtual void changed() override
|
virtual void changed() override
|
||||||
{
|
{
|
||||||
stream()->read(&m_data[0],1<<AW);
|
stream()->read(reinterpret_cast<plib::pistream::value_type *>(&m_data[0]),1<<AW);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -1490,7 +1490,7 @@ namespace netlist
|
|||||||
{
|
{
|
||||||
auto f = stream();
|
auto f = stream();
|
||||||
if (f != nullptr)
|
if (f != nullptr)
|
||||||
f->read(&m_data[0],1<<AW);
|
f->read(reinterpret_cast<plib::pistream::value_type *>(&m_data[0]),1<<AW);
|
||||||
else
|
else
|
||||||
device.state().log().warning("Rom {1} not found", Value());
|
device.state().log().warning("Rom {1} not found", Value());
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "poptions.h"
|
#include "poptions.h"
|
||||||
#include "ptypes.h"
|
#include "ptypes.h"
|
||||||
|
#include "pexception.h"
|
||||||
|
|
||||||
namespace plib {
|
namespace plib {
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
@ -62,15 +63,17 @@ namespace plib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
options::options()
|
options::options()
|
||||||
|
: m_other_args(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
options::options(option *o[])
|
options::options(option *o[])
|
||||||
|
: m_other_args(nullptr)
|
||||||
{
|
{
|
||||||
int i=0;
|
int i=0;
|
||||||
while (o[i] != nullptr)
|
while (o[i] != nullptr)
|
||||||
{
|
{
|
||||||
m_opts.push_back(o[i]);
|
register_option(o[i]);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,9 +88,39 @@ namespace plib {
|
|||||||
m_opts.push_back(opt);
|
m_opts.push_back(opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void options::check_consistency()
|
||||||
|
{
|
||||||
|
for (auto &opt : m_opts)
|
||||||
|
{
|
||||||
|
option *o = dynamic_cast<option *>(opt);
|
||||||
|
if (o != nullptr)
|
||||||
|
{
|
||||||
|
if (o->short_opt() == "" && o->long_opt() == "")
|
||||||
|
{
|
||||||
|
option_args *ov = dynamic_cast<option_args *>(o);
|
||||||
|
if (ov != nullptr)
|
||||||
|
{
|
||||||
|
if (m_other_args != nullptr)
|
||||||
|
{
|
||||||
|
throw pexception("other args can only be specified once!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_other_args = ov;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw pexception("found option with neither short or long tag!" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int options::parse(int argc, char *argv[])
|
int options::parse(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
check_consistency();
|
||||||
m_app = pstring(argv[0]);
|
m_app = pstring(argv[0]);
|
||||||
|
bool seen_other_args = false;
|
||||||
|
|
||||||
for (int i=1; i<argc; )
|
for (int i=1; i<argc; )
|
||||||
{
|
{
|
||||||
@ -96,9 +129,11 @@ namespace plib {
|
|||||||
pstring opt_arg;
|
pstring opt_arg;
|
||||||
bool has_equal_arg = false;
|
bool has_equal_arg = false;
|
||||||
|
|
||||||
if (plib::startsWith(arg, "--"))
|
if (!seen_other_args && plib::startsWith(arg, "--"))
|
||||||
{
|
{
|
||||||
auto v = psplit(arg.substr(2),"=");
|
auto v = psplit(arg.substr(2),"=");
|
||||||
|
if (v.size() && v[0] != pstring(""))
|
||||||
|
{
|
||||||
opt = getopt_long(v[0]);
|
opt = getopt_long(v[0]);
|
||||||
has_equal_arg = (v.size() > 1);
|
has_equal_arg = (v.size() > 1);
|
||||||
if (has_equal_arg)
|
if (has_equal_arg)
|
||||||
@ -108,7 +143,13 @@ namespace plib {
|
|||||||
opt_arg += v[v.size()-1];
|
opt_arg += v[v.size()-1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (plib::startsWith(arg, "-"))
|
else
|
||||||
|
{
|
||||||
|
opt = m_other_args;
|
||||||
|
seen_other_args = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!seen_other_args && plib::startsWith(arg, "-"))
|
||||||
{
|
{
|
||||||
std::size_t p = 1;
|
std::size_t p = 1;
|
||||||
opt = getopt_short(arg.substr(p, 1));
|
opt = getopt_short(arg.substr(p, 1));
|
||||||
@ -121,7 +162,11 @@ namespace plib {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
seen_other_args = true;
|
||||||
|
if (m_other_args == nullptr)
|
||||||
return i;
|
return i;
|
||||||
|
opt = m_other_args;
|
||||||
|
i--; // we haven't had an option specifier;
|
||||||
}
|
}
|
||||||
if (opt == nullptr)
|
if (opt == nullptr)
|
||||||
return i;
|
return i;
|
||||||
@ -183,6 +228,10 @@ namespace plib {
|
|||||||
|
|
||||||
for (auto & optbase : m_opts )
|
for (auto & optbase : m_opts )
|
||||||
{
|
{
|
||||||
|
// Skip anonymous inputs which are collected in option_args
|
||||||
|
if (dynamic_cast<option_args *>(optbase) != nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (auto opt = dynamic_cast<option *>(optbase))
|
if (auto opt = dynamic_cast<option *>(optbase))
|
||||||
{
|
{
|
||||||
pstring line = "";
|
pstring line = "";
|
||||||
@ -227,6 +276,7 @@ namespace plib {
|
|||||||
if (grp->help() != "") ret += split_paragraphs(grp->help(), width, 4, 4) + "\n";
|
if (grp->help() != "") ret += split_paragraphs(grp->help(), width, 4, 4) + "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// FIXME: other help ...
|
||||||
pstring ex("");
|
pstring ex("");
|
||||||
for (auto & optbase : m_opts )
|
for (auto & optbase : m_opts )
|
||||||
{
|
{
|
||||||
@ -248,7 +298,7 @@ namespace plib {
|
|||||||
for (auto & optbase : m_opts)
|
for (auto & optbase : m_opts)
|
||||||
{
|
{
|
||||||
auto opt = dynamic_cast<option *>(optbase);
|
auto opt = dynamic_cast<option *>(optbase);
|
||||||
if (opt && opt->short_opt() == arg)
|
if (opt && arg != "" && opt->short_opt() == arg)
|
||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -258,7 +308,7 @@ namespace plib {
|
|||||||
for (auto & optbase : m_opts)
|
for (auto & optbase : m_opts)
|
||||||
{
|
{
|
||||||
auto opt = dynamic_cast<option *>(optbase);
|
auto opt = dynamic_cast<option *>(optbase);
|
||||||
if (opt && opt->long_opt() == arg)
|
if (opt && arg !="" && opt->long_opt() == arg)
|
||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -212,6 +212,14 @@ private:
|
|||||||
std::vector<pstring> m_val;
|
std::vector<pstring> m_val;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class option_args : public option_vec
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
option_args(options &parent, pstring help)
|
||||||
|
: option_vec(parent, "", "", help)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
class options
|
class options
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -233,6 +241,8 @@ private:
|
|||||||
static pstring split_paragraphs(pstring text, unsigned width, unsigned indent,
|
static pstring split_paragraphs(pstring text, unsigned width, unsigned indent,
|
||||||
unsigned firstline_indent);
|
unsigned firstline_indent);
|
||||||
|
|
||||||
|
void check_consistency();
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *getopt_type()
|
T *getopt_type()
|
||||||
{
|
{
|
||||||
@ -249,6 +259,7 @@ private:
|
|||||||
|
|
||||||
std::vector<option_base *> m_opts;
|
std::vector<option_base *> m_opts;
|
||||||
pstring m_app;
|
pstring m_app;
|
||||||
|
option_args * m_other_args;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ protected:
|
|||||||
virtual size_type vread(T *buf, const size_type n) = 0;
|
virtual size_type vread(T *buf, const size_type n) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef pistream_base<std::uint8_t> pistream;
|
typedef pistream_base<char> pistream;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// postream: output stream
|
// postream: output stream
|
||||||
@ -150,7 +150,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef postream_base<std::uint8_t> postream;
|
typedef postream_base<char> postream;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// pomemstream: output string stream
|
// pomemstream: output string stream
|
||||||
|
@ -8,37 +8,6 @@
|
|||||||
#include "../plib/ppmf.h"
|
#include "../plib/ppmf.h"
|
||||||
#include "../nl_setup.h"
|
#include "../nl_setup.h"
|
||||||
|
|
||||||
class nlwav_app : public plib::app
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
nlwav_app() :
|
|
||||||
plib::app(),
|
|
||||||
opt_inp(*this, "i", "input", "-", "input file"),
|
|
||||||
opt_out(*this, "o", "output", "-", "output file"),
|
|
||||||
opt_amp(*this, "a", "amp", 10000.0, "amplification after mean correction"),
|
|
||||||
opt_rate(*this, "r", "rate", 48000, "sample rate of output file"),
|
|
||||||
opt_verb(*this, "v", "verbose", "be verbose - this produces lots of output"),
|
|
||||||
opt_quiet(*this,"q", "quiet", "be quiet - no warnings"),
|
|
||||||
opt_version(*this, "", "version", "display version and exit"),
|
|
||||||
opt_help(*this, "h", "help", "display help and exit")
|
|
||||||
{}
|
|
||||||
plib::option_str opt_inp;
|
|
||||||
plib::option_str opt_out;
|
|
||||||
plib::option_num<double> opt_amp;
|
|
||||||
plib::option_num<long> opt_rate;
|
|
||||||
plib::option_bool opt_verb;
|
|
||||||
plib::option_bool opt_quiet;
|
|
||||||
plib::option_bool opt_version;
|
|
||||||
plib::option_bool opt_help;
|
|
||||||
|
|
||||||
int execute();
|
|
||||||
pstring usage();
|
|
||||||
|
|
||||||
plib::pstdin pin_strm;
|
|
||||||
private:
|
|
||||||
void convert1(long sample_rate);
|
|
||||||
void convert(long sample_rate);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* From: https://ffmpeg.org/pipermail/ffmpeg-devel/2007-October/038122.html
|
/* From: https://ffmpeg.org/pipermail/ffmpeg-devel/2007-October/038122.html
|
||||||
@ -55,9 +24,10 @@ private:
|
|||||||
class wav_t
|
class wav_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wav_t(plib::postream &strm, unsigned sr) : m_f(strm)
|
wav_t(plib::postream &strm, std::size_t sr, std::size_t channels)
|
||||||
|
: m_f(strm)
|
||||||
{
|
{
|
||||||
initialize(sr);
|
initialize(sr, channels);
|
||||||
write(m_fh);
|
write(m_fh);
|
||||||
write(m_fmt);
|
write(m_fmt);
|
||||||
write(m_data);
|
write(m_data);
|
||||||
@ -76,8 +46,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned channels() { return m_fmt.channels; }
|
std::size_t channels() { return m_fmt.channels; }
|
||||||
unsigned sample_rate() { return m_fmt.sample_rate; }
|
std::size_t sample_rate() { return m_fmt.sample_rate; }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void write(const T &val)
|
void write(const T &val)
|
||||||
@ -85,12 +55,15 @@ public:
|
|||||||
m_f.write(reinterpret_cast<const plib::postream::value_type *>(&val), sizeof(T));
|
m_f.write(reinterpret_cast<const plib::postream::value_type *>(&val), sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_sample(int sample)
|
void write_sample(int *sample)
|
||||||
{
|
{
|
||||||
m_data.len += m_fmt.block_align;
|
m_data.len += m_fmt.block_align;
|
||||||
int16_t ps = static_cast<int16_t>(sample); /* 16 bit sample, FIXME: Endianess? */
|
for (std::size_t i = 0; i < channels(); i++)
|
||||||
|
{
|
||||||
|
int16_t ps = static_cast<int16_t>(sample[i]); /* 16 bit sample, FIXME: Endianess? */
|
||||||
write(ps);
|
write(ps);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct riff_chunk_t
|
struct riff_chunk_t
|
||||||
@ -119,7 +92,7 @@ private:
|
|||||||
// data follows
|
// data follows
|
||||||
};
|
};
|
||||||
|
|
||||||
void initialize(unsigned sr)
|
void initialize(std::size_t sr, std::size_t channels)
|
||||||
{
|
{
|
||||||
std::memcpy(m_fh.group_id, "RIFF", 4);
|
std::memcpy(m_fh.group_id, "RIFF", 4);
|
||||||
m_fh.filelen = 0x0; // Fixme
|
m_fh.filelen = 0x0; // Fixme
|
||||||
@ -128,8 +101,8 @@ private:
|
|||||||
std::memcpy(m_fmt.signature, "fmt ", 4);
|
std::memcpy(m_fmt.signature, "fmt ", 4);
|
||||||
m_fmt.fmt_length = 16;
|
m_fmt.fmt_length = 16;
|
||||||
m_fmt.format_tag = 0x0001; //PCM
|
m_fmt.format_tag = 0x0001; //PCM
|
||||||
m_fmt.channels = 1;
|
m_fmt.channels = static_cast<std::uint16_t>(channels);
|
||||||
m_fmt.sample_rate = sr;
|
m_fmt.sample_rate = static_cast<std::uint32_t>(sr);
|
||||||
m_fmt.bits_sample = 16;
|
m_fmt.bits_sample = 16;
|
||||||
m_fmt.block_align = m_fmt.channels * ((m_fmt.bits_sample + 7) / 8);
|
m_fmt.block_align = m_fmt.channels * ((m_fmt.bits_sample + 7) / 8);
|
||||||
m_fmt.bytes_per_second = m_fmt.sample_rate * m_fmt.block_align;
|
m_fmt.bytes_per_second = m_fmt.sample_rate * m_fmt.block_align;
|
||||||
@ -138,7 +111,6 @@ private:
|
|||||||
//m_data.len = m_fmt.bytes_per_second * 2 * 0;
|
//m_data.len = m_fmt.bytes_per_second * 2 * 0;
|
||||||
/* force "play" to play and warn about eof instead of being silent */
|
/* force "play" to play and warn about eof instead of being silent */
|
||||||
m_data.len = (m_f.seekable() ? 0 : 0xffffffff);
|
m_data.len = (m_f.seekable() ? 0 : 0xffffffff);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
riff_chunk_t m_fh;
|
riff_chunk_t m_fh;
|
||||||
@ -146,235 +118,373 @@ private:
|
|||||||
riff_data_t m_data;
|
riff_data_t m_data;
|
||||||
|
|
||||||
plib::postream &m_f;
|
plib::postream &m_f;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class log_processor
|
class log_processor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef plib::pmfp<void, double, double> callback_type;
|
typedef plib::pmfp<void, std::size_t, double, double> callback_type;
|
||||||
log_processor(callback_type cb) : m_cb(cb) { }
|
|
||||||
|
|
||||||
void process(std::unique_ptr<plib::pistream> &&is)
|
struct elem
|
||||||
|
{
|
||||||
|
elem() : t(0), v(0), eof(false), need_more(true) { }
|
||||||
|
double t;
|
||||||
|
double v;
|
||||||
|
bool eof;
|
||||||
|
bool need_more;
|
||||||
|
};
|
||||||
|
|
||||||
|
log_processor(std::size_t channels, callback_type &cb)
|
||||||
|
: m_cb(cb)
|
||||||
|
, m_e(channels)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool readmore(std::vector<plib::putf8_reader> &r)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
for (std::size_t i = 0; i< r.size(); i++)
|
||||||
|
{
|
||||||
|
if (m_e[i].need_more)
|
||||||
{
|
{
|
||||||
plib::putf8_reader reader(std::move(is));
|
|
||||||
pstring line;
|
pstring line;
|
||||||
|
m_e[i].eof = !r[i].readline(line);
|
||||||
while(reader.readline(line))
|
if (!m_e[i].eof)
|
||||||
{
|
{
|
||||||
double t = 0.0; double v = 0.0;
|
sscanf(line.c_str(), "%lf %lf", &m_e[i].t, &m_e[i].v);
|
||||||
sscanf(line.c_str(), "%lf %lf", &t, &v);
|
m_e[i].need_more = false;
|
||||||
m_cb(t, v);
|
}
|
||||||
|
}
|
||||||
|
success |= !m_e[i].eof;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process(std::vector<std::unique_ptr<plib::pistream>> &is)
|
||||||
|
{
|
||||||
|
std::vector<plib::putf8_reader> readers;
|
||||||
|
for (std::size_t i = 0; i < is.size(); i++)
|
||||||
|
{
|
||||||
|
plib::putf8_reader r(std::move(is[i]));
|
||||||
|
readers.push_back(std::move(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
pstring line;
|
||||||
|
bool more = readmore(readers);
|
||||||
|
|
||||||
|
while (more)
|
||||||
|
{
|
||||||
|
double mint = 1e200;
|
||||||
|
std::size_t mini = 0;
|
||||||
|
for (std::size_t i = 0; i<readers.size(); i++)
|
||||||
|
if (!m_e[i].need_more)
|
||||||
|
{
|
||||||
|
if (m_e[i].t < mint)
|
||||||
|
{
|
||||||
|
mint = m_e[i].t;
|
||||||
|
mini = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_e[mini].need_more = true;
|
||||||
|
m_cb(mini, mint, m_e[mini].v);
|
||||||
|
more = readmore(readers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
callback_type m_cb;
|
callback_type m_cb;
|
||||||
|
std::vector<elem> m_e;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct aggregator
|
struct aggregator
|
||||||
{
|
{
|
||||||
typedef plib::pmfp<void, double, double> callback_type;
|
typedef plib::pmfp<void, std::size_t, double, double> callback_type;
|
||||||
|
|
||||||
aggregator(double quantum, callback_type cb)
|
aggregator(std::size_t channels, double quantum, callback_type cb)
|
||||||
: m_quantum(quantum)
|
: m_channels(channels)
|
||||||
|
, m_quantum(quantum)
|
||||||
, m_cb(cb)
|
, m_cb(cb)
|
||||||
, ct(0.0)
|
, ct(0.0)
|
||||||
, lt(0.0)
|
, lt(0.0)
|
||||||
, outsam(0.0)
|
, outsam(channels, 0.0)
|
||||||
, cursam(0.0)
|
, cursam(channels, 0.0)
|
||||||
{ }
|
{ }
|
||||||
void process(double time, double val)
|
void process(std::size_t chan, double time, double val)
|
||||||
{
|
{
|
||||||
while (time >= ct)
|
while (time >= ct + m_quantum)
|
||||||
{
|
{
|
||||||
outsam += (ct - lt) * cursam;
|
for (std::size_t i=0; i< m_channels; i++)
|
||||||
outsam = outsam / m_quantum;
|
{
|
||||||
m_cb(ct, outsam);
|
outsam[i] += (ct - lt) * cursam[i];
|
||||||
outsam = 0.0;
|
outsam[i] = outsam[i] / m_quantum;
|
||||||
|
m_cb(i, ct, outsam[i]);
|
||||||
|
outsam[i] = 0.0;
|
||||||
|
}
|
||||||
lt = ct;
|
lt = ct;
|
||||||
ct += m_quantum;
|
ct += m_quantum;
|
||||||
}
|
}
|
||||||
outsam += (time-lt)*cursam;
|
for (std::size_t i=0; i< m_channels; i++)
|
||||||
|
outsam[i] += (time-lt)*cursam[i];
|
||||||
lt = time;
|
lt = time;
|
||||||
cursam = val;
|
cursam[chan] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::size_t m_channels;
|
||||||
double m_quantum;
|
double m_quantum;
|
||||||
callback_type m_cb;
|
callback_type m_cb;
|
||||||
double ct;
|
double ct;
|
||||||
double lt;
|
double lt;
|
||||||
double outsam;
|
std::vector<double> outsam;
|
||||||
double cursam;
|
std::vector<double> cursam;
|
||||||
};
|
};
|
||||||
|
|
||||||
class wavwriter
|
class wavwriter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wavwriter(plib::postream &fo, unsigned sample_rate, double ampa)
|
wavwriter(plib::postream &fo, std::size_t channels, std::size_t sample_rate, double ampa)
|
||||||
: mean(0.0)
|
: mean(channels, 0.0)
|
||||||
, means(0.0)
|
, means(channels, 0.0)
|
||||||
, maxsam(-1e9)
|
, maxsam(channels, -1e9)
|
||||||
, minsam(1e9)
|
, minsam(channels, 1e9)
|
||||||
, n(0)
|
, m_n(channels, 0)
|
||||||
|
, m_samples(channels, 0)
|
||||||
|
, m_last_time(0)
|
||||||
, m_fo(fo)
|
, m_fo(fo)
|
||||||
, amp(ampa)
|
, m_amp(ampa)
|
||||||
, m_wo(m_fo, sample_rate)
|
, m_wo(m_fo, sample_rate, channels)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void process(double time, double outsam)
|
void process(std::size_t chan, double time, double outsam)
|
||||||
{
|
{
|
||||||
means += outsam;
|
if (time > m_last_time)
|
||||||
maxsam = std::max(maxsam, outsam);
|
m_wo.write_sample(m_samples.data());
|
||||||
minsam = std::min(minsam, outsam);
|
m_last_time = time;
|
||||||
n++;
|
means[chan] += outsam;
|
||||||
//mean = means / (double) n;
|
maxsam[chan] = std::max(maxsam[chan], outsam);
|
||||||
mean += 5.0 / static_cast<double>(m_wo.sample_rate()) * (outsam - mean);
|
minsam[chan] = std::min(minsam[chan], outsam);
|
||||||
|
m_n[chan]++;
|
||||||
|
//mean = means / (double) m_n;
|
||||||
|
mean[chan] += 5.0 / static_cast<double>(m_wo.sample_rate()) * (outsam - mean[chan]);
|
||||||
|
|
||||||
outsam = (outsam - mean) * amp;
|
outsam = (outsam - mean[chan]) * m_amp;
|
||||||
outsam = std::max(-32000.0, outsam);
|
outsam = std::max(-32000.0, outsam);
|
||||||
outsam = std::min(32000.0, outsam);
|
outsam = std::min(32000.0, outsam);
|
||||||
m_wo.write_sample(static_cast<int>(outsam));
|
m_samples[chan] = static_cast<int>(outsam);
|
||||||
}
|
}
|
||||||
|
|
||||||
double mean;
|
std::vector<double> mean;
|
||||||
double means;
|
std::vector<double> means;
|
||||||
double maxsam;
|
std::vector<double> maxsam;
|
||||||
double minsam;
|
std::vector<double> minsam;
|
||||||
std::size_t n;
|
std::vector<std::size_t> m_n;
|
||||||
|
std::vector<int> m_samples;
|
||||||
|
double m_last_time;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
plib::postream &m_fo;
|
plib::postream &m_fo;
|
||||||
double amp;
|
double m_amp;
|
||||||
wav_t m_wo;
|
wav_t m_wo;
|
||||||
};
|
};
|
||||||
|
|
||||||
void nlwav_app::convert(long sample_rate)
|
class vcdwriter
|
||||||
{
|
{
|
||||||
plib::postream *fo = (opt_out() == "-" ? &pout_strm : plib::palloc<plib::pofilestream>(opt_out()));
|
public:
|
||||||
std::unique_ptr<plib::pistream> fin = (opt_inp() == "-" ?
|
|
||||||
plib::make_unique<plib::pstdin>()
|
|
||||||
: plib::make_unique<plib::pifilestream>(opt_inp()));
|
|
||||||
plib::putf8_reader reader(std::move(fin));
|
|
||||||
wav_t *wo = plib::palloc<wav_t>(*fo, static_cast<unsigned>(sample_rate));
|
|
||||||
|
|
||||||
double dt = 1.0 / static_cast<double>(wo->sample_rate());
|
enum format_e
|
||||||
double ct = dt;
|
{
|
||||||
//double mean = 2.4;
|
DIGITAL,
|
||||||
double amp = opt_amp();
|
ANALOG
|
||||||
double mean = 0.0;
|
};
|
||||||
double means = 0.0;
|
|
||||||
double cursam = 0.0;
|
|
||||||
double outsam = 0.0;
|
|
||||||
double lt = 0.0;
|
|
||||||
double maxsam = -1e9;
|
|
||||||
double minsam = 1e9;
|
|
||||||
int n = 0;
|
|
||||||
//short sample = 0;
|
|
||||||
pstring line;
|
|
||||||
|
|
||||||
while(reader.readline(line))
|
vcdwriter(plib::postream &fo, std::vector<pstring> channels,
|
||||||
|
format_e format, double high_level = 2.0, double low_level = 1.0)
|
||||||
|
: m_channels(channels.size())
|
||||||
|
, m_last_time(0)
|
||||||
|
, m_fo(fo)
|
||||||
|
, m_high_level(high_level)
|
||||||
|
, m_low_level(low_level)
|
||||||
|
, m_format(format)
|
||||||
{
|
{
|
||||||
#if 1
|
for (pstring::value_type c = 64; c < 64+26; c++)
|
||||||
double t = 0.0; double v = 0.0;
|
m_ids.push_back(pstring(c));
|
||||||
sscanf(line.c_str(), "%lf %lf", &t, &v);
|
write("$date Sat Jan 19 14:14:17 2019\n");
|
||||||
while (t >= ct)
|
write("$end\n");
|
||||||
|
write("$version Netlist nlwav 0.1\n");
|
||||||
|
write("$end\n");
|
||||||
|
write("$timescale 1 ns\n");
|
||||||
|
write("$end\n");
|
||||||
|
std::size_t i = 0;
|
||||||
|
for (auto ch : channels)
|
||||||
{
|
{
|
||||||
outsam += (ct - lt) * cursam;
|
// $var real 64 N1X1 N1X1 $end
|
||||||
outsam = outsam / dt;
|
if (format == ANALOG)
|
||||||
if (t>0.0)
|
write(pstring("$var real 64 ") + m_ids[i++] + " " + ch + " $end\n");
|
||||||
|
else if (format == DIGITAL)
|
||||||
|
write(pstring("$var wire 1 ") + m_ids[i++] + " " + ch + " $end\n");
|
||||||
|
}
|
||||||
|
write("$enddefinitions $end\n");
|
||||||
|
if (format == ANALOG)
|
||||||
{
|
{
|
||||||
means += outsam;
|
write("$dumpvars\n");
|
||||||
maxsam = std::max(maxsam, outsam);
|
//r0.0 N1X1
|
||||||
minsam = std::min(minsam, outsam);
|
for (i = 0; i < channels.size(); i++)
|
||||||
n++;
|
write(pstring("r0.0 ") + m_ids[i] + "\n");
|
||||||
//mean = means / (double) n;
|
write("$end\n");
|
||||||
mean += 5.0 / static_cast<double>(wo->sample_rate()) * (outsam - mean);
|
|
||||||
}
|
}
|
||||||
outsam = (outsam - mean) * amp;
|
|
||||||
outsam = std::max(-32000.0, outsam);
|
|
||||||
outsam = std::min(32000.0, outsam);
|
|
||||||
wo->write_sample(static_cast<int>(outsam));
|
|
||||||
outsam = 0.0;
|
|
||||||
lt = ct;
|
|
||||||
ct += dt;
|
|
||||||
}
|
}
|
||||||
outsam += (t-lt)*cursam;
|
|
||||||
lt = t;
|
void process(std::size_t chan, double time, double outsam)
|
||||||
cursam = v;
|
|
||||||
#else
|
|
||||||
float t = 0.0; float v = 0.0;
|
|
||||||
fscanf(FIN, "%f %f", &t, &v);
|
|
||||||
while (ct <= t)
|
|
||||||
{
|
{
|
||||||
wo.write_sample(sample);
|
if (time > m_last_time)
|
||||||
n++;
|
{
|
||||||
ct += dt;
|
write(pstring("#") + plib::to_string(static_cast<std::int64_t>(m_last_time * 1e9)) + " ");
|
||||||
|
write(m_buf + "\n");
|
||||||
|
m_buf = "";
|
||||||
|
m_last_time = time;
|
||||||
}
|
}
|
||||||
means += v;
|
if (m_format == ANALOG)
|
||||||
mean = means / (double) n;
|
m_buf += "r" + plib::to_string(outsam)+ " " + m_ids[chan] + " ";
|
||||||
v = v - mean;
|
else
|
||||||
v = v * amp;
|
{
|
||||||
if (v>32000.0)
|
if (outsam >= m_high_level)
|
||||||
v = 32000.0;
|
m_buf += pstring("1") + m_ids[chan] + " ";
|
||||||
else if (v<-32000.0)
|
else if (outsam <= m_low_level)
|
||||||
v = -32000.0;
|
m_buf += pstring("0") + m_ids[chan] + " ";
|
||||||
sample = v;
|
|
||||||
//printf("%f %f\n", t, v);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
plib::pfree(wo);
|
}
|
||||||
if (opt_out() != "-")
|
|
||||||
plib::pfree(fo);
|
std::size_t m_channels;
|
||||||
|
double m_last_time;
|
||||||
if (!opt_quiet())
|
|
||||||
{
|
private:
|
||||||
perr("Mean (low freq filter): {}\n", mean);
|
void write(pstring line)
|
||||||
perr("Mean (static): {}\n", means / static_cast<double>(n));
|
{
|
||||||
perr("Amp + {}\n", 32000.0 / (maxsam- mean));
|
auto p = static_cast<const char *>(line.c_str());
|
||||||
perr("Amp - {}\n", -32000.0 / (minsam- mean));
|
std::size_t len = std::strlen(p);
|
||||||
}
|
m_fo.write(p, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nlwav_app::convert1(long sample_rate)
|
plib::postream &m_fo;
|
||||||
{
|
std::vector<pstring> m_ids;
|
||||||
plib::postream *fo = (opt_out() == "-" ? &pout_strm : plib::palloc<plib::pofilestream>(opt_out()));
|
pstring m_buf;
|
||||||
std::unique_ptr<plib::pistream> fin = (opt_inp() == "-" ?
|
double m_high_level;
|
||||||
plib::make_unique<plib::pstdin>()
|
double m_low_level;
|
||||||
: plib::make_unique<plib::pifilestream>(opt_inp()));
|
format_e m_format;
|
||||||
|
};
|
||||||
double dt = 1.0 / static_cast<double>(sample_rate);
|
|
||||||
|
class nlwav_app : public plib::app
|
||||||
wavwriter *wo = plib::palloc<wavwriter>(*fo, static_cast<unsigned>(sample_rate), opt_amp());
|
{
|
||||||
aggregator ag(dt, aggregator::callback_type(&wavwriter::process, wo));
|
public:
|
||||||
log_processor lp(log_processor::callback_type(&aggregator::process, &ag));
|
nlwav_app() :
|
||||||
|
plib::app(),
|
||||||
lp.process(std::move(fin));
|
opt_fmt(*this, "f", "format", 0, std::vector<pstring>({"wav","vcda","vcdd"}),
|
||||||
|
"output format. Available options are wav|vcda|vcdd.\n"
|
||||||
|
"wav : multichannel wav output\n"
|
||||||
|
"vcda : analog VCD output\n"
|
||||||
|
"vcdd : digital VCD output\n"
|
||||||
|
"Digital signals are created using the high and low options"
|
||||||
|
),
|
||||||
|
opt_out(*this, "o", "output", "-", "output file"),
|
||||||
|
opt_rate(*this, "r", "rate", 48000, "sample rate of output file"),
|
||||||
|
opt_amp(*this, "a", "amp", 10000.0, "amplification after mean correction (wav only)"),
|
||||||
|
opt_high(*this, "u", "high", 2.0, "minimum input for high level (vcdd only)"),
|
||||||
|
opt_low(*this, "l", "low", 1.0, "maximum input for low level (vcdd only)"),
|
||||||
|
opt_verb(*this, "v", "verbose", "be verbose - this produces lots of output"),
|
||||||
|
opt_quiet(*this,"q", "quiet", "be quiet - no warnings"),
|
||||||
|
opt_args(*this, "input file(s)"),
|
||||||
|
opt_version(*this, "", "version", "display version and exit"),
|
||||||
|
opt_help(*this, "h", "help", "display help and exit"),
|
||||||
|
opt_ex1(*this, "./nlwav -f vcdd -o x.vcd log_V*",
|
||||||
|
"convert all files starting with \"log_V\" into a digital vcd file"),
|
||||||
|
opt_ex2(*this, "./nlwav -f wav -o x.wav log_V*",
|
||||||
|
"convert all files starting with \"log_V\" into a multichannel wav file"),
|
||||||
|
m_outstrm(nullptr)
|
||||||
|
{}
|
||||||
|
plib::option_str_limit<unsigned> opt_fmt;
|
||||||
|
plib::option_str opt_out;
|
||||||
|
plib::option_num<std::size_t> opt_rate;
|
||||||
|
plib::option_num<double> opt_amp;
|
||||||
|
plib::option_num<double> opt_high;
|
||||||
|
plib::option_num<double> opt_low;
|
||||||
|
plib::option_bool opt_verb;
|
||||||
|
plib::option_bool opt_quiet;
|
||||||
|
plib::option_args opt_args;
|
||||||
|
plib::option_bool opt_version;
|
||||||
|
plib::option_bool opt_help;
|
||||||
|
plib::option_example opt_ex1;
|
||||||
|
plib::option_example opt_ex2;
|
||||||
|
|
||||||
|
int execute();
|
||||||
|
pstring usage();
|
||||||
|
|
||||||
|
plib::pstdin pin_strm;
|
||||||
|
private:
|
||||||
|
void convert_wav();
|
||||||
|
void convert_vcd(vcdwriter::format_e format);
|
||||||
|
std::vector<std::unique_ptr<plib::pistream>> m_instrms;
|
||||||
|
plib::postream *m_outstrm;
|
||||||
|
};
|
||||||
|
|
||||||
|
void nlwav_app::convert_wav()
|
||||||
|
{
|
||||||
|
|
||||||
|
double dt = 1.0 / static_cast<double>(opt_rate());
|
||||||
|
|
||||||
|
std::unique_ptr<wavwriter> wo = plib::make_unique<wavwriter>(*m_outstrm, m_instrms.size(), opt_rate(), opt_amp());
|
||||||
|
std::unique_ptr<aggregator> ago = plib::make_unique<aggregator>(m_instrms.size(), dt, aggregator::callback_type(&wavwriter::process, wo.get()));
|
||||||
|
aggregator::callback_type agcb = log_processor::callback_type(&aggregator::process, ago.get());
|
||||||
|
|
||||||
|
log_processor lp(m_instrms.size(), agcb);
|
||||||
|
|
||||||
|
lp.process(m_instrms);
|
||||||
|
|
||||||
if (!opt_quiet())
|
if (!opt_quiet())
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
perr("Mean (low freq filter): {}\n", wo->mean);
|
perr("Mean (low freq filter): {}\n", wo->mean);
|
||||||
perr("Mean (static): {}\n", wo->means / static_cast<double>(wo->n));
|
perr("Mean (static): {}\n", wo->means / static_cast<double>(wo->m_n));
|
||||||
perr("Amp + {}\n", 32000.0 / (wo->maxsam - wo->mean));
|
perr("Amp + {}\n", 32000.0 / (wo->maxsam - wo->mean));
|
||||||
perr("Amp - {}\n", -32000.0 / (wo->minsam - wo->mean));
|
perr("Amp - {}\n", -32000.0 / (wo->minsam - wo->mean));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plib::pfree(wo);
|
void nlwav_app::convert_vcd(vcdwriter::format_e format)
|
||||||
if (opt_out() != "-")
|
{
|
||||||
plib::pfree(fo);
|
|
||||||
|
|
||||||
|
std::unique_ptr<vcdwriter> wo = plib::make_unique<vcdwriter>(*m_outstrm, opt_args(),
|
||||||
|
format, opt_high(), opt_low());
|
||||||
|
log_processor::callback_type agcb = log_processor::callback_type(&vcdwriter::process, wo.get());
|
||||||
|
|
||||||
|
log_processor lp(m_instrms.size(), agcb);
|
||||||
|
|
||||||
|
lp.process(m_instrms);
|
||||||
|
|
||||||
|
if (!opt_quiet())
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
perr("Mean (low freq filter): {}\n", wo->mean);
|
||||||
|
perr("Mean (static): {}\n", wo->means / static_cast<double>(wo->m_n));
|
||||||
|
perr("Amp + {}\n", 32000.0 / (wo->maxsam - wo->mean));
|
||||||
|
perr("Amp - {}\n", -32000.0 / (wo->minsam - wo->mean));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pstring nlwav_app::usage()
|
pstring nlwav_app::usage()
|
||||||
{
|
{
|
||||||
return help("Convert netlist log files into wav files.\n",
|
return help("Convert netlist log files into wav files.\n",
|
||||||
"nltool [options]");
|
"nlwav [OPTION] ... [FILE] ...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int nlwav_app::execute()
|
int nlwav_app::execute()
|
||||||
{
|
{
|
||||||
|
for (auto &i : opt_args())
|
||||||
|
pout(pstring("Hello : ") + i + "\n");
|
||||||
if (opt_help())
|
if (opt_help())
|
||||||
{
|
{
|
||||||
pout(usage());
|
pout(usage());
|
||||||
@ -393,10 +503,31 @@ int nlwav_app::execute()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((1))
|
m_outstrm = (opt_out() == "-" ? &pout_strm : plib::palloc<plib::pofilestream>(opt_out()));
|
||||||
convert1(opt_rate());
|
|
||||||
else
|
for (auto &oi: opt_args())
|
||||||
convert(opt_rate());
|
{
|
||||||
|
std::unique_ptr<plib::pistream> fin = (oi == "-" ?
|
||||||
|
plib::make_unique<plib::pstdin>()
|
||||||
|
: plib::make_unique<plib::pifilestream>(oi));
|
||||||
|
m_instrms.push_back(std::move(fin));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opt_fmt())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
convert_wav(); break;
|
||||||
|
case 1:
|
||||||
|
convert_vcd(vcdwriter::ANALOG); break;
|
||||||
|
case 2:
|
||||||
|
convert_vcd(vcdwriter::DIGITAL); break;
|
||||||
|
default:
|
||||||
|
// tease compiler - can't happen
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_out() != "-")
|
||||||
|
plib::pfree(m_outstrm);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// copyright-holders:Andrew Gardner, Couriersud
|
// copyright-holders:Andrew Gardner, Couriersud
|
||||||
#include "netlist/devices/net_lib.h"
|
#include "netlist/devices/net_lib.h"
|
||||||
|
|
||||||
#define USE_FRONTIERS 1
|
#define USE_FRONTIERS 0
|
||||||
#define USE_FIXED_STV 1
|
#define USE_FIXED_STV 1
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
@ -308,7 +308,7 @@ NETLIST_END()
|
|||||||
|
|
||||||
NETLIST_START(kidniki)
|
NETLIST_START(kidniki)
|
||||||
|
|
||||||
#if (1 || USE_FRONTIERS)
|
#if (0 || USE_FRONTIERS)
|
||||||
SOLVER(Solver, 18000)
|
SOLVER(Solver, 18000)
|
||||||
PARAM(Solver.ACCURACY, 1e-7)
|
PARAM(Solver.ACCURACY, 1e-7)
|
||||||
PARAM(Solver.NR_LOOPS, 100)
|
PARAM(Solver.NR_LOOPS, 100)
|
||||||
@ -322,9 +322,9 @@ NETLIST_START(kidniki)
|
|||||||
PARAM(Solver.DYNAMIC_LTE, 5e-4)
|
PARAM(Solver.DYNAMIC_LTE, 5e-4)
|
||||||
PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 20e-6)
|
PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 20e-6)
|
||||||
#else
|
#else
|
||||||
SOLVER(Solver, 12000)
|
SOLVER(Solver, 18000)
|
||||||
PARAM(Solver.ACCURACY, 1e-8)
|
PARAM(Solver.ACCURACY, 1e-6)
|
||||||
PARAM(Solver.NR_LOOPS, 300)
|
PARAM(Solver.NR_LOOPS, 100)
|
||||||
PARAM(Solver.GS_LOOPS, 20)
|
PARAM(Solver.GS_LOOPS, 20)
|
||||||
PARAM(Solver.METHOD, "GMRES")
|
PARAM(Solver.METHOD, "GMRES")
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user