nlwav: add sampled output format. [Couriersud]

Using this output format nlwav will pick point samples at regular
intervals from log files. This can be used to e.g. calculate
RGB output levels with netlist.
This commit is contained in:
couriersud 2020-03-02 18:15:22 +01:00
parent 8330b75048
commit fde057ba00
3 changed files with 106 additions and 11 deletions

View File

@ -251,7 +251,7 @@ namespace devices
{
NETLIB_CONSTRUCTOR(logic_inputN)
, m_Q(*this, "Q{}")
, m_IN(*this, "IN", false)
, m_IN(*this, "IN", 0)
// make sure we get the family first
, m_FAMILY(*this, "FAMILY", "FAMILY(TYPE=TTL)")
, m_supply(*this)

View File

@ -1733,10 +1733,6 @@ namespace netlist
class object_array_t : public plib::uninitialised_array_t<C, N>
{
public:
struct init
{
std::array<const char *, N> p;
};
template<typename... Args>
object_array_t(core_device_t &dev, const std::initializer_list<const char *> &names, Args&&... args)
{

View File

@ -373,23 +373,93 @@ private:
format_e m_format;
};
class tabwriter
{
public:
enum format_e
{
DIGITAL,
ANALOG
};
tabwriter(std::ostream &fo, const std::vector<pstring> &channels,
double start, double inc, std::size_t samples)
: m_last_time(0)
, m_next_time(start)
, m_fo(fo)
, m_inc(inc)
, m_samples(samples)
, m_buf(channels.size())
, m_n(0)
{
}
void process(std::size_t chan, double time, double outsam)
{
if (time > m_last_time)
{
if (m_n < m_samples)
{
while (m_next_time < time && m_n < m_samples)
{
pstring o;
for (auto e = m_buf.begin(); e != m_buf.end(); e++)
{
o += pstring(",") + plib::to_string(*e); // FIXME: locale!!
}
write(o.substr(1) + "\n");
m_n++;
m_next_time += m_inc;
}
}
m_last_time = time;
}
m_buf[chan] = outsam;
}
private:
void write(const pstring &line)
{
m_fo.write(line.c_str(), static_cast<std::streamsize>(plib::strlen(line.c_str())));
}
double m_last_time;
double m_next_time;
std::ostream &m_fo;
std::vector<pstring> m_ids;
double m_inc;
std::size_t m_samples;
std::vector<double> m_buf;
std::size_t m_n;
};
class nlwav_app : public plib::app
{
public:
nlwav_app() :
plib::app(),
opt_fmt(*this, "f", "format", 0, std::vector<pstring>({"wav","vcda","vcdd"}),
"output format. Available options are wav|vcda|vcdd."
opt_fmt(*this, "f", "format", 0, std::vector<pstring>({"wav","vcda","vcdd", "tab"}),
"output format. Available options are wav|vcda|vcdd|tab."
" wav : multichannel wav output"
" vcda : analog VCD output"
" vcdd : digital VCD output"
" tab : sampled output"
" Digital signals are created using the --high and --low options"
),
opt_out(*this, "o", "output", "-", "output file"),
opt_grp1(*this, "wav options", "These options apply to wav output only"),
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_amp(*this, "a", "amp", 10000.0, "amplification after mean correction"),
opt_grp2(*this, "vcdd options", "These options apply to vcdd output only"),
opt_high(*this, "u", "high", 2.0, "minimum input for high level"),
opt_low(*this, "l", "low", 1.0, "maximum input for low level"),
opt_grp3(*this, "tab options", "These options apply to sampled output only"),
opt_start(*this, "s", "start", 0.0, "time when sampling starts"),
opt_inc(*this, "i", "increment", 0.001, "time between samples"),
opt_samples(*this, "n", "samples", 1000000,"number of samples"),
opt_grp4(*this, "General options", "These options always apply"),
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)"),
@ -398,7 +468,10 @@ public:
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")
"convert all files starting with \"log_V\" into a multichannel wav file"),
opt_ex3(*this, "./nlwav -f tab -o x.tab -s 0.0000005 -i 0.000001 -n 256 log_BLUE.log",
"convert file log_BLUE.log to sampled output. First sample at 500ns "
"followed by 255 samples every micro-second.")
{}
int execute() override;
@ -407,14 +480,23 @@ public:
private:
void convert_wav(std::ostream &ostrm);
void convert_vcd(std::ostream &ostrm, vcdwriter::format_e format);
void convert_tab(std::ostream &ostrm);
void convert(std::ostream &ostrm);
plib::option_str_limit<unsigned> opt_fmt;
plib::option_str opt_out;
plib::option_group opt_grp1;
plib::option_num<std::size_t> opt_rate;
plib::option_num<double> opt_amp;
plib::option_group opt_grp2;
plib::option_num<double> opt_high;
plib::option_num<double> opt_low;
plib::option_group opt_grp3;
plib::option_num<double> opt_start;
plib::option_num<double> opt_inc;
plib::option_num<std::size_t> opt_samples;
plib::option_group opt_grp4;
plib::option_bool opt_verb;
plib::option_bool opt_quiet;
plib::option_args opt_args;
@ -422,6 +504,7 @@ private:
plib::option_bool opt_help;
plib::option_example opt_ex1;
plib::option_example opt_ex2;
plib::option_example opt_ex3;
std::vector<plib::unique_ptr<std::istream>> m_instrms;
};
@ -471,6 +554,20 @@ void nlwav_app::convert_vcd(std::ostream &ostrm, vcdwriter::format_e format)
}
}
void nlwav_app::convert_tab(std::ostream &ostrm)
{
auto wo = plib::make_unique<tabwriter>(ostrm, opt_args(),
opt_start(), opt_inc(), opt_samples());
log_processor::callback_type agcb = log_processor::callback_type(&tabwriter::process, wo.get());
log_processor lp(m_instrms.size(), agcb);
lp.process(m_instrms);
}
pstring nlwav_app::usage()
{
return help("Convert netlist log files into wav files.\n",
@ -487,6 +584,8 @@ void nlwav_app::convert(std::ostream &ostrm)
convert_vcd(ostrm, vcdwriter::ANALOG); break;
case 2:
convert_vcd(ostrm, vcdwriter::DIGITAL); break;
case 3:
convert_tab(ostrm); break;
default:
// tease compiler - can't happen
break;