/* * stripnuls * version 1.0, 2005-01-05 * * To compile, run * cc stripnuls.c -o stripnuls -lm * * Written by * Kjetil Torgrim Homme * University of Oslo, 2004-2005 * * Released into the public domain */ #include #include #include #include #include /* a larger array can give better efficiency, but it shouldn't be larger than BYTES_PER_SECOND */ static char nuls[4*4096]; /* silences shorter than this are left untouched. it's measured in seconds and the value must be at least one second. a lot of songs seem to use a fade-out lasting a little more than 5 seconds. a buffer of 6 seconds requires 1 MiB of memory. */ #define KEEP_SILENCE 6.0 #define BYTES_PER_SAMPLE 2 #define CHANNELS 2 #define SAMPLES_PER_SECOND 44100 #define BYTES_PER_SECOND ((double) BYTES_PER_SAMPLE*CHANNELS*SAMPLES_PER_SECOND) #define BLOCKS_PER_SECOND (BYTES_PER_SECOND / sizeof(nuls)) /* never shorten silences shorter than KEEP_SILENCE seconds. */ #define THRESHOLD ((int) (KEEP_SILENCE * BLOCKS_PER_SECOND)) static int bytecount; static int infd; static int outfd; static int verbose; static char silence[THRESHOLD][sizeof (nuls)]; static void write_data (const void *data, size_t length) { if (write (outfd, data, length) != length) { perror ("write"); exit (2); } } static void emit_nuls (int zeroes) { if (zeroes > THRESHOLD) { /* we want to make sure that silences shorter or equal to KEEP_SILENCE are unchanged. we do this by taking the square root of (the length of the unwanted silence + 1s). if we have a 7.2s silence, and KEEP_SILENCE is 6, we calculate the sqrt(2.2)+5. */ int newsize = (sqrt (zeroes / BLOCKS_PER_SECOND - (KEEP_SILENCE - 1)) + KEEP_SILENCE - 1) * BLOCKS_PER_SECOND; printf ("%d:%d@%d\n", zeroes, newsize, bytecount / sizeof (nuls) - zeroes); if (verbose) fprintf (stderr, "shrunk %.1fs into %.1fs at %.1fs\n", zeroes * sizeof (nuls) / BYTES_PER_SECOND, newsize * sizeof (nuls) / BYTES_PER_SECOND, (bytecount - zeroes * sizeof (nuls)) / BYTES_PER_SECOND); zeroes = newsize; } else { if (verbose > 1) fprintf (stderr, "too short, %.1fs at %.1fs\n", zeroes * sizeof (nuls) / BYTES_PER_SECOND, (bytecount - zeroes * sizeof (nuls)) / BYTES_PER_SECOND); } if (zeroes <= THRESHOLD) { write_data (silence, zeroes * sizeof (nuls)); } else { write_data (silence, THRESHOLD * sizeof (nuls)); zeroes -= THRESHOLD; /* we only keep the first five seconds of near silence, the rest is padded with true zeroes. */ while (zeroes--) write_data (nuls, sizeof (nuls)); } } int main (int argc, char **argv) { int zeroes = 0; int n; int in; int samples = sizeof (nuls) / sizeof (short); signed short buf[samples]; const char *progname = argv[0]; while (argc > 1 && strcmp (argv[1], "-v") == 0) { ++verbose; ++argv; --argc; } if (argc != 3) { fprintf (stderr, "Usage: %s [-v] infile outfile\n", progname); exit (64); } infd = open (argv[1], O_RDONLY); if (infd == -1) { perror(argv[1]); exit (1); } outfd = open (argv[2], O_CREAT | O_WRONLY, 0666); if (outfd == -1) { perror (argv[2]); exit (1); } /* * the samples are linear, and the highest value is 32768. * bels are logarithmic, and the loudness of the sound is * reduced by 10 for every 10 decibels. the sample value * describes the voltage level, and the power of the signal is * proportional to the square of the voltage. therefore each * halving of the sample value corresponds to -6.02 dB. * * 32768 0 dB * 16384 -6 dB * 8192 -12 dB * : : * 16 -66 dB * 8 -72 dB * 4 -78 dB * 2 -84 dB * 1 -90 dB * 0 -96 dB * * 10 dB is comparable to the sound of a human breathing 3m * away, 80 dB is a vacuum cleaner 1m away. -72 dB seems like * a reasonable and conservative cut-off. if you play music * as loud as a vacuum cleaner, you will probably not miss the * sound of breathing between tracks. * * ,-, / * /###\ | * /#####\ | sin(x) dx = -cos(x) + C * \#####/ | * \###/ / * `-' * * area of half a sine wave is -cos(pi) - -cos(0) == 2. * average power is thus 2/pi. sine waves with intensity -72 * dB will have sample peaks at 13 (0.04% of max volume). */ while ((n = read (infd, buf, sizeof (buf)))) { if (n < 0) { perror ("read"); exit (3); } bytecount += n; if (n == sizeof (buf)) { int i = 0; int sum = 0; do { if (buf[i] < 0) sum -= buf[i]; else if (buf[i] > 0) sum += buf[i]; else continue; /* we only mute average power more quiet than -72 dB, ie. sample value 8 */ if (sum > 8 * sizeof (nuls)/BYTES_PER_SAMPLE) goto not_silent; } while (++i < samples); if (verbose > 2) fprintf (stderr, "muted. sum %6d at %.3fs\n", sum, (bytecount - sizeof (nuls)) / BYTES_PER_SECOND); if (zeroes < THRESHOLD) memcpy (silence[zeroes], buf, sizeof(buf)); zeroes++; continue; } not_silent: if (zeroes) { emit_nuls (zeroes); zeroes = 0; } write_data (buf, n); } if (zeroes) emit_nuls (zeroes); return (0); }