summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author couriersud <couriersud@arcor.de>2015-07-26 20:02:50 +0200
committer couriersud <couriersud@arcor.de>2015-07-26 20:03:13 +0200
commit8b388e91316769c5e71d53c435127f73d8d60a9a (patch)
treef403074bdebe6db4c12c9a7cc9a63cc506a78ab1
parentf3686bb125ee63e4b08eb7d60dcaf8dce88d06c8 (diff)
Added nlwav to tools. nlwav converts netlist logs into wav files.
Example usage: ./nlwav -i netlist.log_RO.1.log -o tt.wav ./nlwav -h [Couriersud]
-rw-r--r--nl_examples/congo_bongo.c6
-rw-r--r--scripts/src/tools.lua36
-rw-r--r--src/tools/nltool.c78
-rw-r--r--src/tools/nlwav.c292
4 files changed, 408 insertions, 4 deletions
diff --git a/nl_examples/congo_bongo.c b/nl_examples/congo_bongo.c
index 25f8258f290..8f0a4de31e2 100644
--- a/nl_examples/congo_bongo.c
+++ b/nl_examples/congo_bongo.c
@@ -34,7 +34,7 @@ NETLIST_START(dummy)
// .END
SOLVER(Solver, 24000)
- PARAM(Solver.ACCURACY, 1e-7)
+ PARAM(Solver.ACCURACY, 1e-9)
PARAM(Solver.NR_LOOPS, 90)
PARAM(Solver.SOR_FACTOR, 0.001)
PARAM(Solver.GS_LOOPS, 1)
@@ -50,8 +50,8 @@ NETLIST_START(dummy)
//CLOCK(I_CONGA_H0, 2)
TTL_INPUT(I_CONGA_L0, 0)
//CLOCK(I_CONGA_L0, 2)
- //TTL_INPUT(I_GORILLA0, 0)
- CLOCK(I_GORILLA0, 2)
+ TTL_INPUT(I_GORILLA0, 0)
+ //CLOCK(I_GORILLA0, 2)
TTL_INPUT(I_RIM0, 0)
//CLOCK(I_RIM0, 2)
diff --git a/scripts/src/tools.lua b/scripts/src/tools.lua
index 55f966eed2e..e2cb09d44d9 100644
--- a/scripts/src/tools.lua
+++ b/scripts/src/tools.lua
@@ -619,6 +619,42 @@ files {
}
--------------------------------------------------
+-- nlwav
+--------------------------------------------------
+
+project("nlwav")
+uuid ("7c5396d1-2a1a-4c93-bed6-6b8fa182054a")
+kind "ConsoleApp"
+
+options {
+ "ForceCPP",
+}
+
+flags {
+ "Symbols", -- always include minimum symbols for executables
+}
+
+if _OPTIONS["SEPARATE_BIN"]~="1" then
+ targetdir(MAME_DIR)
+end
+
+links {
+ "utils",
+ "ocore_" .. _OPTIONS["osd"],
+ "netlist",
+}
+
+includedirs {
+ MAME_DIR .. "src/osd",
+ MAME_DIR .. "src/lib/util",
+ MAME_DIR .. "src/emu/netlist",
+}
+
+files {
+ MAME_DIR .. "src/tools/nlwav.c",
+}
+
+--------------------------------------------------
-- castool
--------------------------------------------------
diff --git a/src/tools/nltool.c b/src/tools/nltool.c
index 488f98c9f9a..3a898c1f96d 100644
--- a/src/tools/nltool.c
+++ b/src/tools/nltool.c
@@ -104,6 +104,7 @@ public:
opt_file("f", "file", "-", "file to process (default is stdin)", this),
opt_type("y", "type", "spice", "spice:eagle", "type of file to be converted: spice,eagle", this),
opt_cmd ("c", "cmd", "run", "run|convert|listdevices", this),
+ opt_inp( "i", "input", "", "input file to process (default is none)", this),
opt_verb("v", "verbose", "be verbose - this produces lots of output", this),
opt_quiet("q", "quiet", "be quiet - no warnings", this),
opt_help("h", "help", "display help", this)
@@ -115,6 +116,7 @@ public:
poption_str opt_file;
poption_str_limit opt_type;
poption_str opt_cmd;
+ poption_str opt_inp;
poption_bool opt_verb;
poption_bool opt_quiet;
poption_bool opt_help;
@@ -263,6 +265,66 @@ void usage(tool_options_t &opts)
fprintf(stderr, "%s\n", opts.help().cstr());
}
+struct input_t
+{
+ netlist::netlist_time m_time;
+ netlist::param_t *m_param;
+ double m_value;
+
+ input_t()
+ {
+
+ }
+ input_t(netlist::netlist_t *netlist, const pstring &line)
+ {
+ char buf[400];
+ double t;
+ int e = sscanf(line.cstr(), "%lf,%[^,],%lf", &t, buf, &m_value);
+ if ( e!= 3)
+ throw netlist::fatalerror_e("error %d scanning line %s\n", e, line.cstr());
+ m_time = netlist::netlist_time::from_double(t);
+ m_param = netlist->setup().find_param(buf, true);
+ }
+
+ void setparam()
+ {
+ switch (m_param->param_type())
+ {
+ case netlist::param_t::MODEL:
+ case netlist::param_t::STRING:
+ throw netlist::fatalerror_e("param %s is not numeric\n", m_param->name().cstr());
+ case netlist::param_t::DOUBLE:
+ static_cast<netlist::param_double_t*>(m_param)->setTo(m_value);
+ break;
+ case netlist::param_t::INTEGER:
+ static_cast<netlist::param_int_t*>(m_param)->setTo((int)m_value);
+ break;
+ case netlist::param_t::LOGIC:
+ static_cast<netlist::param_logic_t*>(m_param)->setTo((int) m_value);
+ break;
+ }
+ }
+};
+
+plist_t<input_t> *read_input(netlist::netlist_t *netlist, pstring fname)
+{
+ plist_t<input_t> *ret = palloc(plist_t<input_t>());
+ if (fname != "")
+ {
+ pstring_list_t lines(filetobuf(fname) , "\n");
+ for (unsigned i=0; i<lines.size(); i++)
+ {
+ pstring l = lines[i].trim();
+ if (l != "")
+ {
+ input_t inp(netlist, l);
+ ret->add(inp);
+ }
+ }
+ }
+ return ret;
+}
+
static void run(tool_options_t &opts)
{
netlist_tool_t nt;
@@ -271,14 +333,28 @@ static void run(tool_options_t &opts)
nt.m_opts = &opts;
nt.init();
nt.read_netlist(filetobuf(opts.opt_file()), opts.opt_name());
+
+ plist_t<input_t> *inps = read_input(&nt, opts.opt_inp());
+
double ttr = opts.opt_ttr();
printf("startup time ==> %5.3f\n", (double) (osd_ticks() - t) / (double) osd_ticks_per_second() );
printf("runnning ...\n");
t = osd_ticks();
- nt.process_queue(netlist::netlist_time::from_double(ttr));
+ unsigned pos = 0;
+ netlist::netlist_time nlt = netlist::netlist_time::zero;
+
+ while (pos < inps->size() && (*inps)[pos].m_time < netlist::netlist_time::from_double(ttr))
+ {
+ nt.process_queue((*inps)[pos].m_time - nlt);
+ (*inps)[pos].setparam();
+ nlt = (*inps)[pos].m_time;
+ pos++;
+ }
+ nt.process_queue(netlist::netlist_time::from_double(ttr) - nlt);
nt.stop();
+ pfree(inps);
double emutime = (double) (osd_ticks() - t) / (double) osd_ticks_per_second();
printf("%f seconds emulation took %f real time ==> %5.2f%%\n", ttr, emutime, ttr/emutime*100.0);
diff --git a/src/tools/nlwav.c b/src/tools/nlwav.c
new file mode 100644
index 00000000000..731358be6e9
--- /dev/null
+++ b/src/tools/nlwav.c
@@ -0,0 +1,292 @@
+#include <cstdio>
+#include <cstring>
+#include "plib/poptions.h"
+#include "plib/pstring.h"
+#include "plib/plists.h"
+#include "nl_setup.h"
+
+class nlwav_options_t : public poptions
+{
+public:
+ nlwav_options_t() :
+ poptions(),
+#if 0
+ opt_ttr ("t", "time_to_run", 1.0, "time to run the emulation (seconds)", this),
+ opt_name("n", "name", "", "netlist in file to run; default is first one", this),
+ opt_logs("l", "logs", "", "colon separated list of terminals to log", this),
+ opt_file("f", "file", "-", "file to process (default is stdin)", this),
+ opt_type("y", "type", "spice", "spice:eagle", "type of file to be converted: spice,eagle", this),
+ opt_cmd ("c", "cmd", "run", "run|convert|listdevices", this),
+ opt_inp( "i", "input", "", "input file to process (default is none)", this),
+#endif
+ opt_inp( "i", "input", "", "input file", this),
+ opt_out( "o", "output", "", "output file", this),
+ opt_amp( "a", "amp", 10000.0, "amplification after mean correction", this),
+ opt_verb("v", "verbose", "be verbose - this produces lots of output", this),
+ opt_quiet("q", "quiet", "be quiet - no warnings", this),
+ opt_help("h", "help", "display help", this)
+ {}
+#if 0
+ poption_double opt_ttr;
+ poption_str opt_name;
+ poption_str opt_logs;
+ poption_str opt_file;
+ poption_str_limit opt_type;
+ poption_str opt_cmd;
+#endif
+ poption_str opt_inp;
+ poption_str opt_out;
+ poption_double opt_amp;
+ poption_bool opt_verb;
+ poption_bool opt_quiet;
+ poption_bool opt_help;
+};
+
+/* http://de.wikipedia.org/wiki/RIFF_WAVE */
+class wav_t
+{
+public:
+ wav_t(const pstring &fn, unsigned sr)
+ {
+ m_f = std::fopen(fn.cstr(),"w");
+ if (m_f==NULL)
+ throw netlist::fatalerror_e("Error opening output file: %s", fn.cstr());
+ initialize(sr);
+ std::fwrite(&m_fh, sizeof(m_fh), 1, m_f);
+ std::fwrite(&m_fmt, sizeof(m_fmt), 1, m_f);
+ std::fwrite(&m_data, sizeof(m_data), 1, m_f);
+ }
+ ~wav_t()
+ {
+ close();
+ }
+
+ unsigned channels() { return m_fmt.channels; }
+ unsigned sample_rate() { return m_fmt.sample_rate; }
+
+ void write_sample(int sample)
+ {
+ m_data.len += m_fmt.block_align;
+ short ps = sample; /* 16 bit sample, FIXME: powerpc? */
+ std::fwrite(&ps, sizeof(ps), 1, m_f);
+ }
+
+ void close()
+ {
+ if (m_f != NULL)
+ {
+ std::fseek(m_f, 0, SEEK_SET);
+ std::fwrite(&m_fh, sizeof(m_fh), 1, m_f);
+ std::fwrite(&m_fmt, sizeof(m_fmt), 1, m_f);
+
+ //data.len = fmt.block_align * n;
+ std::fwrite(&m_data, sizeof(m_data), 1, m_f);
+
+
+ std::fclose(m_f);
+ m_f = NULL;
+ }
+ }
+private:
+ struct riff_chunk_t
+ {
+ char group_id[4];
+ unsigned filelen;
+ char rifftype[4];
+ };
+
+ struct riff_format_t
+ {
+ char signature[4];
+ unsigned fmt_length;
+ short format_tag;
+ short channels;
+ unsigned sample_rate;
+ unsigned bytes_per_second;
+ short block_align;
+ short bits_sample;
+ };
+
+ struct riff_data_t
+ {
+ char signature[4];
+ unsigned len;
+ // data follows
+ };
+
+ void initialize(unsigned sr)
+ {
+ std::strncpy(m_fh.group_id, "RIFF", 4);
+ m_fh.filelen = 0; // Fixme
+ std::strncpy(m_fh.rifftype, "WAVE", 4);
+
+ std::strncpy(m_fmt.signature, "fmt ", 4);
+ m_fmt.fmt_length = 16;
+ m_fmt.format_tag = 0x0001; //PCM
+ m_fmt.channels = 1;
+ m_fmt.sample_rate = sr;
+ m_fmt.bits_sample = 16;
+ 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;
+
+ std::strncpy(m_data.signature, "data", 4);
+ m_data.len = m_fmt.bytes_per_second * 2 * 0;
+
+ }
+
+ riff_chunk_t m_fh;
+ riff_format_t m_fmt;
+ riff_data_t m_data;
+
+ FILE *m_f;
+
+};
+
+void convert(nlwav_options_t &opts)
+{
+
+ wav_t wo(opts.opt_out(), 48000);
+
+ FILE *FIN = std::fopen(opts.opt_inp(),"r");
+ if (FIN==NULL)
+ throw netlist::fatalerror_e("Error opening input file: %s", opts.opt_inp().cstr());
+
+ double dt = 1.0 / (double) wo.sample_rate();
+ double ct = dt;
+ //double mean = 2.4;
+ double amp = opts.opt_amp();
+ 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;
+
+
+ while(!std::feof(FIN))
+ {
+#if 1
+ float t = 0.0; float v = 0.0;
+ fscanf(FIN, "%f %f", &t, &v);
+ while (t >= ct)
+ {
+ outsam += (ct - lt) * cursam;
+ outsam = outsam / dt;
+ if (t>0.0)
+ {
+ means += outsam;
+ maxsam = std::max(maxsam, outsam);
+ minsam = std::min(minsam, outsam);
+ n++;
+ //mean = means / (double) n;
+ mean += 5.0 / (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((int) outsam);
+ outsam = 0.0;
+ lt = ct;
+ ct += dt;
+ }
+ outsam += (t-lt)*cursam;
+ lt = t;
+ cursam = v;
+#else
+ float t = 0.0; float v = 0.0;
+ fscanf(FIN, "%f %f", &t, &v);
+ while (ct <= t)
+ {
+ wo.write_sample(sample);
+ n++;
+ ct += dt;
+ }
+ means += v;
+ mean = means / (double) n;
+ v = v - mean;
+ v = v * amp;
+ if (v>32000.0)
+ v = 32000.0;
+ else if (v<-32000.0)
+ v = -32000.0;
+ sample = v;
+ //printf("%f %f\n", t, v);
+#endif
+ }
+ printf("Mean (low freq filter): %f\n", mean);
+ printf("Mean (static): %f\n", means / (double) n);
+ printf("Amp + %f\n", 32000.0 / (maxsam- mean));
+ printf("Amp - %f\n", -32000.0 / (minsam- mean));
+ wo.close();
+ fclose(FIN);
+
+}
+
+void usage(nlwav_options_t &opts)
+{
+ fprintf(stderr,
+ "Usage:\n"
+ " nltool -help\n"
+ " nltool [options]\n"
+ "\n"
+ "Where:\n"
+ );
+ fprintf(stderr, "%s\n", opts.help().cstr());
+}
+
+
+int main(int argc, char *argv[])
+{
+#if (!PSTANDALONE)
+ track_memory(true);
+ {
+#endif
+ nlwav_options_t opts;
+ int ret;
+
+ if ((ret = opts.parse(argc, argv)) != argc)
+ {
+ fprintf(stderr, "Error parsing %s\n", argv[ret]);
+ usage(opts);
+ return 1;
+ }
+
+ if (opts.opt_help())
+ {
+ usage(opts);
+ return 1;
+ }
+
+ convert(opts);
+#if (!PSTANDALONE)
+ }
+ dump_unfreed_mem();
+#endif
+
+ return 0;
+}
+
+/*
+Der Daten-Abschnitt enthält die Abtastwerte:
+Offset Länge Inhalt Beschreibung
+36 (0x24) 4 'data' Header-Signatur
+40 (0x28) 4 <length> Länge des Datenblocks, max. <Dateigröße> − 44
+
+0 (0x00) char 4 'RIFF'
+4 (0x04) unsigned 4 <Dateigröße> − 8
+8 (0x08) char 4 'WAVE'
+
+Der fmt-Abschnitt (24 Byte) beschreibt das Format der einzelnen Abtastwerte:
+Offset Länge Inhalt Beschreibung
+12 (0x0C) 4 'fmt ' Header-Signatur (folgendes Leerzeichen beachten)
+16 (0x10) 4 <fmt length> Länge des restlichen fmt-Headers (16 Bytes)
+20 (0x14) 2 <format tag> Datenformat der Abtastwerte (siehe separate Tabelle weiter unten)
+22 (0x16) 2 <channels> Anzahl der Kanäle: 1 = mono, 2 = stereo; mittlerweile sind auch mehr als 2 Kanäle (z. B. für Raumklang) möglich.[2]
+24 (0x18) 4 <sample rate> Samples pro Sekunde je Kanal (z. B. 44100)
+28 (0x1C) 4 <bytes/second> Abtastrate · Frame-Größe
+32 (0x20) 2 <block align> Frame-Größe = <Anzahl der Kanäle> · ((<Bits/Sample (eines Kanals)> + 7) / 8) (Division ohne Rest)
+34 (0x22) 2 <bits/sample> Anzahl der Datenbits pro Samplewert je Kanal (z. B. 12)
+*/