From f3dfada88829ddd4f2a8e2ee93649e2b1937b1b3 Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Wed, 15 Jun 2022 11:31:35 +0100 Subject: [PATCH] Provide proper support for R2/R3 choice through command line options in utility --- main/main.cpp | 198 +++++++++++++++++++++++++++++++++----------------- meson.build | 31 ++++++-- 2 files changed, 158 insertions(+), 71 deletions(-) diff --git a/main/main.cpp b/main/main.cpp index 16e559d..5f6992a 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -103,7 +103,10 @@ int main(int argc, char **argv) bool together = false; bool crispchanged = false; int crispness = -1; + bool faster = false; + bool finer = false; bool help = false; + bool fullHelp = false; bool version = false; bool quiet = false; @@ -128,11 +131,17 @@ int main(int argc, char **argv) bool ignoreClipping = false; + std::string myName(argv[0]); + + bool isR3 = (myName.size() > 3 && + myName.substr(myName.size() - 3, 3) == "-r3"); + while (1) { int optionIndex = 0; static struct option longOpts[] = { { "help", 0, 0, 'h' }, + { "full-help", 0, 0, 'H' }, { "version", 0, 0, 'V' }, { "time", 1, 0, 't' }, { "tempo", 1, 0, 'T' }, @@ -148,10 +157,10 @@ int main(int argc, char **argv) { "formant", 0, 0, 'F' }, { "no-threads", 0, 0, '0' }, { "no-transients", 0, 0, '1' }, - { "no-lamination", 0, 0, '2' }, + { "no-lamination", 0, 0, '.' }, { "centre-focus", 0, 0, '7' }, - { "window-long", 0, 0, '3' }, - { "window-short", 0, 0, '4' }, + { "window-long", 0, 0, '>' }, + { "window-short", 0, 0, '<' }, { "bl-transients", 0, 0, '8' }, { "detector-perc", 0, 0, '5' }, { "detector-soft", 0, 0, '6' }, @@ -163,16 +172,19 @@ int main(int argc, char **argv) { "freqmap", 1, 0, 'Q' }, { "pitchmap", 1, 0, 'C' }, { "ignore-clipping", 0, 0, 'i' }, + { "fast", 0, 0, '2' }, + { "fine", 0, 0, '3' }, { 0, 0, 0, 0 } }; c = getopt_long(argc, argv, - "t:p:d:RLPFc:f:T:D:qhVM:", + "t:p:d:RLPFc:f:T:D:qhHVM:23", longOpts, &optionIndex); if (c == -1) break; switch (c) { case 'h': help = true; break; + case 'H': fullHelp = true; break; case 'V': version = true; break; case 't': ratio *= atof(optarg); haveRatio = true; break; case 'T': ratio *= tempo_convert(optarg); haveRatio = true; break; @@ -187,9 +199,9 @@ int main(int argc, char **argv) case '0': threading = 1; break; case '@': threading = 2; break; case '1': transients = NoTransients; crispchanged = true; break; - case '2': lamination = false; crispchanged = true; break; - case '3': longwin = true; crispchanged = true; break; - case '4': shortwin = true; crispchanged = true; break; + case '.': lamination = false; crispchanged = true; break; + case '>': longwin = true; crispchanged = true; break; + case '<': shortwin = true; crispchanged = true; break; case '5': detector = PercussiveDetector; crispchanged = true; break; case '6': detector = SoftDetector; crispchanged = true; break; case '7': together = true; break; @@ -202,6 +214,8 @@ int main(int argc, char **argv) case 'Q': freqMapFile = optarg; freqOrPitchMapSpecified = true; break; case 'C': pitchMapFile = optarg; freqOrPitchMapSpecified = true; break; case 'i': ignoreClipping = true; break; + case '2': faster = true; break; + case '3': finer = true; break; default: help = true; break; } } @@ -220,15 +234,15 @@ int main(int argc, char **argv) realtime = true; } - if (help || !haveRatio || optind + 2 != argc) { + if (help || fullHelp || !haveRatio || optind + 2 != argc) { cerr << endl; cerr << "Rubber Band" << endl; cerr << "An audio time-stretching and pitch-shifting library and utility program." << endl; cerr << "Copyright 2007-2022 Particular Programs Ltd." << endl; cerr << endl; - cerr << " Usage: " << argv[0] << " [options] " << endl; + cerr << " Usage: " << myName << " [options] " << endl; cerr << endl; - cerr << "You must specify at least one of the following time and pitch ratio options." << endl; + cerr << "You must specify at least one of the following time and pitch ratio options:" << endl; cerr << endl; cerr << " -t, --time Stretch to X times original duration, or" << endl; cerr << " -T, --tempo Change tempo by multiple X (same as --time 1/X), or" << endl; @@ -239,7 +253,7 @@ int main(int argc, char **argv) cerr << " -f, --frequency Change frequency by multiple X" << endl; cerr << endl; cerr << "The following options provide ways of making the time and frequency ratios" << endl; - cerr << "change during the audio." << endl; + cerr << "change during the audio:" << endl; cerr << endl; cerr << " -M, --timemap Use file F as the source for time map" << endl; cerr << endl; @@ -267,55 +281,86 @@ int main(int argc, char **argv) cerr << " lists frequency multipliers rather than pitch offsets (like the difference" << endl; cerr << " between pitch and frequency options above)." << endl; cerr << endl; - cerr << "The following options provide a simple way to adjust the sound. See below" << endl; - cerr << "for more details." << endl; + cerr << "The following options affect the sound manipulation and quality:" << endl; + cerr << endl; + cerr << " -2, --fast Use the R2 (faster) engine" << endl; + cerr << endl; + cerr << " This is the default (for backward compatibility) when this tool is invoked" << endl; + cerr << " as \"rubberband\". It was the only engine available in versions prior to v3.0." << endl; + cerr << endl; + cerr << " -3, --fine Use the R3 (finer) engine" << endl; + cerr << endl; + cerr << " This is the default when this tool is invoked as \"rubberband-r3\". It almost" << endl; + cerr << " always produces better results than the R2 engine, but with significantly" << endl; + cerr << " higher CPU load." << endl; cerr << endl; - cerr << " -c, --crisp Crispness (N = 0,1,2,3,4,5,6); default 5 (see below)" << endl; cerr << " -F, --formant Enable formant preservation when pitch shifting" << endl; cerr << endl; - cerr << "The remaining options fine-tune the processing mode and stretch algorithm." << endl; - cerr << "These are mostly included for test purposes; the default settings and standard" << endl; - cerr << "crispness parameter are intended to provide the best sounding set of options" << endl; - cerr << "for most situations. The default is to use none of these options." << endl; + cerr << " This option attempts to keep the formant envelope unchanged when changing" << endl; + cerr << " the pitch, retaining the original timbre of vocals and instruments in a" << endl; + cerr << " recognisable way." << endl; cerr << endl; - cerr << " -R, --realtime Select realtime mode (implies --no-threads)." << endl; - cerr << " This utility does not do realtime stream processing;" << endl; - cerr << " the option merely selects realtime mode for the" << endl; - cerr << " stretcher it uses" << endl; - cerr << " --no-threads No extra threads regardless of CPU and channel count" << endl; - cerr << " --threads Assume multi-CPU even if only one CPU is identified" << endl; - cerr << " --no-transients Disable phase resynchronisation at transients" << endl; - cerr << " --bl-transients Band-limit phase resync to extreme frequencies" << endl; - cerr << " --no-lamination Disable phase lamination" << endl; - cerr << " --window-long Use longer processing window (actual size may vary)" << endl; - cerr << " --window-short Use shorter processing window" << endl; - cerr << " --smoothing Apply window presum and time-domain smoothing" << endl; - cerr << " --detector-perc Use percussive transient detector (as in pre-1.5)" << endl; - cerr << " --detector-soft Use soft transient detector" << endl; - cerr << " --pitch-hq In RT mode, use a slower, higher quality pitch shift" << endl; - cerr << " --centre-focus Preserve focus of centre material in stereo" << endl; - cerr << " (at a cost in width and individual channel quality)" << endl; - cerr << " --ignore-clipping Ignore clipping at output; the default is to restart" << endl; - cerr << " with reduced gain if clipping occurs" << endl; - cerr << " -L, --loose [Accepted for compatibility but ignored; always off]" << endl; - cerr << " -P, --precise [Accepted for compatibility but ignored; always on]" << endl; + if (fullHelp || !isR3) { + cerr << " -c, --crisp Crispness (N = 0,1,2,3,4,5,6); default 5" << endl; + cerr << endl; + cerr << " This option only has an effect when using the R2 (faster) engine. See below" << endl; + cerr << " for details of the different levels." << endl; + cerr << endl; + } + if (fullHelp) { + cerr << "The remaining options fine-tune the processing mode and stretch algorithm." << endl; + cerr << "These are mostly included for test purposes; the default settings and standard" << endl; + cerr << "crispness parameter are intended to provide the best sounding set of options" << endl; + cerr << "for most situations. The default is to use none of these options." << endl; + cerr << endl; + cerr << " -R, --realtime Select realtime mode (implies --no-threads)." << endl; + cerr << " This utility does not do realtime stream processing;" << endl; + cerr << " the option merely selects realtime mode for the" << endl; + cerr << " stretcher it uses" << endl; + cerr << " --no-threads No extra threads regardless of CPU and channel count" << endl; + cerr << " --threads Assume multi-CPU even if only one CPU is identified" << endl; + cerr << " --no-transients Disable phase resynchronisation at transients" << endl; + cerr << " --bl-transients Band-limit phase resync to extreme frequencies" << endl; + cerr << " --no-lamination Disable phase lamination" << endl; + cerr << " --window-long Use longer processing window (actual size may vary)" << endl; + cerr << " --window-short Use shorter processing window" << endl; + cerr << " --smoothing Apply window presum and time-domain smoothing" << endl; + cerr << " --detector-perc Use percussive transient detector (as in pre-1.5)" << endl; + cerr << " --detector-soft Use soft transient detector" << endl; + cerr << " --pitch-hq In RT mode, use a slower, higher quality pitch shift" << endl; + cerr << " --centre-focus Preserve focus of centre material in stereo" << endl; + cerr << " (at a cost in width and individual channel quality)" << endl; + cerr << " --ignore-clipping Ignore clipping at output; the default is to restart" << endl; + cerr << " with reduced gain if clipping occurs" << endl; + cerr << " -L, --loose [Accepted for compatibility but ignored; always off]" << endl; + cerr << " -P, --precise [Accepted for compatibility but ignored; always on]" << endl; + cerr << endl; + cerr << " -d, --debug Select debug level (N = 0,1,2,3); default 0, full 3" << endl; + cerr << " (N.B. debug level 3 includes audible ticks in output)" << endl; + cerr << endl; + } + cerr << "The following options are for output control and administration:" << endl; cerr << endl; - cerr << " -d, --debug Select debug level (N = 0,1,2,3); default 0, full 3" << endl; - cerr << " (N.B. debug level 3 includes audible ticks in output)" << endl; cerr << " -q, --quiet Suppress progress output" << endl; - cerr << endl; cerr << " -V, --version Show version number and exit" << endl; - cerr << " -h, --help Show this help" << endl; - cerr << endl; - cerr << "\"Crispness\" levels:" << endl; - cerr << " -c 0 equivalent to --no-transients --no-lamination --window-long" << endl; - cerr << " -c 1 equivalent to --detector-soft --no-lamination --window-long (for piano)" << endl; - cerr << " -c 2 equivalent to --no-transients --no-lamination" << endl; - cerr << " -c 3 equivalent to --no-transients" << endl; - cerr << " -c 4 equivalent to --bl-transients" << endl; - cerr << " -c 5 default processing options" << endl; - cerr << " -c 6 equivalent to --no-lamination --window-short (may be good for drums)" << endl; + cerr << " -h, --help Show the normal help output" << endl; + cerr << " -H, --full-help Show the full help output" << endl; cerr << endl; + if (fullHelp) { + cerr << "\"Crispness\" levels:" << endl; + cerr << " -c 0 equivalent to --no-transients --no-lamination --window-long" << endl; + cerr << " -c 1 equivalent to --detector-soft --no-lamination --window-long (for piano)" << endl; + cerr << " -c 2 equivalent to --no-transients --no-lamination" << endl; + cerr << " -c 3 equivalent to --no-transients" << endl; + cerr << " -c 4 equivalent to --bl-transients" << endl; + cerr << " -c 5 default processing options" << endl; + cerr << " -c 6 equivalent to --no-lamination --window-short (may be good for drums)" << endl; + cerr << endl; + } else { + cerr << "Numerous other options are available, mostly for tuning the behaviour of" << endl; + cerr << "the R2 engine. Run \"" << myName << " --full-help\" for details." << endl; + cerr << endl; + } return 2; } @@ -323,6 +368,23 @@ int main(int argc, char **argv) cerr << "ERROR: Invalid time ratio " << ratio << endl; return 1; } + + if (faster && finer) { + cerr << "WARNING: Both fast (R2) and fine (R3) engines selected, will use default for" << endl; + cerr << " this tool (" << (isR3 ? "fine" : "fast") << ")" << endl; + faster = false; + finer = false; + } + + if (isR3) { + if (!faster) { + finer = true; + } + } else { + if (!finer) { + faster = true; + } + } if (crispness >= 0 && crispchanged) { cerr << "WARNING: Both crispness option and transients, lamination or window options" << endl; @@ -352,17 +414,22 @@ int main(int argc, char **argv) }; if (!quiet) { - cerr << "Using crispness level: " << crispness << " ("; - switch (crispness) { - case 0: cerr << "Mushy"; break; - case 1: cerr << "Piano"; break; - case 2: cerr << "Smooth"; break; - case 3: cerr << "Balanced multitimbral mixture"; break; - case 4: cerr << "Unpitched percussion with stable notes"; break; - case 5: cerr << "Crisp monophonic instrumental"; break; - case 6: cerr << "Unpitched solo percussion"; break; + if (finer) { + cerr << "Using R3 (finer) engine" << endl; + } else { + cerr << "Using R2 (faster) engine" << endl; + cerr << "Using crispness level: " << crispness << " ("; + switch (crispness) { + case 0: cerr << "Mushy"; break; + case 1: cerr << "Piano"; break; + case 2: cerr << "Smooth"; break; + case 3: cerr << "Balanced multitimbral mixture"; break; + case 4: cerr << "Unpitched percussion with stable notes"; break; + case 5: cerr << "Crisp monophonic instrumental"; break; + case 6: cerr << "Unpitched solo percussion"; break; + } + cerr << ")" << endl; } - cerr << ")" << endl; } std::map timeMap; @@ -502,10 +569,9 @@ int main(int argc, char **argv) } RubberBandStretcher::Options options = 0; - - //!!! - cerr << "\n\n\n\n\n*** WARNING - THIS IS A TEST VERSION ONLY\n\n\n\n\n" << endl; - options = RubberBandStretcher::OptionEngineFiner; + if (finer) { + options = RubberBandStretcher::OptionEngineFiner; + } if (realtime) options |= RubberBandStretcher::OptionProcessRealTime; if (!lamination) options |= RubberBandStretcher::OptionPhaseIndependent; diff --git a/meson.build b/meson.build index 5dd0492..282cf8f 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project( 'Rubber Band Library', 'c', 'cpp', - version: '3.0.0', + version: '3.0.0-pre', license: 'GPL-2.0-or-later', default_options: [ 'cpp_std=c++11', @@ -448,6 +448,7 @@ if cpp.get_id() == 'msvc' endif rubberband_library_name = 'rubberband' rubberband_program_name = 'rubberband-program' + rubberband_program_name_r3 = 'rubberband-program-r3' rubberband_ladspa_name = 'ladspa-rubberband' rubberband_lv2_name = 'lv2-rubberband' rubberband_vamp_name = 'vamp-rubberband' @@ -457,6 +458,7 @@ else rubberband_library_name = 'rubberband' rubberband_dynamic_name = 'rubberband' rubberband_program_name = 'rubberband' + rubberband_program_name_r3 = 'rubberband-r3' rubberband_ladspa_name = 'ladspa-rubberband' rubberband_lv2_name = 'lv2-rubberband' rubberband_vamp_name = 'vamp-rubberband' @@ -686,8 +688,8 @@ else endif if have_sndfile - target_summary += { 'Command-line utility': [ true, 'Name: ' + rubberband_program_name ] } - message('Will build command-line utility') + message('Will build command-line utilities') + target_summary += { 'Command-line utility (R2)': [ true, 'Name: ' + rubberband_program_name ] } rubberband_program = executable( rubberband_program_name, program_sources, @@ -705,9 +707,28 @@ if have_sndfile ], install: true, ) + target_summary += { 'Command-line utility (R3)': [ true, 'Name: ' + rubberband_program_name_r3 ] } + rubberband_program_r3 = executable( + rubberband_program_name_r3, + program_sources, + include_directories: general_include_dirs, + cpp_args: general_compile_args, + c_args: general_compile_args, + link_args: [ + arch_flags, + feature_libraries, + ], + dependencies: [ + rubberband_objlib_dep, + general_dependencies, + sndfile_dep, + ], + install: true, + ) else - target_summary += { 'Command-line utility': false } - message('Not building command-line utility: libsndfile dependency not found') + message('Not building command-line utilities: libsndfile dependency not found') + target_summary += { 'Command-line utility (R2)': false } + target_summary += { 'Command-line utility (R3)': false } endif if have_boost_unit_test