mirror of
https://github.com/holub/mame
synced 2025-04-19 23:12:11 +03:00
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]
This commit is contained in:
parent
f3686bb125
commit
8b388e9131
@ -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)
|
||||
|
||||
|
@ -618,6 +618,42 @@ files {
|
||||
MAME_DIR .. "src/tools/nltool.c",
|
||||
}
|
||||
|
||||
--------------------------------------------------
|
||||
-- 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
|
||||
--------------------------------------------------
|
||||
|
@ -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);
|
||||
|
292
src/tools/nlwav.c
Normal file
292
src/tools/nlwav.c
Normal file
@ -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)
|
||||
*/
|
Loading…
Reference in New Issue
Block a user