From 12a3abdb2837c18aab671c7e75ebd5d2fb1f775a Mon Sep 17 00:00:00 2001 From: couriersud Date: Tue, 5 May 2020 23:54:30 +0200 Subject: [PATCH] netlist: nlwav - new functionality. [Couriersud] nlwav now supports 16 and 32 bit integer format (wav16s, wav32s) as well as 32 bit float format (wav32f). The "wav" format is no longer supported. Added support for high and low pass filtering the wav output. Dynamic volume adjustment (use "-a 0") --hpboost can suppress spikes at the beginning of the file (<10ms) The addition of the float format simplifies debugging significantly since it covers the whole dynamic format. Added nlwav to the local VS 2019 build. --- src/lib/netlist/buildVS/netlist.sln | 17 +- .../netlist/buildVS/netlistlib.vcxproj.user | 4 - src/lib/netlist/buildVS/nlwav.vcxproj | 162 ++++++++++ src/lib/netlist/buildVS/nlwav.vcxproj.filters | 22 ++ src/lib/netlist/plib/poptions.h | 13 +- src/lib/netlist/prg/nltool.cpp | 7 +- src/lib/netlist/prg/nlwav.cpp | 290 ++++++++++++++---- 7 files changed, 440 insertions(+), 75 deletions(-) delete mode 100755 src/lib/netlist/buildVS/netlistlib.vcxproj.user create mode 100755 src/lib/netlist/buildVS/nlwav.vcxproj create mode 100755 src/lib/netlist/buildVS/nlwav.vcxproj.filters mode change 100644 => 100755 src/lib/netlist/prg/nlwav.cpp diff --git a/src/lib/netlist/buildVS/netlist.sln b/src/lib/netlist/buildVS/netlist.sln index a06f407d3c2..433d034cf6f 100755 --- a/src/lib/netlist/buildVS/netlist.sln +++ b/src/lib/netlist/buildVS/netlist.sln @@ -1,12 +1,14 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30011.22 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netlistlib", "netlistlib.vcxproj", "{A374399B-B87F-4E0F-9525-6C099600705F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nltool", "nltool.vcxproj", "{9204EC28-A29B-4A36-9E47-2C46041D67D3}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nlwav", "nlwav.vcxproj", "{48D0ADAF-62EC-472E-A51B-8D837280649D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -31,8 +33,19 @@ Global {9204EC28-A29B-4A36-9E47-2C46041D67D3}.Release|x64.Build.0 = Release|x64 {9204EC28-A29B-4A36-9E47-2C46041D67D3}.Release|x86.ActiveCfg = Release|Win32 {9204EC28-A29B-4A36-9E47-2C46041D67D3}.Release|x86.Build.0 = Release|Win32 + {48D0ADAF-62EC-472E-A51B-8D837280649D}.Debug|x64.ActiveCfg = Debug|x64 + {48D0ADAF-62EC-472E-A51B-8D837280649D}.Debug|x64.Build.0 = Debug|x64 + {48D0ADAF-62EC-472E-A51B-8D837280649D}.Debug|x86.ActiveCfg = Debug|Win32 + {48D0ADAF-62EC-472E-A51B-8D837280649D}.Debug|x86.Build.0 = Debug|Win32 + {48D0ADAF-62EC-472E-A51B-8D837280649D}.Release|x64.ActiveCfg = Release|x64 + {48D0ADAF-62EC-472E-A51B-8D837280649D}.Release|x64.Build.0 = Release|x64 + {48D0ADAF-62EC-472E-A51B-8D837280649D}.Release|x86.ActiveCfg = Release|Win32 + {48D0ADAF-62EC-472E-A51B-8D837280649D}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {992701A0-B9F5-4F7D-BF3F-5B0EBEA51F04} + EndGlobalSection EndGlobal diff --git a/src/lib/netlist/buildVS/netlistlib.vcxproj.user b/src/lib/netlist/buildVS/netlistlib.vcxproj.user deleted file mode 100755 index abe8dd8961e..00000000000 --- a/src/lib/netlist/buildVS/netlistlib.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/lib/netlist/buildVS/nlwav.vcxproj b/src/lib/netlist/buildVS/nlwav.vcxproj new file mode 100755 index 00000000000..7b191fedccd --- /dev/null +++ b/src/lib/netlist/buildVS/nlwav.vcxproj @@ -0,0 +1,162 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + {a374399b-b87f-4e0f-9525-6c099600705f} + + + + 16.0 + {48D0ADAF-62EC-472E-A51B-8D837280649D} + Win32Proj + nlwav + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + false + + + true + + + true + + + false + + + + + + Level3 + true + true + + + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)..\..\ + + + Console + true + true + true + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/src/lib/netlist/buildVS/nlwav.vcxproj.filters b/src/lib/netlist/buildVS/nlwav.vcxproj.filters new file mode 100755 index 00000000000..7b114761bb4 --- /dev/null +++ b/src/lib/netlist/buildVS/nlwav.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/src/lib/netlist/plib/poptions.h b/src/lib/netlist/plib/poptions.h index 3a807c3c7f0..2db0e7e9585 100755 --- a/src/lib/netlist/plib/poptions.h +++ b/src/lib/netlist/plib/poptions.h @@ -12,6 +12,7 @@ #include "pstonum.h" #include "pstring.h" #include "putil.h" +#include "pfmtlog.h" namespace plib { @@ -27,7 +28,7 @@ namespace plib { PCOPYASSIGNMOVE(option_base, delete) - pstring help() const { return m_help; } + virtual pstring help() const { return m_help; } private: pstring m_help; }; @@ -169,16 +170,23 @@ namespace plib { public: option_num(options &parent, const pstring &ashort, const pstring &along, T defval, const pstring &help, - T minval = std::numeric_limits::min(), + T minval = std::numeric_limits::lowest(), T maxval = std::numeric_limits::max() ) : option(parent, ashort, along, help, true) , m_val(defval) , m_min(minval) , m_max(maxval) + , m_def(defval) {} T operator ()() const { return m_val; } + pstring help() const override + { + auto hs(option::help()); + return plib::pfmt(hs)(m_def, m_min, m_max); + } + protected: int parse(const pstring &argument) override { @@ -191,6 +199,7 @@ namespace plib { T m_val; T m_min; T m_max; + T m_def; }; class option_vec : public option diff --git a/src/lib/netlist/prg/nltool.cpp b/src/lib/netlist/prg/nltool.cpp index ca05dc689b7..f2d18092629 100644 --- a/src/lib/netlist/prg/nltool.cpp +++ b/src/lib/netlist/prg/nltool.cpp @@ -1195,14 +1195,9 @@ int tool_app_t::execute() return 1; } } - catch (netlist::nl_exception &e) - { - perr("Netlist exception caught: {}\n", e.text()); - return 2; - } catch (plib::pexception &e) { - perr("plib exception caught: {}\n", e.text()); + perr("Exception caught: {}\n", e.text()); return 2; } diff --git a/src/lib/netlist/prg/nlwav.cpp b/src/lib/netlist/prg/nlwav.cpp old mode 100644 new mode 100755 index 0606c583e07..a444e2f9ef9 --- a/src/lib/netlist/prg/nlwav.cpp +++ b/src/lib/netlist/prg/nlwav.cpp @@ -1,14 +1,21 @@ // license:GPL-2.0+ // copyright-holders:Couriersud -#include "plib/pstring.h" +#include "netlist/plib/pstring.h" #include "netlist/nl_setup.h" -#include "plib/plists.h" -#include "plib/pmain.h" -#include "plib/ppmf.h" -#include "plib/pstream.h" +#include "netlist/plib/plists.h" +#include "netlist/plib/pmain.h" +#include "netlist/plib/ppmf.h" +#include "netlist/plib/pstream.h" #include +// see below - this belongs somewhere else! +#ifdef _WIN32 +#include +#include +#include +#endif + // From: https://ffmpeg.org/pipermail/ffmpeg-devel/2007-October/038122.html // The most compatible way to make a wav header for unknown length is to put // 0xffffffff in the header. 0 as the RIFF length and 0 as the data chunk length @@ -24,12 +31,20 @@ class wav_t { public: - // XXNOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) - wav_t(std::ostream &strm, bool is_seekable, std::size_t sr, std::size_t channels) + + enum format + { + s16, + s32, + f32 + }; + + wav_t(std::ostream &strm, bool is_seekable, format fmt, std::size_t sr, std::size_t channels) : m_f(strm) , m_stream_is_seekable(is_seekable) + , m_format(fmt) // force "play" to play and warn about eof instead of being silent - , m_fmt(static_cast(channels), static_cast(sr)) + , m_fmt(static_cast(channels), static_cast(sr), fmt) , m_data(is_seekable ? 0 : 0xffffffff) { @@ -60,17 +75,43 @@ public: template void write(const T &val) { + static_assert(sizeof(std::ostream::char_type) == 1, "char_type size must be 1"); auto ptr(reinterpret_cast(&val)); m_f.write(ptr, sizeof(T)); } - void write_sample(const int *sample) + template + void write_sample_int(double sample) + { + const auto mmax(static_cast(plib::numeric_limits::max())); + const auto mmin(static_cast(plib::numeric_limits::min())); + + sample *= mmax; + sample = std::max(mmin, sample); + sample = std::min(mmax, sample); + const auto dest(static_cast(sample)); + write(dest); + } + + // expects normalized samples between -1.0 to 1.0 for s16 and s32 + void write_samples(double *sample) { m_data.len += m_fmt.block_align; for (std::size_t i = 0; i < channels(); i++) { - auto ps = static_cast(sample[i]); // 16 bit sample, FIXME: Endianess? - write(ps); + switch (m_format) + { + case s16: + write_sample_int(sample[i]); + break; + case s32: + write_sample_int(sample[i]); + break; + case f32: + const auto df32(static_cast(sample[i])); + write(df32); + break; + } } } @@ -84,8 +125,23 @@ private: struct riff_format_t { - riff_format_t(uint16_t achannels, uint32_t asample_rate) + riff_format_t(uint16_t achannels, uint32_t asample_rate, format fm) { + switch (fm) + { + case s16: + format_tag = 0x0001; // PCM + bits_sample = 16; + break; + case s32: + format_tag = 0x0001; // PCM + bits_sample = 32; + break; + case f32: + format_tag = 0x0003; // FLOAT + bits_sample = 32; + break; + } channels = achannels; sample_rate = asample_rate; block_align = channels * ((bits_sample + 7) / 8); @@ -93,12 +149,12 @@ private: } std::array signature = {{'f','m','t',' '}}; uint32_t fmt_length = 16; - uint16_t format_tag = 0x0001; // PCM + uint16_t format_tag; uint16_t channels; uint32_t sample_rate; uint32_t bytes_per_second; uint16_t block_align; - uint16_t bits_sample = 16; + uint16_t bits_sample; }; struct riff_data_t @@ -111,6 +167,7 @@ private: std::ostream &m_f; bool m_stream_is_seekable; + format m_format; riff_chunk_t m_fh; riff_format_t m_fmt; @@ -240,52 +297,130 @@ private: std::vector cursam; }; +struct filter_hp +{ + using callback_type = plib::pmfp; + + filter_hp(double freq, bool boost, std::size_t channels, callback_type cb) + : m_channels(channels) + , m_cb(cb) + , m_hp_omega(plib::constants::two() * plib::constants::pi() * freq) + , m_boost(boost) + , m_lt(channels, 0.0) + , m_in(channels, 0.0) + , m_cap(channels, 0.0) + { } + void process(std::size_t chan, double time, double val) + { + // based on CR filter + auto dt(time - m_lt[chan]); + + double omega = ((m_boost && (time < 1.0/m_hp_omega)) ? 1e12 : m_hp_omega); + auto m(1.0 - plib::exp(-dt * omega)); + m_cap[chan] += m * (m_in[chan] - m_cap[chan]); + // out = in - vcap + m_cb(chan, time, m_in[chan] - m_cap[chan]); + + m_in[chan] = val; + m_lt[chan] = time; + } + +private: + std::size_t m_channels; + callback_type m_cb; + double m_hp_omega; + bool m_boost; + std::vector m_lt; + std::vector m_in; + std::vector m_cap; +}; + +struct filter_lp +{ + using callback_type = plib::pmfp; + + filter_lp(double freq, std::size_t channels, callback_type cb) + : m_channels(channels) + , m_cb(cb) + , m_lp_omega(plib::constants::two() * plib::constants::pi() * freq) + , m_lt(channels, 0.0) + , m_in(channels, 0.0) // lp filter + , m_cap(channels, 0.0) // hp filter + { } + void process(std::size_t chan, double time, double val) + { + // based on RC filter + auto dt(time - m_lt[chan]); + + auto m(1.0 - plib::exp(-dt * m_lp_omega)); + + m_cap[chan] += m * (m_in[chan] - m_cap[chan]); + // out = vcap + m_cb(chan, time, m_cap[chan]); + + m_in[chan] = val; + m_lt[chan] = time; + } + +private: + std::size_t m_channels; + callback_type m_cb; + double m_lp_omega; + std::vector m_lt; + std::vector m_in; + std::vector m_cap; +}; + class wavwriter { public: - wavwriter(std::ostream &fo, bool is_seekable, std::size_t channels, std::size_t sample_rate, double ampa) - : mean(channels, 0.0) - , means(channels, 0.0) - , maxsam(channels, -1e9) + wavwriter(std::ostream &fo, bool is_seekable, wav_t::format fmt, + std::size_t channels, std::size_t sample_rate, double ampa) + : maxsam(channels, -1e9) , minsam(channels, 1e9) , m_n(channels, 0) , m_samples(channels, 0) , m_last_time(0) , m_fo(fo) - , m_amp(ampa) - , m_wo(m_fo, is_seekable, sample_rate, channels) + , m_amp(ampa <= 0.0 ? 1.0e6 : ampa) + , m_auto(ampa <= 0.0) + , m_wo(m_fo, is_seekable, fmt, sample_rate, channels) { } void process(std::size_t chan, double time, double outsam) { if (time > m_last_time) - m_wo.write_sample(m_samples.data()); + m_wo.write_samples(m_samples.data()); m_last_time = time; - means[chan] += outsam; maxsam[chan] = std::max(maxsam[chan], outsam); minsam[chan] = std::min(minsam[chan], outsam); m_n[chan]++; - //mean = means / (double) m_n; - mean[chan] += 5.0 / static_cast(m_wo.sample_rate()) * (outsam - mean[chan]); - outsam = (outsam - mean[chan]) * m_amp; - outsam = std::max(-32000.0, outsam); - outsam = std::min(32000.0, outsam); - m_samples[chan] = static_cast(outsam); + auto val(outsam * m_amp); + if (m_auto && plib::abs(val) > 1.0) + { + do + { + m_amp /= 2.0; + val = outsam * m_amp; + } while (plib::abs(val) > 1.0); + // FIXME: log this in state and provide on verbose output + //printf("dynamp adjusted to %f at %f\n", m_amp, time); + } + m_samples[chan] = val; } - std::vector mean; - std::vector means; std::vector maxsam; std::vector minsam; std::vector m_n; - std::vector m_samples; + std::vector m_samples; double m_last_time; private: std::ostream &m_fo; double m_amp; + bool m_auto; wav_t m_wo; }; @@ -441,18 +576,23 @@ class nlwav_app : public plib::app public: nlwav_app() : plib::app(), - opt_fmt(*this, "f", "format", 0, std::vector({"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" + opt_fmt(*this, "f", "format", 0, std::vector({"wav16s","wav32s","wav32f","vcda","vcdd", "tab"}), + "output format. Available options are wav16s|wav32s|wav32f|vcda|vcdd|tab.\n" + " wav16s : multichannel wav output 16 bit signed\n" + " wav32s : multichannel wav output 32 bit signed\n" + " wav32f : multichannel wav output 32 bit float\n" + " vcda : analog VCD output\n" + " vcdd : digital VCD output\n" + " tab : sampled output\n" " 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"), + opt_lowpass(*this, "", "lowpass", 20000.0, "lowpass filter frequency.\nDefault {1:.0} Hz."), + opt_highpass(*this, "", "highpass", 20.0, "highpass filter frequency.\nDefault is {1:.0} Hz."), + opt_hpboost(*this, "", "hpboost", "enable highpass boost to filter out initial click."), 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"), @@ -468,8 +608,8 @@ public: 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"), + opt_ex2(*this, "./nlwav -f wav16s -o x.wav log_V*", + "convert all files starting with \"log_V\" into a multichannel wav file (16bit, signed)"), 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.") @@ -479,7 +619,7 @@ public: pstring usage() override; private: - void convert_wav(std::ostream &ostrm); + void convert_wav(std::ostream &ostrm, wav_t::format fmt); void convert_vcd(std::ostream &ostrm, vcdwriter::format_e format); void convert_tab(std::ostream &ostrm); void convert(const pstring &outname); @@ -489,6 +629,9 @@ private: plib::option_group opt_grp1; plib::option_num opt_rate; plib::option_num opt_amp; + plib::option_num opt_lowpass; + plib::option_num opt_highpass; + plib::option_bool opt_hpboost; plib::option_group opt_grp2; plib::option_num opt_high; plib::option_num opt_low; @@ -509,16 +652,20 @@ private: std::vector> m_instrms; }; -void nlwav_app::convert_wav(std::ostream &ostrm) +void nlwav_app::convert_wav(std::ostream &ostrm, wav_t::format fmt) { double dt = plib::reciprocal(static_cast(opt_rate())); + auto nchan = m_instrms.size(); - plib::unique_ptr wo = plib::make_unique(ostrm, opt_out() != "-", m_instrms.size(), opt_rate(), opt_amp()); - plib::unique_ptr ago = plib::make_unique(m_instrms.size(), dt, aggregator::callback_type(&wavwriter::process, wo.get())); - aggregator::callback_type agcb = log_processor::callback_type(&aggregator::process, ago.get()); + auto wo = plib::make_unique(ostrm, opt_out() != "-", fmt, nchan, opt_rate(), opt_amp()); + auto ago = plib::make_unique(nchan, dt, aggregator::callback_type(&wavwriter::process, wo.get())); + auto fgo_hp = plib::make_unique(opt_highpass(), opt_hpboost(), nchan, filter_hp::callback_type(&aggregator::process, ago.get())); + auto fgo_lp = plib::make_unique(opt_lowpass(), nchan, filter_lp::callback_type(&filter_hp::process, fgo_hp.get())); - log_processor lp(m_instrms.size(), agcb); + auto topcb = log_processor::callback_type(&filter_lp::process, fgo_lp.get()); + + log_processor lp(nchan, topcb); lp.process(m_instrms); @@ -591,6 +738,10 @@ static void open_ostream_and_exec(pstring fname, bool binary, F func) else { std::cout.imbue(std::locale::classic()); + // FIXME: switch to binary on windows +#ifdef _WIN32 + _setmode(_fileno(stdout), _O_BINARY); +#endif func(std::cout); } } @@ -600,15 +751,21 @@ void nlwav_app::convert(const pstring &outname) switch (opt_fmt()) { case 0: - open_ostream_and_exec(outname, true, [this](std::ostream &ostrm) { convert_wav(ostrm); }); + open_ostream_and_exec(outname, true, [this](std::ostream &ostrm) { convert_wav(ostrm, wav_t::s16); }); break; case 1: - open_ostream_and_exec(outname, false, [this](std::ostream &ostrm) { convert_vcd(ostrm, vcdwriter::ANALOG); }); + open_ostream_and_exec(outname, true, [this](std::ostream &ostrm) { convert_wav(ostrm, wav_t::s32); }); break; case 2: - open_ostream_and_exec(outname, false, [this](std::ostream &ostrm) { convert_vcd(ostrm, vcdwriter::DIGITAL); }); + open_ostream_and_exec(outname, true, [this](std::ostream &ostrm) { convert_wav(ostrm, wav_t::f32); }); break; case 3: + open_ostream_and_exec(outname, false, [this](std::ostream &ostrm) { convert_vcd(ostrm, vcdwriter::ANALOG); }); + break; + case 4: + open_ostream_and_exec(outname, false, [this](std::ostream &ostrm) { convert_vcd(ostrm, vcdwriter::DIGITAL); }); + break; + case 5: open_ostream_and_exec(outname, false, [this](std::ostream &ostrm) { convert_tab(ostrm); }); break; default: @@ -637,23 +794,34 @@ int nlwav_app::execute() return 0; } - for (const auto &oi: opt_args()) + try { - plib::unique_ptr fin; - if (oi == "-") + for (const auto &oi: opt_args()) { - auto temp(plib::make_unique()); - plib::copystream(*temp, std::cin); - fin = std::move(temp); + plib::unique_ptr fin; + if (oi == "-") + { + auto temp(plib::make_unique()); + plib::copystream(*temp, std::cin); + fin = std::move(temp); + } + else + { + fin = plib::make_unique(plib::filesystem::u8path(oi), std::ios::in); + if (fin->fail()) + throw plib::file_open_e(oi); + } + fin->imbue(std::locale::classic()); + m_instrms.push_back(std::move(fin)); } - else - fin = plib::make_unique(plib::filesystem::u8path(oi)); - fin->imbue(std::locale::classic()); - m_instrms.push_back(std::move(fin)); + + convert(opt_out()); + } + catch (plib::pexception &e) + { + perr("Exception caught: {}\n", e.text()); + return 1; } - - convert(opt_out()); - return 0; }