From f151c6ff228d08e8ca540ac7e44a3cc15f4d5da0 Mon Sep 17 00:00:00 2001 From: David Bryant Date: Wed, 27 Nov 2019 16:32:57 -0800 Subject: [PATCH] - add command-line option to sinusoidally cycle through ratio range - update to version 0.2 (README and main.c) --- README | 12 +++++++++++- main.c | 25 +++++++++++++++++++------ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/README b/README index 556401e..4390f39 100644 --- a/README +++ b/README @@ -40,13 +40,20 @@ properly play these files, and audio editing programs will likely import them correctly (by resampling), but it is possible that some applications will barf on them. +For version 0.2 a new option was added to cycle through the full possible +ratio range in a sinusoidal pattern, starting at 1.0, and either going +up (-c) or down (-cc) first. In this case any specified ratio is ignored +(except if the -s option is also specified to scale the sampling rate). +The total period is fixed at 2π seconds, at which point the output will +again be exactly aligned with the input. + To build the demo app: $ gcc -O2 *.c -o audio-stretch The "help" display from the demo app: - AUDIO-STRETCH Time Domain Harmonic Scaling Demo Version 0.1 + AUDIO-STRETCH Time Domain Harmonic Scaling Demo Version 0.2 Copyright (c) 2019 David Bryant. All Rights Reserved. Usage: AUDIO-STRETCH [-options] infile.wav outfile.wav @@ -54,6 +61,8 @@ The "help" display from the demo app: Options: -r = stretch ratio (0.5 to 2.0, default = 1.0) -u = upper freq period limit (default = 333 Hz) -l = lower freq period limit (default = 55 Hz) + -c = cycle through all ratios, starting higher + -cc = cycle through all ratios, starting lower -s = scale rate to preserve duration (not pitch) -f = fast pitch detection (default >= 32 kHz) -n = normal pitch detection (default < 32 kHz) @@ -68,6 +77,7 @@ Notes: 1. The program will handle only mono or stereo files in the WAV format. The audio must be 16-bit PCM and the acceptable sampling rates are from 8,000 to 48,000 Hz. Any additional RIFF info in the WAV file will be discarded. + The command-line program is only for little-endian architectures. 2. For stereo files, the pitch detection is done on a mono conversion of the audio, but the scaling transformation is done on the independent channels. diff --git a/main.c b/main.c index 0f21b4b..d994ded 100644 --- a/main.c +++ b/main.c @@ -14,11 +14,12 @@ #include #include #include +#include #include "stretch.h" static const char *sign_on = "\n" -" AUDIO-STRETCH Time Domain Harmonic Scaling Demo Version 0.1\n" +" AUDIO-STRETCH Time Domain Harmonic Scaling Demo Version 0.2\n" " Copyright (c) 2019 David Bryant. All Rights Reserved.\n\n"; static const char *usage = @@ -26,6 +27,8 @@ static const char *usage = " Options: -r = stretch ratio (0.5 to 2.0, default = 1.0)\n" " -u = upper freq period limit (default = 333 Hz)\n" " -l = lower freq period limit (default = 55 Hz)\n" +" -c = cycle through all ratios, starting higher\n" +" -cc = cycle through all ratios, starting lower\n" " -s = scale rate to preserve duration (not pitch)\n" " -f = fast pitch detection (default >= 32 kHz)\n" " -n = normal pitch detection (default < 32 kHz)\n" @@ -71,7 +74,7 @@ static int verbose_mode, quiet_mode; int main (argc, argv) int argc; char **argv; { - int asked_help = 0, overwrite = 0, scale_rate = 0, force_fast = 0, force_normal = 0, fast_mode, scaled_rate; + int asked_help = 0, overwrite = 0, scale_rate = 0, force_fast = 0, force_normal = 0, cycle_ratio = 0; int upper_frequency = 333, lower_frequency = 55, min_period, max_period; int samples_to_process, insamples = 0, outsamples = 0; char *infilename = NULL, *outfilename = NULL; @@ -130,6 +133,10 @@ int main (argc, argv) int argc; char **argv; scale_rate = 1; break; + case 'C': case 'c': + cycle_ratio++; + break; + case 'F': case 'f': force_fast = 1; break; @@ -301,15 +308,18 @@ int main (argc, argv) int argc; char **argv; min_period = WaveHeader.SampleRate / upper_frequency; max_period = WaveHeader.SampleRate / lower_frequency; - fast_mode = (force_fast || WaveHeader.SampleRate >= 32000) && !force_normal; + int fast_mode = (force_fast || WaveHeader.SampleRate >= 32000) && !force_normal; if (verbose_mode) fprintf (stderr, "initializing stretch library with period range = %d to %d, %d channels, %s\n", min_period, max_period, WaveHeader.NumChannels, fast_mode ? "fast mode" : "normal mode"); - if (!quiet_mode && ratio == 1.0) + if (!quiet_mode && ratio == 1.0 && !cycle_ratio) fprintf (stderr, "warning: a ratio of 1.0 will do nothing but copy the WAV file!\n"); + if (!quiet_mode && ratio != 1.0 && cycle_ratio && !scale_rate) + fprintf (stderr, "warning: specifying ratio with cycling doesn't do anything (unless scaling rate)\n"); + stretcher = stretch_init (min_period, max_period, WaveHeader.NumChannels, fast_mode); if (!stretcher) { @@ -324,11 +334,11 @@ int main (argc, argv) int argc; char **argv; return 1; } - scaled_rate = scale_rate ? (int)(WaveHeader.SampleRate * ratio + 0.5) : WaveHeader.SampleRate; + int scaled_rate = scale_rate ? (int)(WaveHeader.SampleRate * ratio + 0.5) : WaveHeader.SampleRate; write_pcm_wav_header (outfile, 0, WaveHeader.NumChannels, 2, scaled_rate); short *inbuffer = malloc (BUFFER_SAMPLES * WaveHeader.BlockAlign); - short *outbuffer = malloc ((BUFFER_SAMPLES * 2 + 2048) * WaveHeader.BlockAlign); + short *outbuffer = malloc ((BUFFER_SAMPLES * 2 + max_period * 3) * WaveHeader.BlockAlign); while (1) { int samples_read = fread (inbuffer, WaveHeader.BlockAlign, @@ -338,6 +348,9 @@ int main (argc, argv) int argc; char **argv; insamples += samples_read; samples_to_process -= samples_read; + if (cycle_ratio) + ratio = (sin ((double) outsamples / WaveHeader.SampleRate) * (cycle_ratio & 1 ? 0.75 : -0.75)) + 1.25; + if (samples_read) samples_generated = stretch_samples (stretcher, inbuffer, samples_read, outbuffer, ratio); else