Freeverb3 VST plugins
Revision | 667d56e94dad133f339085b3590578c02406ef0c (tree) |
---|---|
Time | 2018-05-13 20:57:31 |
Author | Teru Kamogashira <tkamogashira@user...> |
Commiter | Teru Kamogashira |
Updated to freeverb3-3.2.1.
@@ -0,0 +1,35 @@ | ||
1 | +ACLOCAL_AMFLAGS = -I m4 --install | |
2 | +SUBDIRS = libsamplerate2 libsndfile libgdither freeverb VST VSTGUI Res VstMain src m4 | |
3 | + | |
4 | +EXTRA_DIST = autogen.sh \ | |
5 | +cross-sh/mingw-cross-S-sse.sh cross-sh/mingw-cross-sse3.sh cross-sh/mingw-cross-S-avx.sh \ | |
6 | +cross-sh/mingw-cross-D-sse2.sh cross-sh/mingw-cross-D-sse4.sh cross-sh/mingw-cross-D-avx.sh \ | |
7 | +cross-sh/mingw-w64-cross-sse.sh cross-sh/mingw-w64-cross-D-sse2.sh cross-sh/mingw-w64-cross-avx.sh cross-sh/mingw-w64-cross-D-avx.sh \ | |
8 | +cross-sh/build_fftw.sh cross-sh/build_libs.sh cross-sh/build_oggs.sh cross-sh/cross-set.sh \ | |
9 | +cross-sh/macosx-S-universal.sh | |
10 | + | |
11 | +vstinidir = $(libdir) | |
12 | +vstini_DATA = freeverb3cfg.xml freeverb3prg.xml | |
13 | + | |
14 | +vstdocumentdir = $(prefix) | |
15 | +vstdocument_DATA = VSTGUI-LICENSE.txt VST-LICENSE.rtf README.txt AUTHORS.txt | |
16 | + | |
17 | +m4datadir = $(datadir)/aclocal | |
18 | + | |
19 | +# dist-hook: CL | |
20 | + | |
21 | +# CL: | |
22 | +# cvs2cl.pl --show-dead --no-times --tags --branches --revisions | |
23 | + | |
24 | +PACKAGENAME = freeverb3_vst$(cv_dstr)-$(RELEASE).$(MAJOR).$(MINOR).zip | |
25 | + | |
26 | +vstdist: install-strip | |
27 | + rm -f $(DESTDIR)$(libdir)/*.la $(DESTDIR)$(libdir)/*.a | |
28 | + rm -f $(DESTDIR)/$(PACKAGENAME) | |
29 | + (if [ "$(DESTDIR)" != "" ]; then cd $(DESTDIR); else cd / ; fi ; zip -9r $(PACKAGENAME) `echo $(prefix)|sed -e s/^\\\\///g`) | |
30 | + | |
31 | +DEPLIBNAME = freeverb3_vst-dev-deplib-win-$(RELEASE).$(MAJOR).$(MINOR).zip | |
32 | +deplib: | |
33 | + zip -9r $(DEPLIBNAME) include lib32 lib64 | |
34 | + | |
35 | + |
@@ -965,7 +965,7 @@ | ||
965 | 965 | for(int si = 0;si < MODEL_SLOT_SIZE;si ++) |
966 | 966 | { |
967 | 967 | // add to outputL/R (skip init) |
968 | - if(model[si][0]->getSampleSize() == 0||muteWet[si][0] == true) | |
968 | + if(model[si][0]->getImpulseSize() == 0||muteWet[si][0] == true) | |
969 | 969 | continue; |
970 | 970 | unsigned slotoption = FV3_IR_SKIP_INIT|FV3_IR_MUTE_DRY; |
971 | 971 | if(getParameter(KRTParam(si,KWet)) == 0.0f) |
@@ -1294,7 +1294,7 @@ | ||
1294 | 1294 | targetSlot->setFragmentSize(conf_fragmentSize, conf_factor); |
1295 | 1295 | targetSlot->loadImpulse(L, R, size); |
1296 | 1296 | writeLogA("Impulser2: loadToModel: %ld -> %ld / %ld x %ld / %ld x %ld\n", |
1297 | - size, targetSlot->getSampleSize(), | |
1297 | + size, targetSlot->getImpulseSize(), | |
1298 | 1298 | targetSlot->getSFragmentSize(), targetSlot->getSFragmentCount(), |
1299 | 1299 | targetSlot->getLFragmentSize(), targetSlot->getLFragmentCount()); |
1300 | 1300 | } |
@@ -0,0 +1,43 @@ | ||
1 | +/** | |
2 | + * Mac dependent codes | |
3 | + * | |
4 | + * Copyright (C) 2006-2014 Teru Kamogashira | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify | |
7 | + * it under the terms of the GNU General Public License as published by | |
8 | + * the Free Software Foundation; either version 2 of the License, or | |
9 | + * (at your option) any later version. | |
10 | + * | |
11 | + * This program is distributed in the hope that it will be useful, | |
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | + * GNU General Public License for more details. | |
15 | + * | |
16 | + * You should have received a copy of the GNU General Public License | |
17 | + * along with this program; if not, write to the Free Software | |
18 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
19 | + */ | |
20 | + | |
21 | +#import <Foundation/Foundation.h> | |
22 | +#import <Cocoa/Cocoa.h> | |
23 | + | |
24 | +#import "Mac.h" | |
25 | + | |
26 | +#ifdef MAC | |
27 | +void MacMessageBox(char * title, char * string) | |
28 | +{ | |
29 | + NSString * info = [[NSString alloc] initWithFormat:@"%s", title]; | |
30 | + NSString * text = [[NSString alloc] initWithFormat:@"%s", string]; | |
31 | + NSAlert* alert =[NSAlert alertWithMessageText:text | |
32 | + defaultButton:@"OK" alternateButton:nil otherButton:nil | |
33 | + informativeTextWithFormat:info]; | |
34 | + [alert runModal]; | |
35 | +} | |
36 | + | |
37 | +void getHomeDirectoryName(char * str) | |
38 | +{ | |
39 | + char path[PATH_MAX]; | |
40 | + CFStringGetCString((CFStringRef)NSHomeDirectory(), path, sizeof(path), kCFStringEncodingUTF8); | |
41 | + memcpy(str, path, PATH_MAX); | |
42 | +} | |
43 | +#endif |
@@ -13,6 +13,7 @@ | ||
13 | 13 | slot.cpp slot_t.hpp slot.hpp \ |
14 | 14 | utils.cpp utils_t.hpp utils.hpp \ |
15 | 15 | irbase.hpp irbase_t.hpp irbase.cpp \ |
16 | + irmodel1.cpp irmodel1.hpp irmodel1_t.hpp \ | |
16 | 17 | irmodel2.cpp irmodel2.hpp irmodel2_t.hpp \ |
17 | 18 | irmodel2zl.cpp irmodel2zl.hpp irmodel2zl_t.hpp \ |
18 | 19 | irmodel3.cpp irmodel3.hpp irmodel3_t.hpp \ |
@@ -278,6 +279,9 @@ | ||
278 | 279 | irbase.hpp \ |
279 | 280 | irbase_t.hpp \ |
280 | 281 | irbase.cpp \ |
282 | + irmodel1.cpp \ | |
283 | + irmodel1.hpp \ | |
284 | + irmodel1_t.hpp \ | |
281 | 285 | irmodel2.cpp \ |
282 | 286 | irmodel2.hpp \ |
283 | 287 | irmodel2_t.hpp \ |
@@ -0,0 +1,96 @@ | ||
1 | +/** | |
2 | + * CArg arg table | |
3 | + * | |
4 | + * Copyright (C) 2007-2014 Teru Kamogashira | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify | |
7 | + * it under the terms of the GNU General Public License as published by | |
8 | + * the Free Software Foundation; either version 2 of the License, or | |
9 | + * (at your option) any later version. | |
10 | + * | |
11 | + * This program is distributed in the hope that it will be useful, | |
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | + * GNU General Public License for more details. | |
15 | + * | |
16 | + * You should have received a copy of the GNU General Public License | |
17 | + * along with this program; if not, write to the Free Software | |
18 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
19 | + */ | |
20 | + | |
21 | +#include "CArg.hpp" | |
22 | + | |
23 | +CArg::CArg() | |
24 | +{ | |
25 | + blank[0] = '\0'; | |
26 | +} | |
27 | + | |
28 | +int CArg::registerArg(int argc, char ** argv) | |
29 | +{ | |
30 | + for(int i = 1;i < argc;i ++) | |
31 | + { | |
32 | + if(strlen(argv[i]) > 1&&strncmp(argv[i], "-", 1) == 0) | |
33 | + { | |
34 | + std::string option, value; | |
35 | + std::pair<std::map<std::string,std::string>::iterator,bool> result; | |
36 | + if(i + 1 >= argc) | |
37 | + { | |
38 | + std::cerr << "CArg::registerArg: Missing value to [" | |
39 | + << argv[i] << "].\n" << std::endl; | |
40 | + return -1; | |
41 | + } | |
42 | + option = argv[i]; | |
43 | + i ++; | |
44 | + value = argv[i]; | |
45 | + result = | |
46 | + optionMap.insert(std::pair<std::string,std::string>(option,value)); | |
47 | + if(!result.second) | |
48 | + { | |
49 | + optionMap[option] = value; | |
50 | + std::cerr << "CArg::registerArg: Value to [" | |
51 | + << option << "] was overwritten.\n" << std::endl; | |
52 | + } | |
53 | + } | |
54 | + else | |
55 | + { | |
56 | + argVector.push_back(argv[i]); | |
57 | + } | |
58 | + } | |
59 | + return 0; | |
60 | +} | |
61 | + | |
62 | +int CArg::getInt(const char * key) | |
63 | +{ | |
64 | + return std::atol(getString(key)); | |
65 | +} | |
66 | + | |
67 | +long CArg::getLong(const char * key) | |
68 | +{ | |
69 | + return std::atol(getString(key)); | |
70 | +} | |
71 | + | |
72 | +double CArg::getDouble(const char * key) | |
73 | +{ | |
74 | + return std::atof(getString(key)); | |
75 | +} | |
76 | + | |
77 | +const char * CArg::getString(const char * key) | |
78 | +{ | |
79 | + std::string keyString = key; | |
80 | + std::map<std::string,std::string>::iterator result; | |
81 | + result = optionMap.find(keyString); | |
82 | + if(result != optionMap.end()) | |
83 | + { | |
84 | + return result->second.c_str(); | |
85 | + } | |
86 | + return blank; | |
87 | +} | |
88 | + | |
89 | +const char * CArg::getFileArg(unsigned at) | |
90 | +{ | |
91 | + if(argVector.size() > at) | |
92 | + { | |
93 | + return argVector[at].c_str(); | |
94 | + } | |
95 | + return blank; | |
96 | +} |
@@ -0,0 +1,47 @@ | ||
1 | +/** | |
2 | + * CArg arg table | |
3 | + * | |
4 | + * Copyright (C) 2007-2014 Teru Kamogashira | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify | |
7 | + * it under the terms of the GNU General Public License as published by | |
8 | + * the Free Software Foundation; either version 2 of the License, or | |
9 | + * (at your option) any later version. | |
10 | + * | |
11 | + * This program is distributed in the hope that it will be useful, | |
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | + * GNU General Public License for more details. | |
15 | + * | |
16 | + * You should have received a copy of the GNU General Public License | |
17 | + * along with this program; if not, write to the Free Software | |
18 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
19 | + */ | |
20 | + | |
21 | +#ifndef __CArg_HPP | |
22 | +#define __CArg_HPP | |
23 | + | |
24 | +#include <cstdlib> | |
25 | +#include <cstring> | |
26 | +#include <iostream> | |
27 | +#include <string> | |
28 | +#include <vector> | |
29 | +#include <map> | |
30 | + | |
31 | +class CArg | |
32 | +{ | |
33 | +public: | |
34 | + CArg(); | |
35 | + int registerArg(int argc, char ** argv); | |
36 | + const char * getString(const char * key); | |
37 | + int getInt(const char * key); | |
38 | + long getLong(const char * key); | |
39 | + double getDouble(const char * key); | |
40 | + const char * getFileArg(unsigned at); | |
41 | +private: | |
42 | + char blank[1]; | |
43 | + std::map<std::string,std::string> optionMap; | |
44 | + std::vector<std::string> argVector; | |
45 | +}; | |
46 | + | |
47 | +#endif |
@@ -0,0 +1,69 @@ | ||
1 | +if TARGET_WINDOWS | |
2 | +bin_PROGRAMS = fv3_rateconv | |
3 | +endif | |
4 | + | |
5 | +INCLUDES = -I$(top_srcdir)/freeverb -I$(top_srcdir)/libsndfile -I$(top_srcdir)/libgdither -I$(top_srcdir)/include -I$(top_srcdir) | |
6 | + | |
7 | +if BUILD_PLUGDOUBLE | |
8 | +INCLUDES += -DPLUGDOUBLE | |
9 | +endif | |
10 | + | |
11 | +EXEFLAGS = -static -static-libgcc -static-libstdc++ -Wl,-O1 -Wl,--as-needed -Wl,--sort-common \ | |
12 | + -Wl,-lm -Wl,-lstdc++ -Wl,-lgcc -Wl,-lgcc_eh -Wl,-lkernel32 | |
13 | + | |
14 | +IMP_LIB = | |
15 | + | |
16 | +if BUILD_X64 | |
17 | +IMP_LIB += -L$(top_srcdir)/lib64 | |
18 | +else | |
19 | +IMP_LIB += -L$(top_srcdir)/lib32 | |
20 | +endif | |
21 | + | |
22 | +if DEFAULT_FFTW3N | |
23 | +if BUILD_PLUGDOUBLE | |
24 | +IMP_LIB += -lfftw3 | |
25 | +else | |
26 | +IMP_LIB += -lfftw3f | |
27 | +endif | |
28 | +else | |
29 | +IMP_LIB += -l$(cv_fftw3n) | |
30 | +endif | |
31 | + | |
32 | +if DEFAULT_LIBFLACN | |
33 | +IMP_LIB += -lFLAC -lws2_32 | |
34 | +else | |
35 | +IMP_LIB += -l$(cv_libflacn) | |
36 | +endif | |
37 | + | |
38 | +if DEFAULT_LIBVORBISN | |
39 | +IMP_LIB += -lvorbis -lvorbisfile -lvorbisenc | |
40 | +else | |
41 | +IMP_LIB += -lvorbis$(cv_libvorbisn) -lvorbisfile$(cv_libvorbisn) -lvorbisenc$(cv_libvorbisn) | |
42 | +endif | |
43 | + | |
44 | +if DEFAULT_LIBOGGN | |
45 | +IMP_LIB += -logg | |
46 | +else | |
47 | +IMP_LIB += -l$(cv_liboggn) | |
48 | +endif | |
49 | + | |
50 | +mingwdlldir = $(bindir) | |
51 | + | |
52 | +if INCLUDE_MINGW_RUNTIME | |
53 | +if BUILD_X64 | |
54 | +mingwdll_DATA = 64/libstdc++-6.dll 64/libgcc_s_sjlj-1.dll | |
55 | +else | |
56 | +mingwdll_DATA = 32/mingwm10.dll 32/libstdc++-6.dll 32/libgcc_s_sjlj-1.dll | |
57 | +endif | |
58 | +else | |
59 | +mingwdll_DATA = | |
60 | +endif | |
61 | + | |
62 | +if BUILD_PROFILE_GENERATE | |
63 | +EXEFLAGS += -Wl,-lgcov -fprofile-generate -ftest-coverage -fprofile-arcs | |
64 | +endif | |
65 | + | |
66 | +fv3_rateconv_LDADD = $(top_srcdir)/freeverb/libir.la $(top_srcdir)/libsndfile/libsndfile.la $(top_srcdir)/libgdither/libgdither.la $(IMP_LIB) | |
67 | +fv3_rateconv_LDFLAGS = $(EXEFLAGS) | |
68 | +fv3_rateconv_SOURCES = rateconv.cpp CArg.cpp CArg.hpp | |
69 | + |
@@ -0,0 +1,830 @@ | ||
1 | +/** | |
2 | + * Freeverb3 Sampling Rate Converter | |
3 | + * | |
4 | + * Copyright (C) 2007-2014 Teru Kamogashira | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify | |
7 | + * it under the terms of the GNU General Public License as published by | |
8 | + * the Free Software Foundation; either version 2 of the License, or | |
9 | + * (at your option) any later version. | |
10 | + * | |
11 | + * This program is distributed in the hope that it will be useful, | |
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | + * GNU General Public License for more details. | |
15 | + * | |
16 | + * You should have received a copy of the GNU General Public License | |
17 | + * along with this program; if not, write to the Free Software | |
18 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
19 | + */ | |
20 | + | |
21 | +#include "fv3_config.h" | |
22 | + | |
23 | +#include <cstdio> | |
24 | +#include <cstdlib> | |
25 | +#include <cstring> | |
26 | +#include <cmath> | |
27 | + | |
28 | +#include <stdint.h> | |
29 | + | |
30 | +#include <sndfile.h> | |
31 | +#include <sndfile.hh> | |
32 | +#include <fftw3.h> | |
33 | +#include <freeverb/irmodel2.hpp> | |
34 | +#include <gdither.h> | |
35 | + | |
36 | +#include "CArg.hpp" | |
37 | + | |
38 | +#define DEFAULT_TARGET_FS 48000 | |
39 | +#define DEFAULT_MODE W_KAISER | |
40 | +#define DEFAULT_KAISER_PARAMETER 140 | |
41 | +#define DEFAULT_COSRO_PARAMETER 0.1 | |
42 | +#define DEFAULT_TRANSITION_BAND 1 | |
43 | + | |
44 | +#ifndef DIST_STRING | |
45 | +#define DIST_STRING "" | |
46 | +#endif | |
47 | + | |
48 | +#ifdef PLUGDOUBLE | |
49 | +typedef fv3::irbase_ IRBASE; | |
50 | +typedef fv3::irmodel2_ IR2; | |
51 | +typedef double pfloat_t; | |
52 | +#else | |
53 | +typedef fv3::irbase_f IRBASE; | |
54 | +typedef fv3::irmodel2_f IR2; | |
55 | +typedef float pfloat_t; | |
56 | +#endif | |
57 | + | |
58 | +static IR2 reverbm; | |
59 | +const unsigned options = FV3_IR_DEFAULT|FV3_IR_SKIP_FILTER|FV3_IR_MUTE_DRY; | |
60 | +//const long fragmentSize = 512; | |
61 | +//const long ffactor = 32; | |
62 | +long groupDelay = 0; | |
63 | +const long VST_frame = 16384; | |
64 | +pfloat_t clipL = 0.0, clipR = 0.0; | |
65 | +pfloat_t attenuation = 1.0f; | |
66 | + | |
67 | +CArg args; | |
68 | + | |
69 | +SndfileHandle * output; | |
70 | +static long outputFormat = SF_FORMAT_WAV|SF_FORMAT_FLOAT; | |
71 | +static long outputMode = 0; | |
72 | + | |
73 | +#define OMODE_FL 0 | |
74 | +#define OMODE_16 1 | |
75 | +#define OMODE_24 2 | |
76 | +#define OMODE_32 3 | |
77 | + | |
78 | +static GDither pdither; | |
79 | +static long ditherMode = GDitherNone; | |
80 | + | |
81 | +#ifndef M_PI | |
82 | +#define M_PI 3.14159265358979323846 | |
83 | +#endif | |
84 | + | |
85 | +#ifndef max | |
86 | +#define max(a,b) (((a) > (b)) ? (a) : (b)) | |
87 | +#endif | |
88 | + | |
89 | +#ifndef min | |
90 | +#define min(a,b) (((a) < (b)) ? (a) : (b)) | |
91 | +#endif | |
92 | + | |
93 | +static long checkFileExist(const char * filename) | |
94 | +{ | |
95 | + FILE * fp = fopen(filename ,"rb"); | |
96 | + if(fp == NULL) | |
97 | + return 0; | |
98 | + return 1; | |
99 | +} | |
100 | + | |
101 | +static long gcmi(long a, long b) | |
102 | +{ | |
103 | + if(a < b) return gcmi(b, a); | |
104 | + long r = a % b; | |
105 | + if(r == 0) return b; | |
106 | + else return gcmi(b, r); | |
107 | +} | |
108 | + | |
109 | +static long lcmi(long a, long b) | |
110 | +{ | |
111 | + long g = gcmi(a, b); | |
112 | + return (a/g) * (b/g) * g; | |
113 | +} | |
114 | + | |
115 | +// FIR FILTER C | |
116 | + | |
117 | +// Windows | |
118 | + | |
119 | +static void Square(pfloat_t w[], const long N) | |
120 | +{ | |
121 | + long i; | |
122 | + for(i = 0;i < N;i ++) | |
123 | + { | |
124 | + w[i] = 1; | |
125 | + } | |
126 | + return; | |
127 | +} | |
128 | + | |
129 | +static void Hamming(pfloat_t w[], const long N) | |
130 | +{ | |
131 | + long i; | |
132 | + const pfloat_t M = N-1; | |
133 | + for(i = 0; i < N; i++) | |
134 | + { | |
135 | + w[i] = 0.54 - (0.46*cos(2.0*M_PI*(pfloat_t)i/M)); | |
136 | + } | |
137 | + return; | |
138 | +} | |
139 | + | |
140 | +static void Hanning(pfloat_t w[], const long N) | |
141 | +{ | |
142 | + long i; | |
143 | + const pfloat_t M = N-1; | |
144 | + for(i = 0; i < N; i++) | |
145 | + { | |
146 | + w[i] = 0.5 * (1.0 - cos(2.0*M_PI*(pfloat_t)i/M)); | |
147 | + } | |
148 | + return; | |
149 | +} | |
150 | + | |
151 | +static void Blackman(pfloat_t w[], const long N) | |
152 | +{ | |
153 | + long i; | |
154 | + const pfloat_t M = N-1; | |
155 | + for(i = 0; i < N; i++) | |
156 | + { | |
157 | + w[i] = | |
158 | + 0.42 - (0.5 * cos(2.0*M_PI*(pfloat_t)i/M)) + | |
159 | + (0.08*cos(4.0*M_PI*(pfloat_t)i/M)); | |
160 | + } | |
161 | + return; | |
162 | +} | |
163 | + | |
164 | +#ifndef isfinite | |
165 | +#define isfinite(v) std::isfinite(v) | |
166 | +#endif | |
167 | + | |
168 | +static pfloat_t i_zero(pfloat_t x) | |
169 | +{ | |
170 | + /* | |
171 | + The zeroth order Modified Bessel function: | |
172 | + | |
173 | + I_0(x) = 1 + | |
174 | + x^2 / 2^2 + | |
175 | + x^4 / (2^2 * 4^2) + | |
176 | + x^6 / (2^2 * 4^2 * 6^2) + | |
177 | + ... to infinity | |
178 | + | |
179 | + This function grows quite quickly towards very large numbers. | |
180 | + By re-organising the calculations somewhat we minimise the dynamic | |
181 | + range in the floating polong numbers, and can thus calculate the | |
182 | + function for larger x than we could do with a naive implementation. | |
183 | + */ | |
184 | + pfloat_t n, a, halfx, sum; | |
185 | + halfx = x / 2.0; | |
186 | + sum = 1.0; | |
187 | + a = 1.0; | |
188 | + n = 1.0; | |
189 | + do { | |
190 | + a *= halfx; | |
191 | + a /= n; | |
192 | + sum += a * a; | |
193 | + n += 1.0; | |
194 | + /* either 'sum' will reach +inf or 'a' zero... */ | |
195 | + } while (a != 0.0 && isfinite(sum)); | |
196 | + return sum; | |
197 | +} | |
198 | + | |
199 | +static void Kaiser(pfloat_t w[], const long N, pfloat_t sl) | |
200 | +{ | |
201 | + long i; | |
202 | + pfloat_t beta = 0.5; | |
203 | + // -sl[dB] | |
204 | + if(sl > 50) | |
205 | + beta = 0.1102*(sl-8.7); | |
206 | + else if(sl >= 20) | |
207 | + beta = 0.5842 * std::pow((double)sl-21, 0.4) + 0.07886*(sl-21); | |
208 | + else | |
209 | + beta = 0; | |
210 | + std::fprintf(stderr, "Kaiser beta=%f\n", beta); | |
211 | + const pfloat_t M = N-1; | |
212 | + pfloat_t inv_izbeta = 1.0 / i_zero(M_PI*beta); | |
213 | + for(i = 0;i < N;i ++) | |
214 | + { | |
215 | + w[i] = | |
216 | + i_zero(M_PI*beta*sqrt(1-std::pow(2*(pfloat_t)i/M-1, 2))) * inv_izbeta; | |
217 | + } | |
218 | +} | |
219 | + | |
220 | +static void CosROW(pfloat_t w[], const long &N, const pfloat_t &fc, | |
221 | + const pfloat_t &alpha) | |
222 | +{ | |
223 | + long i; | |
224 | + const pfloat_t M = N-1; | |
225 | + pfloat_t n; | |
226 | + for(i = 0; i < N; i++) | |
227 | + { | |
228 | + n = (pfloat_t)i - M/2.0; | |
229 | + w[i] = std::cos(M_PI*n*2.0*fc*M_PI*alpha) | |
230 | + / (1 - std::pow((M_PI*n*2.0*fc*2*alpha),2)); | |
231 | + } | |
232 | + return; | |
233 | +} | |
234 | + | |
235 | +// Sinc | |
236 | + | |
237 | +static void Sinc(pfloat_t sinc[], const long N, const pfloat_t &fc) | |
238 | +{ | |
239 | + long i; | |
240 | + const pfloat_t M = N-1; | |
241 | + pfloat_t n; | |
242 | + // Generate sinc delayed by (N-1)/2 | |
243 | + for(i = 0; i < N; i++) | |
244 | + { | |
245 | + if(i == M/2.0) | |
246 | + { | |
247 | + sinc[i] = 2.0 * fc; | |
248 | + } | |
249 | + else | |
250 | + { | |
251 | + n = (pfloat_t)i - M/2.0; | |
252 | + sinc[i] = std::sin(M_PI*n*2.0*fc) / (M_PI*n); | |
253 | + } | |
254 | + } | |
255 | + return; | |
256 | +} | |
257 | + | |
258 | +const long W_BLACKMAN = 1; | |
259 | +const long W_HANNING = 2; | |
260 | +const long W_HAMMING = 3; | |
261 | +const long W_KAISER = 4; | |
262 | +const long W_COSRO = 5; | |
263 | +const long W_SQUARE = 6; | |
264 | + | |
265 | +// LPF | |
266 | + | |
267 | +static void firLPF(pfloat_t h[], const long N, | |
268 | + const long WINDOW, const pfloat_t fc, | |
269 | + const pfloat_t sl, const pfloat_t alpha) | |
270 | +{ | |
271 | + long i; | |
272 | + pfloat_t * w = new pfloat_t[N]; | |
273 | + pfloat_t * sinc = new pfloat_t[N]; | |
274 | + Sinc(sinc, N, fc); | |
275 | + switch(WINDOW) | |
276 | + { | |
277 | + case W_SQUARE: | |
278 | + std::fprintf(stderr, "W_SQUARE\n"); | |
279 | + Square(w, N); | |
280 | + break; | |
281 | + case W_BLACKMAN: | |
282 | + std::fprintf(stderr, "W_BLACKMAN\n"); | |
283 | + Blackman(w, N); | |
284 | + break; | |
285 | + case W_HANNING: | |
286 | + std::fprintf(stderr, "W_HANNING\n"); | |
287 | + Hanning(w, N); | |
288 | + break; | |
289 | + case W_HAMMING: | |
290 | + std::fprintf(stderr, "W_HAMMING\n"); | |
291 | + Hamming(w, N); | |
292 | + break; | |
293 | + case W_KAISER: | |
294 | + std::fprintf(stderr, "W_KAISER -%fdB\n", sl); | |
295 | + Kaiser(w, N, sl); | |
296 | + break; | |
297 | + case W_COSRO: | |
298 | + std::fprintf(stderr, "W_COSRO alpha=%f\n", alpha); | |
299 | + CosROW(w, N, fc, alpha); | |
300 | + break; | |
301 | + default: | |
302 | + std::fprintf(stderr, "Invalid window mode: %ld\n", WINDOW); | |
303 | + std::exit(-1); | |
304 | + break; | |
305 | + } | |
306 | + for(i = 0; i < N; i++) | |
307 | + { | |
308 | + h[i] = sinc[i] * w[i]; | |
309 | + } | |
310 | + delete[] w; | |
311 | + delete[] sinc; | |
312 | + return; | |
313 | +} | |
314 | + | |
315 | +#if 0 | |
316 | +static void firHPF(pfloat_t h[], const long N, | |
317 | + const long WINDOW, const pfloat_t fc, | |
318 | + const pfloat_t sl, const pfloat_t alpha) | |
319 | +{ | |
320 | + long i; | |
321 | + firLPF(h, N, WINDOW, fc, sl, alpha); | |
322 | + // 2. Spectrally invert (negate all samples and add 1 to center sample) lowpass filter | |
323 | + // = delta[n-((N-1)/2)] - h[n], in the time domain | |
324 | + for(i = 0;i < N;i ++) | |
325 | + { | |
326 | + h[i] *= -1.0; // = 0 - h[i] | |
327 | + } | |
328 | + h[(N-1)/2] += 1.0; // = 1 - h[(N-1)/2] | |
329 | + return; | |
330 | +} | |
331 | + | |
332 | +static void firBSF(double h[], const long N, | |
333 | + const long WINDOW, const pfloat_t fc1, const pfloat_t fc2, | |
334 | + const pfloat_t sl, const pfloat_t alpha) | |
335 | +{ | |
336 | + long i; | |
337 | + pfloat_t *h1 = new pfloat_t[N]; | |
338 | + pfloat_t *h2 = new pfloat_t[N]; | |
339 | + firLPF(h1, N, WINDOW, fc1, sl, alpha); | |
340 | + firHPF(h2, N, WINDOW, fc2, sl, alpha); | |
341 | + for(i = 0;i < N;i ++) | |
342 | + { | |
343 | + h[i] = h1[i] + h2[i]; | |
344 | + } | |
345 | + delete[] h1; | |
346 | + delete[] h2; | |
347 | + return; | |
348 | +} | |
349 | + | |
350 | +static void firBPF(double h[], const int N, | |
351 | + const int WINDOW, const double fc1, const double fc2, | |
352 | + const pfloat_t sl, const pfloat_t alpha) | |
353 | +{ | |
354 | + int i; | |
355 | + firBSF(h, N, WINDOW, fc1, fc2, sl, alpha); | |
356 | + for (i = 0; i < N; i++) | |
357 | + { | |
358 | + h[i] *= -1.0; // = 0 - h[i] | |
359 | + } | |
360 | + h[(N-1)/2] += 1.0; // = 1 - h[(N-1)/2] | |
361 | + return; | |
362 | +} | |
363 | +#endif | |
364 | + | |
365 | +// FIR FILTER C | |
366 | + | |
367 | +static void setLPF(IRBASE * model, long len, pfloat_t fc, | |
368 | + const long WINDOW, const pfloat_t sl, const pfloat_t alpha) | |
369 | +{ | |
370 | + std::fprintf(stderr, "LPF: filterLength %ld limit %f\n", len, fc); | |
371 | + pfloat_t * fir = new pfloat_t[len]; | |
372 | + firLPF(fir, len, WINDOW, fc, sl, alpha); | |
373 | + //model->loadImpulse(fir, fir, len, FFTW_ESTIMATE, fragmentSize, ffactor); | |
374 | + model->loadImpulse(fir, fir, len); | |
375 | + delete[] fir; | |
376 | +} | |
377 | + | |
378 | +static long predictN(long mode, pfloat_t transitionF, | |
379 | + const pfloat_t attenuation, const pfloat_t alpha) | |
380 | +{ | |
381 | + std::fprintf(stderr, "== predict filter length ===\n"); | |
382 | + std::fprintf(stderr, "Transition Bandwidth %f\n", transitionF); | |
383 | + long N = 0; | |
384 | + switch(mode) | |
385 | + { | |
386 | + case W_SQUARE: | |
387 | + N = (long)std::ceil((1.8*M_PI)/(transitionF*M_PI))+1; | |
388 | + break; | |
389 | + case W_BLACKMAN: | |
390 | + N = (long)std::ceil((11*M_PI)/(transitionF*M_PI))+1; | |
391 | + break; | |
392 | + case W_HANNING: | |
393 | + N = (long)std::ceil((6.2*M_PI)/(transitionF*M_PI))+1; | |
394 | + break; | |
395 | + case W_HAMMING: | |
396 | + N = (long)std::ceil((6.6*M_PI)/(transitionF*M_PI))+1; | |
397 | + break; | |
398 | + case W_KAISER: | |
399 | + if(attenuation <= 21) | |
400 | + N = (long)std::ceil(0.9222/transitionF)+1; | |
401 | + else | |
402 | + N = (long)std::ceil((attenuation-7.95)/(14.36*transitionF))+1; | |
403 | + break; | |
404 | + case W_COSRO: | |
405 | + N = 0; | |
406 | + break; | |
407 | + default: | |
408 | + std::fprintf(stderr, "Invalid window mode: %ld\n", mode); | |
409 | + N = 0; | |
410 | + break; | |
411 | + } | |
412 | + return N; | |
413 | +} | |
414 | + | |
415 | +static void mute(pfloat_t * f, long t) | |
416 | +{ | |
417 | + for(long i = 0;i < t;i ++) | |
418 | + f[i] = 0.0f; | |
419 | +} | |
420 | + | |
421 | +static long rcount = 0; | |
422 | +static void readPad(pfloat_t * L, pfloat_t * R, long factor, | |
423 | + long size, SndfileHandle * snd) | |
424 | +{ | |
425 | + pfloat_t v[2]; | |
426 | + for(long i = 0;i < size;i ++) | |
427 | + { | |
428 | + if(rcount == 0) | |
429 | + { | |
430 | + snd->readf(v, 1); | |
431 | + L[i] = v[0]; | |
432 | + R[i] = v[1]; | |
433 | + } | |
434 | + else | |
435 | + { | |
436 | + L[i] = R[i] = 0; | |
437 | + } | |
438 | + rcount ++; | |
439 | + if(rcount == factor) | |
440 | + rcount = 0; | |
441 | + } | |
442 | +} | |
443 | + | |
444 | +static long wcount = 0; | |
445 | +static void writePick(pfloat_t * L, pfloat_t * R, | |
446 | + long factor, long size, double dfactor) | |
447 | +{ | |
448 | + float v[2]; | |
449 | + for(long i = 0;i < size;i ++) | |
450 | + { | |
451 | + if(wcount == 0) | |
452 | + { | |
453 | + v[0] = dfactor*L[i]*attenuation; | |
454 | + v[1] = dfactor*R[i]*attenuation; | |
455 | + if(v[0] > 1.0||v[0] < -1.0) | |
456 | + { | |
457 | + clipL = v[0]; | |
458 | + } | |
459 | + if(v[1] > 1.0||v[1] < -1.0) | |
460 | + { | |
461 | + clipR = v[1]; | |
462 | + } | |
463 | + if(groupDelay > 0) | |
464 | + { | |
465 | + groupDelay --; | |
466 | + } | |
467 | + else | |
468 | + { | |
469 | + switch(outputMode) | |
470 | + { | |
471 | + case OMODE_16: | |
472 | + int16_t o16[2]; | |
473 | + gdither_runf(pdither, 0, 1, v, o16); | |
474 | + gdither_runf(pdither, 1, 1, v, o16); | |
475 | + output->writef(o16, 1); | |
476 | + break; | |
477 | + case OMODE_24: | |
478 | + case OMODE_32: | |
479 | + int32_t o32[2]; | |
480 | + gdither_runf(pdither, 0, 1, v, o32); | |
481 | + gdither_runf(pdither, 1, 1, v, o32); | |
482 | + output->writef(o32, 1); | |
483 | + break; | |
484 | + default: | |
485 | + output->writef(v, 1); | |
486 | + break; | |
487 | + } | |
488 | + } | |
489 | + } | |
490 | + wcount ++; | |
491 | + if(wcount == factor) | |
492 | + wcount = 0; | |
493 | + } | |
494 | +} | |
495 | + | |
496 | +static void processAll(IRBASE * model, SndfileHandle * snd, | |
497 | + long fBlock, long upBlock, long toBlock) | |
498 | +{ | |
499 | + long upFactor = upBlock/fBlock; | |
500 | + double factor = (double)upFactor; | |
501 | + long downFactor = upBlock/toBlock; | |
502 | + long long upFrames = ((long long)upFactor)*snd->frames(); | |
503 | + std::fprintf(stderr, "Original samples: %lld\n", (long long)snd->frames()); | |
504 | + std::fprintf(stderr, "Total samples: %lld\n", upFrames); | |
505 | + long count = (long)(upFrames/((long long)VST_frame)); | |
506 | + long rest = (long)(upFrames%((long long)VST_frame)); | |
507 | + pfloat_t *iL, *iR, *oL, *oR; | |
508 | + try | |
509 | + { | |
510 | + iL = new pfloat_t[VST_frame]; | |
511 | + iR = new pfloat_t[VST_frame]; | |
512 | + oL = new pfloat_t[VST_frame]; | |
513 | + oR = new pfloat_t[VST_frame]; | |
514 | + } | |
515 | + catch(std::bad_alloc) | |
516 | + { | |
517 | + std::fprintf(stderr, "std::bad_alloc %ld x 4\n", VST_frame); | |
518 | + std::exit(-1); | |
519 | + } | |
520 | + for(long i = 0;i < count;i ++) | |
521 | + { | |
522 | + std::fprintf(stderr, "%ld/%ld x %ld\r", i, count, VST_frame); | |
523 | + readPad(iL, iR, upFactor, VST_frame, snd); | |
524 | + model->processreplace(iL,iR,oL,oR,VST_frame,options); | |
525 | + writePick(oL, oR, downFactor, VST_frame, factor); | |
526 | + } | |
527 | + std::fprintf(stderr, "\nrest = %ld", rest); | |
528 | + readPad(iL, iR, upFactor, rest, snd); | |
529 | + model->processreplace(iL,iR,oL,oR,rest,options); | |
530 | + writePick(oL, oR, downFactor, rest, factor); | |
531 | + | |
532 | + std::fprintf(stderr, "\nWait for IR...\n"); | |
533 | + int wait = ((model->getImpulseSize()-1)/2) + model->getLatency(); | |
534 | + count = wait/VST_frame; | |
535 | + rest = wait%VST_frame; | |
536 | + for(long i = 0;i < count;i ++) | |
537 | + { | |
538 | + std::fprintf(stderr, "%ld/%ld x %ld\r", i, count, VST_frame); | |
539 | + mute(iL, VST_frame); | |
540 | + mute(iR, VST_frame); | |
541 | + model->processreplace(iL,iR,oL,oR,VST_frame,options); | |
542 | + writePick(oL, oR, downFactor, VST_frame, factor); | |
543 | + } | |
544 | + std::fprintf(stderr, "\nrest = %ld", rest); | |
545 | + mute(iL, rest); | |
546 | + mute(iR, rest); | |
547 | + model->processreplace(iL,iR,oL,oR,rest,options); | |
548 | + writePick(oL, oR, downFactor, rest, factor); | |
549 | + | |
550 | + std::fprintf(stderr, "\ndone.\n"); | |
551 | + delete[] iL; | |
552 | + delete[] iR; | |
553 | + delete[] oL; | |
554 | + delete[] oR; | |
555 | +} | |
556 | + | |
557 | +void help(const char * cmd) | |
558 | +{ | |
559 | + std::fprintf(stderr, "%s [options] input output\n", cmd); | |
560 | + std::fprintf(stderr, "Input: libsndfile supported file.\n"); | |
561 | + std::fprintf(stderr, "Output: WAV\n"); | |
562 | + std::fprintf(stderr, "[[Options]]\n"); | |
563 | + std::fprintf(stderr, "-r Target sampling rate\n"); | |
564 | + std::fprintf(stderr, "-m Mode\n"); | |
565 | + std::fprintf(stderr, "\tn Window [Stopband Attenuation]\n"); | |
566 | + std::fprintf(stderr, "\t1 Blackman [-74dB]\n"); | |
567 | + std::fprintf(stderr, "\t2 Hanning [-44dB]\n"); | |
568 | + std::fprintf(stderr, "\t3 Hamming [-53dB]\n"); | |
569 | + std::fprintf(stderr, "\t4 Kaiser [-<parameter>dB]\n"); | |
570 | + std::fprintf(stderr, "\t5 CosineRollOff (alpha=<parameter>)\n"); | |
571 | + std::fprintf(stderr, "\t\t(alpha >0 && <=1) 0->default,\n"); | |
572 | + std::fprintf(stderr, "\t\tuse Square window when alpha=0.\n"); | |
573 | + std::fprintf(stderr, "\t6 Square [-21dB]\n"); | |
574 | + std::fprintf(stderr, "-k Kaiser Parameter\n"); | |
575 | + std::fprintf(stderr, "-a CosineRollOff Parameter\n"); | |
576 | + std::fprintf(stderr, "-t Transition bandwidth [Hz]\n"); | |
577 | + std::fprintf(stderr, "\tignored if the window mode is CosineRollOff\n"); | |
578 | + std::fprintf(stderr, "-ow overwrite\n"); | |
579 | + std::fprintf(stderr, "\t1 = allow overwrite\n"); | |
580 | + std::fprintf(stderr, "-att Overall attenuation\n"); | |
581 | + std::fprintf(stderr, "-n Override filter length\n"); | |
582 | + std::fprintf(stderr, "-f output Precision\n"); | |
583 | + std::fprintf(stderr, "\t0 32bit Float Little Endian (default)\n"); | |
584 | + std::fprintf(stderr, "\t1 Signed 16 bit Little Endian (CD precision)\n"); | |
585 | + std::fprintf(stderr, "\t2 Signed 24 bit Little Endian in 3bytes\n"); | |
586 | + std::fprintf(stderr, "\t3 Signed 32 bit Little Endian\n"); | |
587 | + std::fprintf(stderr, "-gd gdither mode\n"); | |
588 | + std::fprintf(stderr, "\t0 None\n"); | |
589 | + std::fprintf(stderr, "\t1 Rect\n"); | |
590 | + std::fprintf(stderr, "\t2 Tri\n"); | |
591 | + std::fprintf(stderr, "\t3 Shaped\n"); | |
592 | + std::fprintf(stderr, "[[Example]]\n"); | |
593 | + std::fprintf(stderr, "1. conversion to 96k float\n"); | |
594 | + std::fprintf(stderr, "%s -r 96000 -m 4 -k 140 input.wav output.wav\n", | |
595 | + cmd); | |
596 | + std::fprintf(stderr, "2. conversion to CD format with shaped dithering\n"); | |
597 | + std::fprintf(stderr, "%s -r 44100 -m 4 -k 140 -f 1 -gd 3 input.wav output.wav\n", | |
598 | + cmd); | |
599 | + std::fprintf(stderr, "[[Note]]\n"); | |
600 | + std::fprintf(stderr, "If the conversion factor is not an integer,\n"); | |
601 | + std::fprintf(stderr, "it will take a lot to convert. (ex. 48k->44.1k)\n"); | |
602 | + std::fprintf(stderr, "\n"); | |
603 | +} | |
604 | + | |
605 | +int main(int argc, char* argv[]) | |
606 | +{ | |
607 | + std::fprintf(stderr, "1-pass Sampling Rate Converter\n"); | |
608 | + std::fprintf(stderr, "<"PACKAGE DIST_STRING"-"VERSION">\n"); | |
609 | + std::fprintf(stderr, "Copyright (C) 2007-2014 Teru Kamogashira\n"); | |
610 | + std::fprintf(stderr, "sizeof(pfloat_t) = %d\n\n", (int)sizeof(pfloat_t)); | |
611 | + | |
612 | + if (argc <= 1) | |
613 | + { | |
614 | + help(argv[0]); | |
615 | + exit(-1); | |
616 | + } | |
617 | + | |
618 | + if(args.registerArg(argc, argv) != 0) | |
619 | + exit(-1); | |
620 | + | |
621 | + long outputMode = args.getLong("-f"); | |
622 | + std::fprintf(stderr, "> outputMode = %ld\n", outputMode); | |
623 | + switch(outputMode) | |
624 | + { | |
625 | + case OMODE_16: | |
626 | + outputFormat = SF_FORMAT_WAV|SF_FORMAT_PCM_16; | |
627 | + break; | |
628 | + case OMODE_24: | |
629 | + outputFormat = SF_FORMAT_WAV|SF_FORMAT_PCM_24; | |
630 | + break; | |
631 | + case OMODE_32: | |
632 | + outputFormat = SF_FORMAT_WAV|SF_FORMAT_PCM_32; | |
633 | + break; | |
634 | + default: | |
635 | + outputFormat = SF_FORMAT_WAV|SF_FORMAT_FLOAT; | |
636 | + break; | |
637 | + } | |
638 | + | |
639 | + ditherMode = args.getLong("-gd"); | |
640 | + std::fprintf(stderr, "> ditherMode = %ld\n", ditherMode); | |
641 | + GDitherType gt = (GDitherType)ditherMode; | |
642 | + switch(outputMode) | |
643 | + { | |
644 | + case OMODE_16: | |
645 | + pdither = gdither_new(gt, 2, GDither16bit, 16); | |
646 | + break; | |
647 | + case OMODE_24: | |
648 | + pdither = gdither_new(gt, 2, GDither32bit, 24); | |
649 | + break; | |
650 | + case OMODE_32: | |
651 | + pdither = gdither_new(gt, 2, GDither32bit, 32); | |
652 | + break; | |
653 | + default: | |
654 | + std::fprintf(stderr, "Dithering is not used in float output mode.\n"); | |
655 | + pdither = NULL; | |
656 | + break; | |
657 | + } | |
658 | + | |
659 | + long toRate = args.getLong("-r"); | |
660 | + if(toRate <= 0) | |
661 | + { | |
662 | + std::fprintf(stderr, "!!! -r %ld \n", toRate); | |
663 | + toRate = DEFAULT_TARGET_FS; | |
664 | + } | |
665 | + std::fprintf(stderr, "> Target Sampling Rate = %ld\n", toRate); | |
666 | + | |
667 | + long mode = args.getLong("-m"); | |
668 | + if(mode == 0) | |
669 | + { | |
670 | + std::fprintf(stderr, "!!! -m %ld \n", mode); | |
671 | + mode = DEFAULT_MODE; | |
672 | + } | |
673 | + std::fprintf(stderr, "> Mode = %ld\n", mode); | |
674 | + | |
675 | + double kparam = args.getDouble("-k"); | |
676 | + if(kparam <= 0) | |
677 | + { | |
678 | + std::fprintf(stderr, "!!! -k %f \n", kparam); | |
679 | + kparam = DEFAULT_KAISER_PARAMETER; | |
680 | + } | |
681 | + std::fprintf(stderr, "> Kaiser Parameter = %f\n", kparam); | |
682 | + | |
683 | + double cparam = args.getDouble("-a"); | |
684 | + if(cparam <= 0||cparam > 1) | |
685 | + { | |
686 | + std::fprintf(stderr, "!!! -a %f \n", cparam); | |
687 | + cparam = DEFAULT_COSRO_PARAMETER; | |
688 | + } | |
689 | + std::fprintf(stderr, "> CosRO Parameter = %f\n", cparam); | |
690 | + | |
691 | + double transitionBand = args.getDouble("-t"); | |
692 | + if(transitionBand <= 0) | |
693 | + transitionBand = DEFAULT_TRANSITION_BAND; | |
694 | + std::fprintf(stderr, "> Transition Band = %f\n", transitionBand); | |
695 | + | |
696 | + long overWrite = args.getLong("-ow"); | |
697 | + std::fprintf(stderr, "> overWrite = %ld\n", overWrite); | |
698 | + attenuation = args.getDouble("-att"); | |
699 | + if(attenuation == 0) | |
700 | + attenuation = 1; | |
701 | + std::fprintf(stderr, "> overall attenuation = %f\n", attenuation); | |
702 | + | |
703 | + long filterLength = args.getLong("-n"); | |
704 | + std::fprintf(stderr, "> Override Filter Length = %ld\n", filterLength); | |
705 | + | |
706 | + if(strlen(args.getFileArg(0)) == 0) | |
707 | + { | |
708 | + std::fprintf(stderr, "Input file is not specified.\n"); | |
709 | + exit(-1); | |
710 | + } | |
711 | + std::fprintf(stderr, "> Input = %s\n", args.getFileArg(0)); | |
712 | + | |
713 | + if(strlen(args.getFileArg(1)) == 0) | |
714 | + { | |
715 | + std::fprintf(stderr, "Output file is not specified.\n"); | |
716 | + exit(-1); | |
717 | + } | |
718 | + std::fprintf(stderr, "> Output = %s\n", args.getFileArg(1)); | |
719 | + | |
720 | + SndfileHandle sndHandle(args.getFileArg(0)); | |
721 | + if(sndHandle.frames() == 0||sndHandle.channels() != 2) | |
722 | + { | |
723 | + std::fprintf(stderr, "PCM file/channels is not valid: %s(%d).\n", | |
724 | + args.getFileArg(0), sndHandle.channels()); | |
725 | + exit(-1); | |
726 | + } | |
727 | + | |
728 | + if(strcmp(args.getFileArg(0), args.getFileArg(1)) == 0) | |
729 | + { | |
730 | + std::fprintf(stderr, "!!! Input = Output\n"); | |
731 | + exit(-1); | |
732 | + } | |
733 | + | |
734 | + if(overWrite == 0&&checkFileExist(args.getFileArg(1)) != 0) | |
735 | + { | |
736 | + std::fprintf(stderr, "!!! Cannot overwrite file: %s\n", args.getFileArg(1)); | |
737 | + exit(-1); | |
738 | + } | |
739 | + | |
740 | + output = new SndfileHandle(args.getFileArg(1), SFM_WRITE, | |
741 | + outputFormat, sndHandle.channels(), toRate); | |
742 | + if (output->refCount() != 1) | |
743 | + { | |
744 | + std::fprintf(stderr, "SndfileHandle Error: Reference count (%d) != 1.\n", | |
745 | + output->refCount()); | |
746 | + std::fprintf(stderr, "I/O error or permission error.\n"); | |
747 | + exit (-1) ; | |
748 | + } | |
749 | + output->setString(SF_STR_TITLE, args.getFileArg(1)); | |
750 | + | |
751 | + std::fprintf(stderr, "\n"); | |
752 | + long gcmRate = gcmi(toRate, sndHandle.samplerate()); | |
753 | + long upRate = lcmi(toRate, sndHandle.samplerate()); | |
754 | + std::fprintf(stderr, "%d -[0]-> %ld -[LPF]-> %ld\n", | |
755 | + sndHandle.samplerate(), upRate, toRate); | |
756 | + | |
757 | + long fBlock = sndHandle.samplerate()/gcmRate; | |
758 | + long toBlock = toRate/gcmRate; | |
759 | + long upBlock = fBlock*toBlock; | |
760 | + std::fprintf(stderr, "Block: [%ld]->[%ld]->[%ld]\n", fBlock, upBlock, toBlock); | |
761 | + | |
762 | + long upFactor = upBlock/fBlock; | |
763 | + long downFactor = upBlock/toBlock; | |
764 | + | |
765 | + pfloat_t fc = 0.5; | |
766 | + if(upFactor < downFactor) | |
767 | + { | |
768 | + std::fprintf(stderr, " x%ld < [x%ld]", upFactor, downFactor); | |
769 | + fc = 1/(pfloat_t)downFactor/2; | |
770 | + } | |
771 | + else | |
772 | + { | |
773 | + std::fprintf(stderr, " [x%ld] > x%ld", upFactor, downFactor); | |
774 | + fc = 1/(pfloat_t)upFactor/2; | |
775 | + } | |
776 | + std::fprintf(stderr, " ==>> LPF %f\n", fc); | |
777 | + long filter = (long)(2*(double)1/fc); | |
778 | + std::fprintf(stderr, " filterLength > %ld\n", filter); | |
779 | + double upRatef = (double)upRate; | |
780 | + double upFactorf = (double)upFactor; | |
781 | + double transitionF = upFactorf*transitionBand/upRatef; | |
782 | + std::fprintf(stderr, "Transition band F: %.8f\n", transitionF); | |
783 | + long N = predictN(mode, transitionF, kparam, cparam); | |
784 | + std::fprintf(stderr, "Estimated N: %ld\n", N); | |
785 | + if(N > filter) filter = N; | |
786 | + if(filterLength > 0) | |
787 | + { | |
788 | + if((long)(2*(double)1/fc) > filterLength) | |
789 | + { | |
790 | + std::fprintf(stderr, "!!! filterLength is too short.\n"); | |
791 | + } | |
792 | + else | |
793 | + { | |
794 | + filter = filterLength; | |
795 | + std::fprintf(stderr, "FilterLength was overriden.\n"); | |
796 | + } | |
797 | + } | |
798 | + if(filter % 2 == 0) filter ++; | |
799 | + | |
800 | + setLPF(&reverbm, filter, fc, mode, kparam, cparam); | |
801 | + | |
802 | + long upGroupDelay = (filter-1)/2; | |
803 | + std::fprintf(stderr, "U Group Delay = %ld\n", upGroupDelay); | |
804 | + std::fprintf(stderr, "IR Latency = %ld\n", reverbm.getLatency()); | |
805 | + groupDelay = | |
806 | + (long)((double)(upGroupDelay + reverbm.getLatency())/(double)downFactor); | |
807 | + std::fprintf(stderr, "Total Group Delay + Latency = %ld\n", groupDelay); | |
808 | + | |
809 | + reverbm.setwet(0); | |
810 | + reverbm.setwidth(1); | |
811 | + processAll(&reverbm, &sndHandle, fBlock, fBlock*toBlock, toBlock); | |
812 | + | |
813 | + if(clipL != 0.0||clipR != 0.0) | |
814 | + { | |
815 | + std::fprintf(stderr, "Clip L max: %f\n", clipL); | |
816 | + std::fprintf(stderr, "\tshould be x %f\n", fabs(1.0/clipL)); | |
817 | + std::fprintf(stderr, "Clip L max: %f\n", clipR); | |
818 | + std::fprintf(stderr, "\tshould be x %f\n", fabs(1.0/clipR)); | |
819 | + std::fprintf(stderr, "Use -att to reduce clipping.\n"); | |
820 | + } | |
821 | + | |
822 | + delete output; | |
823 | + if(pdither != NULL) | |
824 | + { | |
825 | + gdither_free(pdither); | |
826 | + } | |
827 | + | |
828 | + std::fprintf(stderr, "\n"); | |
829 | + return 0; | |
830 | +} |