diff options
author | Bill Cox <waywardgeek@@gmail.com> | 2011-10-25 08:16:05 -0400 |
---|---|---|
committer | Bill Cox <waywardgeek@@gmail.com> | 2011-10-25 08:16:05 -0400 |
commit | 0b643e2b34b0363b940012258c329ed397dff39d (patch) | |
tree | 71f970aa6db4eabfc04f1a8ee6d081a8e1540aa9 | |
parent | f37d597f3aadc825402b4fa1c253a5010ecd636a (diff) | |
parent | 500b87055c31ddf6d21c676f896de535e0d25734 (diff) | |
download | sonic-0b643e2b34b0363b940012258c329ed397dff39d.tar.gz |
Merge branch 'master' of github.com:waywardgeek/sonic
-rw-r--r-- | Makefile | 15 | ||||
-rw-r--r-- | debian/control | 2 | ||||
-rwxr-xr-x | doc/post | 1 | ||||
-rw-r--r-- | main.c | 6 | ||||
-rw-r--r-- | samples/README | 25 | ||||
-rw-r--r-- | samples/espeak_s450.flac | bin | 155738 -> 0 bytes | |||
-rw-r--r-- | samples/espeak_s450.wav | bin | 0 -> 246730 bytes | |||
-rw-r--r-- | samples/espeak_sonic.flac | bin | 145232 -> 0 bytes | |||
-rw-r--r-- | samples/espeak_sonic.wav | bin | 0 -> 247582 bytes | |||
-rw-r--r-- | samples/sonic.flac | bin | 531914 -> 0 bytes | |||
-rw-r--r-- | samples/sonic.wav | bin | 0 -> 1046244 bytes | |||
-rw-r--r-- | samples/soundstretch.flac | bin | 536928 -> 0 bytes | |||
-rw-r--r-- | samples/soundstretch.wav | bin | 0 -> 1044978 bytes | |||
-rw-r--r-- | samples/stereo_test.flac | bin | 457556 -> 0 bytes | |||
-rw-r--r-- | samples/stereo_test.wav | bin | 0 -> 942124 bytes | |||
-rw-r--r-- | samples/talking.flac | bin | 1044049 -> 0 bytes | |||
-rw-r--r-- | samples/talking.wav | bin | 0 -> 2045402 bytes | |||
-rw-r--r-- | samples/talking_2x.flac | bin | 518543 -> 0 bytes | |||
-rw-r--r-- | samples/talking_2x.wav | bin | 0 -> 1021370 bytes | |||
-rw-r--r-- | samples/twosineperiods.flac | bin | 8396 -> 0 bytes | |||
-rw-r--r-- | samples/twosineperiods.wav | bin | 0 -> 364 bytes | |||
-rw-r--r-- | wave.c | 337 | ||||
-rw-r--r-- | wave.h | 2 |
23 files changed, 319 insertions, 69 deletions
@@ -2,16 +2,16 @@ # safe. We call malloc, and older Linux versions only linked in the thread-safe # malloc if -pthread is specified. -#CFLAGS=-Wall -g -ansi -fPIC -pthread -CFLAGS=-Wall -O2 -ansi -fPIC -pthread +CFLAGS=-Wall -g -ansi -fPIC -pthread +#CFLAGS=-Wall -O2 -ansi -fPIC -pthread LIB_TAG=0.1.18 CC=gcc PREFIX=/usr -all: sonic libsonic.so.$(LIB_TAG) libsonic-$(LIB_TAG).a +all: sonic libsonic.so.$(LIB_TAG) libsonic.a sonic: wave.o main.o libsonic.so.$(LIB_TAG) - $(CC) $(CFLAGS) -lsndfile libsonic.so.$(LIB_TAG) -o sonic wave.o main.o + $(CC) $(CFLAGS) libsonic.so.$(LIB_TAG) -o sonic wave.o main.o sonic.o: sonic.c sonic.h $(CC) $(CFLAGS) -c sonic.c @@ -27,13 +27,15 @@ libsonic.so.$(LIB_TAG): sonic.o ln -sf libsonic.so.$(LIB_TAG) libsonic.so ln -sf libsonic.so.$(LIB_TAG) libsonic.so.0 -libsonic-$(LIB_TAG).a: sonic.o +libsonic.a: sonic.o + $(AR) cqs libsonic.a sonic.o install: sonic libsonic.so.$(LIB_TAG) sonic.h install -d $(DESTDIR)$(PREFIX)/bin $(DESTDIR)$(PREFIX)/include $(DESTDIR)$(PREFIX)/lib install sonic $(DESTDIR)$(PREFIX)/bin install sonic.h $(DESTDIR)$(PREFIX)/include install libsonic.so.$(LIB_TAG) $(DESTDIR)$(PREFIX)/lib + install libsonic.a $(DESTDIR)$(LIBDIR) ln -sf libsonic.so.$(LIB_TAG) $(DESTDIR)$(PREFIX)/lib/libsonic.so ln -sf libsonic.so.$(LIB_TAG) $(DESTDIR)$(PREFIX)/lib/libsonic.so.0 @@ -43,6 +45,7 @@ uninstall: rm -f $(DESTDIR)$(PREFIX)/lib/libsonic.so.$(LIB_TAG) rm -f $(DESTDIR)$(PREFIX)/lib/libsonic.so rm -f $(DESTDIR)$(PREFIX)/lib/libsonic.so.0 + rm -f $(DESTDIR)$(LIBDIR)/libsonic.a clean: - rm -f *.o sonic libsonic.so* + rm -f *.o sonic libsonic.so* libsonic.a diff --git a/debian/control b/debian/control index 500cb40..caeba95 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: sonic Section: sound Priority: extra Maintainer: Bill Cox <waywardgeek@gmail.com> -Build-Depends: libsndfile1-dev, debhelper (>= 7.0.50~) +Build-Depends: debhelper (>= 7.0.50~) Standards-Version: 3.9.1 Homepage: http://vinux-project.org/sonic Vcs-Browser: http://vinux-project.org/gitweb/?p=sonic.git;a=summary @@ -14,6 +14,5 @@ if [ -f ../version ]; then scp $sourceTarball root@dev.vinux-project.org:/var/www/dev.vinux-project.org/sonic/download/$destTarball fi fi -flac -d ../samples/sonic.flac ../samples/soundstretch.flac scp $files root@dev.vinux-project.org:/var/www/dev.vinux-project.org/sonic rm ../samples/*.wav index.html @@ -84,12 +84,6 @@ int main( int sampleRate, numChannels; int xArg = 1; - if(argc < 2 || *(argv[xArg]) != '-') { - fprintf(stderr, "You must provide at least one option to change speed," - "pitch, or volume.\n"); - usage(); - return 1; - } while(xArg < argc && *(argv[xArg]) == '-') { if(!strcmp(argv[xArg], "-c")) { emulateChordPitch = 1; diff --git a/samples/README b/samples/README index 33c5c03..a9c630a 100644 --- a/samples/README +++ b/samples/README @@ -1,35 +1,34 @@ -These flac files show how Sonic performs at increasing speech rates. All sound -sampels are in the public domain. The 'flac' lossless compression utilitiy was -used to reduce the size of the wave files. +These wav files show how Sonic performs at increasing speech rates. All sound +sampels are in the public domain. -sonic.flac +sonic.wav This is a sonic 2X sped-up version of a public domain librivox.org recording, from the audiobook "Princess of Mars". -soundtouch.flac -This is the same recording as sonic.flac, but sped up using soundtouch, which +soundtouch.wav +This is the same recording as sonic.wav, but sped up using soundtouch, which uses WSOLA rather than the sonic algorithm. Even at 2X speed up, you should be able to hear the characteristic WSOLA distortion relative to the sonic version. -talking.flac +talking.wav This is my father talking, using a decent microphone and 44KHz sample rate. -talking_2x.flac +talking_2x.wav This is his voice sped up by 2X using Sonic. -espeak_s450.flac +espeak_s450.wav Sonic also performs well at increasing the speed of synthesized speech. -espeak_s450.flac was generated using 'espeak -s450 -f test1.txt -w -espeak_s450.flac'. This is the highest speed currently supported by espeak, +espeak_s450.wav was generated using 'espeak -s450 -f test1.txt -w +espeak_s450.wav'. This is the highest speed currently supported by espeak, though Sonic can speed up espeak to much faster rates. -espeak_sonic.flac +espeak_sonic.wav This was generated with 'espeak -f test1.txt -w out.wav; sonic 2.6 out.wav espeak_sonic.wav'. Sonic sped it up 2.6X, which is about the same speed as espeak at -s450. I personally feel that the sonic sped up sample sounds better than espeak at -s450. -twosineperiods.flac +twosineperiods.wav This is just two sine periods, which is too short to hear. However, it's useful for making sure the flush function works correctly. A 2-X speedup should result in one sine period with no distortion. diff --git a/samples/espeak_s450.flac b/samples/espeak_s450.flac Binary files differdeleted file mode 100644 index 123f941..0000000 --- a/samples/espeak_s450.flac +++ /dev/null diff --git a/samples/espeak_s450.wav b/samples/espeak_s450.wav Binary files differnew file mode 100644 index 0000000..4239477 --- /dev/null +++ b/samples/espeak_s450.wav diff --git a/samples/espeak_sonic.flac b/samples/espeak_sonic.flac Binary files differdeleted file mode 100644 index a6a05b5..0000000 --- a/samples/espeak_sonic.flac +++ /dev/null diff --git a/samples/espeak_sonic.wav b/samples/espeak_sonic.wav Binary files differnew file mode 100644 index 0000000..cffdb96 --- /dev/null +++ b/samples/espeak_sonic.wav diff --git a/samples/sonic.flac b/samples/sonic.flac Binary files differdeleted file mode 100644 index e7f0f07..0000000 --- a/samples/sonic.flac +++ /dev/null diff --git a/samples/sonic.wav b/samples/sonic.wav Binary files differnew file mode 100644 index 0000000..bc55109 --- /dev/null +++ b/samples/sonic.wav diff --git a/samples/soundstretch.flac b/samples/soundstretch.flac Binary files differdeleted file mode 100644 index fca9f3d..0000000 --- a/samples/soundstretch.flac +++ /dev/null diff --git a/samples/soundstretch.wav b/samples/soundstretch.wav Binary files differnew file mode 100644 index 0000000..e0226d5 --- /dev/null +++ b/samples/soundstretch.wav diff --git a/samples/stereo_test.flac b/samples/stereo_test.flac Binary files differdeleted file mode 100644 index 47b00a8..0000000 --- a/samples/stereo_test.flac +++ /dev/null diff --git a/samples/stereo_test.wav b/samples/stereo_test.wav Binary files differnew file mode 100644 index 0000000..6dfc809 --- /dev/null +++ b/samples/stereo_test.wav diff --git a/samples/talking.flac b/samples/talking.flac Binary files differdeleted file mode 100644 index 070f4b3..0000000 --- a/samples/talking.flac +++ /dev/null diff --git a/samples/talking.wav b/samples/talking.wav Binary files differnew file mode 100644 index 0000000..1df692e --- /dev/null +++ b/samples/talking.wav diff --git a/samples/talking_2x.flac b/samples/talking_2x.flac Binary files differdeleted file mode 100644 index 2c127b1..0000000 --- a/samples/talking_2x.flac +++ /dev/null diff --git a/samples/talking_2x.wav b/samples/talking_2x.wav Binary files differnew file mode 100644 index 0000000..e20f71f --- /dev/null +++ b/samples/talking_2x.wav diff --git a/samples/twosineperiods.flac b/samples/twosineperiods.flac Binary files differdeleted file mode 100644 index 482fbe6..0000000 --- a/samples/twosineperiods.flac +++ /dev/null diff --git a/samples/twosineperiods.wav b/samples/twosineperiods.wav Binary files differnew file mode 100644 index 0000000..c71dfff --- /dev/null +++ b/samples/twosineperiods.wav @@ -21,92 +21,337 @@ /* This file supports read/write wave files. */ +#include <stdio.h> #include <stdlib.h> -#include <limits.h> #include <string.h> -#include <sndfile.h> #include "wave.h" +#define WAVE_BUF_LEN 4096 + struct waveFileStruct { - SNDFILE *soundFile; int numChannels; + int sampleRate; + FILE *soundFile; + int bytesWritten; /* The number of bytes written so far, including header */ + int failed; + int isInput; }; -/* Open the file for reading. Also determine it's sample rate. */ +/* Write a string to a file. */ +static void writeBytes( + waveFile file, + void *bytes, + int length) +{ + size_t bytesWritten; + + if(file->failed) { + return; + } + bytesWritten = fwrite(bytes, sizeof(char), length, file->soundFile); + if(bytesWritten != length) { + fprintf(stderr, "Unable to write to output file"); + file->failed = 1; + } + file->bytesWritten += bytesWritten; +} + +/* Write a string to a file. */ +static void writeString( + waveFile file, + char *string) +{ + writeBytes(file, string, strlen(string)); +} + +/* Write an integer to a file in little endian order. */ +static void writeInt( + waveFile file, + int value) +{ + char bytes[4]; + int i; + + for(i = 0; i < 4; i++) { + bytes[i] = value; + value >>= 8; + } + writeBytes(file, bytes, 4); +} + +/* Write a short integer to a file in little endian order. */ +static void writeShort( + waveFile file, + short value) +{ + char bytes[2]; + int i; + + for(i = 0; i < 2; i++) { + bytes[i] = value; + value >>= 8; + } + writeBytes(file, bytes, 2); +} + +/* Read bytes from the input file. Return the number of bytes actually read. */ +static int readBytes( + waveFile file, + void *bytes, + int length) +{ + if(file->failed) { + return 0; + } + return fread(bytes, sizeof(char), length, file->soundFile); +} + +/* Read an exact number of bytes from the input file. */ +static void readExactBytes( + waveFile file, + void *bytes, + int length) +{ + int numRead; + + if(file->failed) { + return; + } + numRead = fread(bytes, sizeof(char), length, file->soundFile); + if(numRead != length) { + fprintf(stderr, "Failed to read requested bytes from input file\n"); + file->failed = 1; + } +} + +/* Read an integer from the input file */ +static int readInt( + waveFile file) +{ + unsigned char bytes[4]; + int value = 0, i; + + readExactBytes(file, bytes, 4); + for(i = 3; i >= 0; i--) { + value <<= 8; + value |= bytes[i]; + } + return value; +} + +/* Read a short from the input file */ +static int readShort( + waveFile file) +{ + unsigned char bytes[2]; + int value = 0, i; + + readExactBytes(file, bytes, 2); + for(i = 1; i >= 0; i--) { + value <<= 8; + value |= bytes[i]; + } + return value; +} + +/* Read a string from the input and compare it to an expected string. */ +static void expectString( + waveFile file, + char *expectedString) +{ + char buf[11]; /* Be sure that we never call with a longer string */ + int length = strlen(expectedString); + + if(length > 10) { + fprintf(stderr, "Internal error: expected string too long\n"); + file->failed = 1; + } else { + readExactBytes(file, buf, length); + buf[length] = '\0'; + if(strcmp(expectedString, buf)) { + fprintf(stderr, "Unsupported wave file format\n"); + file->failed = 1; + } + } +} + +/* Write the header of the wave file. */ +static void writeHeader( + waveFile file, + int sampleRate) +{ + /* write the wav file per the wav file format */ + writeString(file, "RIFF"); /* 00 - RIFF */ + /* We have to fseek and overwrite this later when we close the file because */ + /* we don't know how big it is until then. */ + writeInt(file, 36 /* + dataLength */); /* 04 - how big is the rest of this file? */ + writeString(file, "WAVE"); /* 08 - WAVE */ + writeString(file, "fmt "); /* 12 - fmt */ + writeInt(file, 16); /* 16 - size of this chunk */ + writeShort(file, 1); /* 20 - what is the audio format? 1 for PCM = Pulse Code Modulation */ + writeShort(file, 1); /* 22 - mono or stereo? 1 or 2? (or 5 or ???) */ + writeInt(file, sampleRate); /* 24 - samples per second (numbers per second) */ + writeInt(file, sampleRate * 2); /* 28 - bytes per second */ + writeShort(file, 2); /* 32 - # of bytes in one sample, for all channels */ + writeShort(file, 16); /* 34 - how many bits in a sample(number)? usually 16 or 24 */ + writeString(file, "data"); /* 36 - data */ + writeInt(file, 0); /* 40 - how big is this data chunk */ +} + +/* Read the header of the wave file. */ +static int readHeader( + waveFile file) +{ + int data; + + expectString(file, "RIFF"); + data = readInt(file); /* 04 - how big is the rest of this file? */ + expectString(file, "WAVE"); /* 08 - WAVE */ + expectString(file, "fmt "); /* 12 - fmt */ + data = readInt(file); /* 16 - size of this chunk */ + if(data != 16) { + fprintf(stderr, "Only basic wave files are supported\n"); + return 0; + } + data = readShort(file); /* 20 - what is the audio format? 1 for PCM = Pulse Code Modulation */ + if(data != 1) { + fprintf(stderr, "Only PCM wave files are supported\n"); + return 0; + } + file->numChannels = readShort(file); /* 22 - mono or stereo? 1 or 2? (or 5 or ???) */ + file->sampleRate = readInt(file); /* 24 - samples per second (numbers per second) */ + readInt(file); /* 28 - bytes per second */ + readShort(file); /* 32 - # of bytes in one sample, for all channels */ + data = readShort(file); /* 34 - how many bits in a sample(number)? usually 16 or 24 */ + if(data != 16) { + fprintf(stderr, "Only 16 bit PCM wave files are supported\n"); + return 0; + } + expectString(file, "data"); /* 36 - data */ + readInt(file); /* 40 - how big is this data chunk */ + return 1; +} + +/* Close the input or output file and free the waveFile. */ +static void closeFile( + waveFile file) +{ + FILE *soundFile = file->soundFile; + + if(soundFile != NULL) { + fclose(soundFile); + file->soundFile = NULL; + } + free(file); +} + +/* Open a 16-bit little-endian wav file for reading. It may be mono or stereo. */ waveFile openInputWaveFile( char *fileName, int *sampleRate, int *numChannels) { - SF_INFO info; - SNDFILE *soundFile; waveFile file; + FILE *soundFile = fopen(fileName, "rb"); - info.format = 0; - soundFile = sf_open(fileName, SFM_READ, &info); if(soundFile == NULL) { - fprintf(stderr, "Unable to open wave file %s: %s\n", fileName, sf_strerror(NULL)); + fprintf(stderr, "Unable to open wave file %s for reading\n", fileName); return NULL; } file = (waveFile)calloc(1, sizeof(struct waveFileStruct)); file->soundFile = soundFile; - file->numChannels = info.channels; - *sampleRate = info.samplerate; - *numChannels = info.channels; - printf("Frames = %ld, sample rate = %d, channels = %d, format = %d\n", - info.frames, info.samplerate, info.channels, info.format); + file->isInput = 1; + if(!readHeader(file)) { + closeFile(file); + return NULL; + } + *sampleRate = file->sampleRate; + *numChannels = file->numChannels; return file; } -/* Open the file for reading. */ +/* Open a 16-bit little-endian wav file for writing. It may be mono or stereo. */ waveFile openOutputWaveFile( char *fileName, int sampleRate, int numChannels) { - SF_INFO info; - SNDFILE *soundFile; waveFile file; + FILE *soundFile = fopen(fileName, "wb"); - info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; - info.samplerate = sampleRate; - info.channels = numChannels; - soundFile = sf_open(fileName, SFM_WRITE, &info); if(soundFile == NULL) { - fprintf(stderr, "Unable to open wave file %s: %s\n", fileName, sf_strerror(NULL)); + fprintf(stderr, "Unable to open wave file %s for writing\n", fileName); return NULL; } file = (waveFile)calloc(1, sizeof(struct waveFileStruct)); file->soundFile = soundFile; + file->sampleRate = sampleRate; file->numChannels = numChannels; + writeHeader(file, sampleRate); + if(file->failed) { + closeFile(file); + return NULL; + } return file; } /* Close the sound file. */ -void closeWaveFile( +int closeWaveFile( waveFile file) { - SNDFILE *soundFile = file->soundFile; + FILE *soundFile = file->soundFile; + int passed = 1; - sf_close(soundFile); - free(file); + if(!file->isInput) { + if(fseek(soundFile, 4, SEEK_SET) != 0) { + fprintf(stderr, "Failed to seek on input file.\n"); + passed = 0; + } else { + /* Now update the file to have the correct size. */ + writeInt(file, file->bytesWritten - 8); + if(file->failed) { + fprintf(stderr, "Failed to write wave file size.\n"); + passed = 0; + } + if(fseek(soundFile, 40, SEEK_SET) != 0) { + fprintf(stderr, "Failed to seek on input file.\n"); + passed = 0; + } else { + /* Now update the file to have the correct size. */ + writeInt(file, file->bytesWritten - 48); + if(file->failed) { + fprintf(stderr, "Failed to write wave file size.\n"); + passed = 0; + } + } + } + } + closeFile(file); + return passed; } -/* Read from the wave file. */ +/* Read from the wave file. Return the number of samples read. */ int readFromWaveFile( waveFile file, short *buffer, int maxSamples) { - SNDFILE *soundFile = file->soundFile; - int samplesRead; - int numChannels = file->numChannels; + int i, bytesRead, samplesRead; + int bytePos = 0; + unsigned char bytes[WAVE_BUF_LEN]; + short sample; - samplesRead = sf_read_short(soundFile, buffer, maxSamples*numChannels); - if(samplesRead <= 0) { - return 0; + if(maxSamples*file->numChannels*2 > WAVE_BUF_LEN) { + maxSamples = WAVE_BUF_LEN/(file->numChannels*2); + } + bytesRead = readBytes(file, bytes, maxSamples*file->numChannels*2); + samplesRead = bytesRead/(file->numChannels*2); + for(i = 0; i < samplesRead*file->numChannels; i++) { + sample = bytes[bytePos++]; + sample |= (unsigned int)bytes[bytePos++] << 8; + *buffer++ = sample; } - return samplesRead/numChannels; + return samplesRead; } /* Write to the wave file. */ @@ -115,13 +360,23 @@ int writeToWaveFile( short *buffer, int numSamples) { - SNDFILE *soundFile = file->soundFile; - int numWritten; + int i; + int bytePos = 0; + unsigned char bytes[WAVE_BUF_LEN]; + short sample; + int total = numSamples*file->numChannels; - numWritten = sf_write_short(soundFile, buffer, numSamples*file->numChannels); - if(numWritten != numSamples*file->numChannels) { - fprintf(stderr, "Unable to write wave file.\n"); - return 0; + for(i = 0; i < total; i++) { + if(bytePos == WAVE_BUF_LEN) { + writeBytes(file, bytes, bytePos); + bytePos = 0; + } + sample = buffer[i]; + bytes[bytePos++] = sample; + bytes[bytePos++] = sample >> 8; } - return 1; + if(bytePos != 0) { + writeBytes(file, bytes, bytePos); + } + return file->failed; } @@ -24,6 +24,6 @@ typedef struct waveFileStruct *waveFile; waveFile openInputWaveFile(char *fileName, int *sampleRate, int *numChannels); waveFile openOutputWaveFile(char *fileName, int sampleRate, int numChannels); -void closeWaveFile(waveFile file); +int closeWaveFile(waveFile file); int readFromWaveFile(waveFile file, short *buffer, int maxSamples); int writeToWaveFile(waveFile file, short *buffer, int numSamples); |