diff options
author | 2015-07-26 20:02:50 +0200 | |
---|---|---|
committer | 2015-07-26 20:03:13 +0200 | |
commit | 8b388e91316769c5e71d53c435127f73d8d60a9a (patch) | |
tree | f403074bdebe6db4c12c9a7cc9a63cc506a78ab1 | |
parent | f3686bb125ee63e4b08eb7d60dcaf8dce88d06c8 (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.c | 6 | ||||
-rw-r--r-- | scripts/src/tools.lua | 36 | ||||
-rw-r--r-- | src/tools/nltool.c | 78 | ||||
-rw-r--r-- | src/tools/nlwav.c | 292 |
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) +*/ |