shithub: audio-stretch

Download patch

ref: f151c6ff228d08e8ca540ac7e44a3cc15f4d5da0
parent: e6d1e3cad1eb9ef8f59afb597f5dddddb5bf86aa
author: David Bryant <[email protected]>
date: Wed Nov 27 11:32:57 EST 2019

- add command-line option to sinusoidally cycle through ratio range
- update to version 0.2 (README and main.c)

--- a/README
+++ b/README
@@ -40,6 +40,13 @@
 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
@@ -46,7 +53,7 @@
 
 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 @@
  Options:  -r<n.n> = stretch ratio (0.5 to 2.0, default = 1.0)
            -u<n>   = upper freq period limit (default = 333 Hz)
            -l<n>   = 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 @@
 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.
--- a/main.c
+++ b/main.c
@@ -14,11 +14,12 @@
 #include <stdint.h>
 #include <string.h>
 #include <stdio.h>
+#include <math.h>
 
 #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 @@
 " Options:  -r<n.n> = stretch ratio (0.5 to 2.0, default = 1.0)\n"
 "           -u<n>   = upper freq period limit (default = 333 Hz)\n"
 "           -l<n>   = 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 @@
 
 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 @@
                         scale_rate = 1;
                         break;
 
+                    case 'C': case 'c':
+                        cycle_ratio++;
+                        break;
+
                     case 'F': case 'f':
                         force_fast = 1;
                         break;
@@ -301,15 +308,18 @@
 
     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 @@
         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,
@@ -337,6 +347,9 @@
 
         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);