mirror of
https://github.com/holub/mame
synced 2025-05-31 18:11:50 +03:00
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.
This commit is contained in:
parent
0044c33b61
commit
12a3abdb28
@ -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
|
||||
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
162
src/lib/netlist/buildVS/nlwav.vcxproj
Executable file
162
src/lib/netlist/buildVS/nlwav.vcxproj
Executable file
@ -0,0 +1,162 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\prg\nlwav.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="netlistlib.vcxproj">
|
||||
<Project>{a374399b-b87f-4e0f-9525-6c099600705f}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{48D0ADAF-62EC-472E-A51B-8D837280649D}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>nlwav</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)..\..\</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
22
src/lib/netlist/buildVS/nlwav.vcxproj.filters
Executable file
22
src/lib/netlist/buildVS/nlwav.vcxproj.filters
Executable file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\prg\nlwav.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -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<T>::min(),
|
||||
T minval = std::numeric_limits<T>::lowest(),
|
||||
T maxval = std::numeric_limits<T>::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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
290
src/lib/netlist/prg/nlwav.cpp
Normal file → Executable file
290
src/lib/netlist/prg/nlwav.cpp
Normal file → Executable file
@ -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 <cstdio>
|
||||
|
||||
// see below - this belongs somewhere else!
|
||||
#ifdef _WIN32
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#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<std::uint16_t>(channels), static_cast<std::uint32_t>(sr))
|
||||
, m_fmt(static_cast<std::uint16_t>(channels), static_cast<std::uint32_t>(sr), fmt)
|
||||
, m_data(is_seekable ? 0 : 0xffffffff)
|
||||
{
|
||||
|
||||
@ -60,17 +75,43 @@ public:
|
||||
template <typename T>
|
||||
void write(const T &val)
|
||||
{
|
||||
static_assert(sizeof(std::ostream::char_type) == 1, "char_type size must be 1");
|
||||
auto ptr(reinterpret_cast<const std::ostream::char_type *>(&val));
|
||||
m_f.write(ptr, sizeof(T));
|
||||
}
|
||||
|
||||
void write_sample(const int *sample)
|
||||
template <typename T>
|
||||
void write_sample_int(double sample)
|
||||
{
|
||||
const auto mmax(static_cast<double>(plib::numeric_limits<T>::max()));
|
||||
const auto mmin(static_cast<double>(plib::numeric_limits<T>::min()));
|
||||
|
||||
sample *= mmax;
|
||||
sample = std::max(mmin, sample);
|
||||
sample = std::min(mmax, sample);
|
||||
const auto dest(static_cast<T>(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<int16_t>(sample[i]); // 16 bit sample, FIXME: Endianess?
|
||||
write(ps);
|
||||
switch (m_format)
|
||||
{
|
||||
case s16:
|
||||
write_sample_int<int16_t>(sample[i]);
|
||||
break;
|
||||
case s32:
|
||||
write_sample_int<int32_t>(sample[i]);
|
||||
break;
|
||||
case f32:
|
||||
const auto df32(static_cast<float>(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<uint8_t, 4> 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<double> cursam;
|
||||
};
|
||||
|
||||
struct filter_hp
|
||||
{
|
||||
using callback_type = plib::pmfp<void, std::size_t, double, double>;
|
||||
|
||||
filter_hp(double freq, bool boost, std::size_t channels, callback_type cb)
|
||||
: m_channels(channels)
|
||||
, m_cb(cb)
|
||||
, m_hp_omega(plib::constants<double>::two() * plib::constants<double>::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<double> m_lt;
|
||||
std::vector<double> m_in;
|
||||
std::vector<double> m_cap;
|
||||
};
|
||||
|
||||
struct filter_lp
|
||||
{
|
||||
using callback_type = plib::pmfp<void, std::size_t, double, double>;
|
||||
|
||||
filter_lp(double freq, std::size_t channels, callback_type cb)
|
||||
: m_channels(channels)
|
||||
, m_cb(cb)
|
||||
, m_lp_omega(plib::constants<double>::two() * plib::constants<double>::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<double> m_lt;
|
||||
std::vector<double> m_in;
|
||||
std::vector<double> 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<double>(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<int>(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<double> mean;
|
||||
std::vector<double> means;
|
||||
std::vector<double> maxsam;
|
||||
std::vector<double> minsam;
|
||||
std::vector<std::size_t> m_n;
|
||||
std::vector<int> m_samples;
|
||||
std::vector<double> 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<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"
|
||||
opt_fmt(*this, "f", "format", 0, std::vector<pstring>({"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<std::size_t> opt_rate;
|
||||
plib::option_num<double> opt_amp;
|
||||
plib::option_num<double> opt_lowpass;
|
||||
plib::option_num<double> opt_highpass;
|
||||
plib::option_bool opt_hpboost;
|
||||
plib::option_group opt_grp2;
|
||||
plib::option_num<double> opt_high;
|
||||
plib::option_num<double> opt_low;
|
||||
@ -509,16 +652,20 @@ private:
|
||||
std::vector<plib::unique_ptr<std::istream>> 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<double>(opt_rate()));
|
||||
auto nchan = m_instrms.size();
|
||||
|
||||
plib::unique_ptr<wavwriter> wo = plib::make_unique<wavwriter>(ostrm, opt_out() != "-", m_instrms.size(), opt_rate(), opt_amp());
|
||||
plib::unique_ptr<aggregator> ago = plib::make_unique<aggregator>(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<wavwriter>(ostrm, opt_out() != "-", fmt, nchan, opt_rate(), opt_amp());
|
||||
auto ago = plib::make_unique<aggregator>(nchan, dt, aggregator::callback_type(&wavwriter::process, wo.get()));
|
||||
auto fgo_hp = plib::make_unique<filter_hp>(opt_highpass(), opt_hpboost(), nchan, filter_hp::callback_type(&aggregator::process, ago.get()));
|
||||
auto fgo_lp = plib::make_unique<filter_lp>(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<std::istream> fin;
|
||||
if (oi == "-")
|
||||
for (const auto &oi: opt_args())
|
||||
{
|
||||
auto temp(plib::make_unique<std::stringstream>());
|
||||
plib::copystream(*temp, std::cin);
|
||||
fin = std::move(temp);
|
||||
plib::unique_ptr<std::istream> fin;
|
||||
if (oi == "-")
|
||||
{
|
||||
auto temp(plib::make_unique<std::stringstream>());
|
||||
plib::copystream(*temp, std::cin);
|
||||
fin = std::move(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
fin = plib::make_unique<std::ifstream>(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<std::ifstream>(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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user