(Links)
Zeile 265: Zeile 265:
 
  clean:
 
  clean:
 
         -rm *~ *.raw *.core invert $(OUTFILE_WAV) $(OUTFILE_RAW)
 
         -rm *~ *.raw *.core invert $(OUTFILE_WAV) $(OUTFILE_RAW)
 +
 +
== Pascal Version - Faster-smaller-simpler ==
 +
PROGRAM invert;
 +
 +
CONST sfreq=48000; {Abtastfrequenz in Hertz}
 +
      mfreq=6000;  {Spiegelfrequenz in Hertz}
 +
      buflen=1024;
 +
      offset=128;
 +
 +
VAR infile:file;
 +
    outfile:file;
 +
    sample:ARRAY [0..buflen-1] OF byte; {Abtasttyp}
 +
    n,m,l:integer;
 +
 +
BEGIN
 +
  assign(infile,'infile.raw');
 +
  reset(infile,1);
 +
  assign(outfile,'outfile.raw');
 +
  rewrite(outfile,1);
 +
  l:=0;
 +
  REPEAT
 +
    blockread(infile,sample,sizeof(sample),m);
 +
    FOR n:=0 TO buflen-1 DO
 +
    BEGIN
 +
      sample[n]:=round((sample[n]*1.0-offset)*sin((l/(sfreq/mfreq))*2*pi)+offset);
 +
      inc(l);
 +
    END;
 +
    blockwrite(outfile,sample,m);
 +
  UNTIL eof(infile);
 +
  close(outfile);
 +
  close(infile);
 +
END.
 +
 +
== shell-script to use Pascal programm ==
 +
#!/bin/sh
 +
echo sox1
 +
sox temp.mp3 -c 1 -r 48000 -u -b infile.raw lowpass 3000
 +
echo invert
 +
./a.out
 +
echo sox2
 +
sox -r 48000  -c 1 -u -b outfile.raw output.wav lowpass 7000
 +
echo sox3
 +
sox output.wav -c 1 -r 48000 -u -b infile.raw
 +
echo invert
 +
./a.out
 +
echo sox4
 +
sox -r 48000  -c 1 -u -b outfile.raw -w output2.wav lowpass 3000
 +
  
 
== Vergleich ==
 
== Vergleich ==

Version vom 7. August 2006, 19:14 Uhr

C-Code

/*
 * This is a simple voice inverter aka spectrum inverter aka descrambler.
 *
 * It works like this: get a bunch of sample values, calculate
 * the complex spectrum using libfftw, reverse the fourier coeffcients
 * and the phase information and convert it back into the time domain.
 *
 * It is a prototype and far away from HiFi signal processing.
 * First, the conversion introduces much background noise. This problem
 * is unresolved. Second, I suppose there are phase errors that leads to
 * a crackeled sound. I recommend using a highpass filter to address
 * this problem.
 *
 * Please leave a comment under [1], if you have an idea how to fix it.
 *
 * [1] https://berlin.ccc.de/index.php?title=Simple_Voice_Inverter
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <fftw3.h>
#include <math.h>

#define REAL_PART 0
#define IMAGINARY_PART 1

double * in_r;
double * out_r;
fftw_complex * out_c;
fftw_plan plan_forward;
fftw_plan plan_backward;

long f_min_slot;
long f_max_slot;
long f_c_slot;

double window(int x, int n) {
  return 0.42-0.5*cos(2*M_PI*x/n) + 0.08 * cos(4*M_PI*x/n);
  //return 1;
}

void invert( int16_t * input_data, int16_t * output_data, long n, long STEP) {

  int i, x;
  long nc = (n >> 1)+ 1;

  // copy window into double-buf
  for( i = 0; i < n; i++ ) in_r[i] = ((double)input_data[i]) * window(i, n);

  /*** get fourier coefficients ***/
  fftw_execute ( plan_forward ); // -> nc * fft coeff in out[i][0], out[i][1]

  /*** reverse ***/

  for(x = 0; x < f_c_slot-f_min_slot; x++) {
    i = x + f_min_slot;
    long pos = f_max_slot - x;
    double tmp_r = out_c[i][REAL_PART];
    out_c[i][REAL_PART] = out_c[pos][REAL_PART];
    out_c[pos][REAL_PART] = tmp_r;
    double tmp_i = out_c[i][IMAGINARY_PART];
    out_c[i][IMAGINARY_PART] = out_c[pos][IMAGINARY_PART];
    out_c[pos][IMAGINARY_PART] = tmp_i;
  }

  /*** reconstruct ***/
  fftw_execute ( plan_backward ); // -> recovered

  /*** write to ***/
  for(i= 0; i < STEP; i++) {
    output_data[n-3/2*STEP+i] += (int16_t)(out_r[i+n/2] / n);
  }
}

void error(const char * const str) {
  fprintf(stderr, str);
  exit(1);
}

int main(int argc, char **argv) {

  FILE *in_file, *out_file;
  unsigned int n_in, n_out;
  int16_t in_buf[100000], out_buf[100000];

  unsigned int i;

  unsigned int sample_freq = 44100;
  unsigned int mirror_f_min = 50;
  unsigned int mirror_f_max = 3600;
  unsigned int step_msec = 5;
  unsigned int n = 8000;

  if(argc<3) {
    printf("invert <infile.raw> <outfile.raw> [options]\n");
    exit(1);
  }
  else {
    for(i = 3; i < argc; i++) {
      if(!strcmp(argv[i], "--sample-rate")) {
       if(argc >= i) sample_freq = atoi(argv[++i]);
       else error("can't set sample rate\n");
      }
      else if(!strcmp(argv[i], "--f-min")) {
       if(argc >= i) mirror_f_min = atoi(argv[++i]);
       else error("can't set f_min\n");
      }
      else if(!strcmp(argv[i], "--f-max")) {
       if(argc >= i) mirror_f_max = atoi(argv[++i]);
       else error("can't set f_max\n");
      }
      else if(!strcmp(argv[i], "--chunk-len")) {
       if(argc >= i) step_msec = atoi(argv[++i]);
       else error("can't set step_msec\n");
      }
      else if(!strcmp(argv[i], "--n")) {
       if(argc >= i) n = atoi(argv[++i]);
       else error("can't set step_msec\n");
      }
      else error("can't parse command line\n");
    }
  }

  unsigned int f_max = sample_freq >> 1;
  unsigned int mirror_f_c = mirror_f_min + ((mirror_f_max - mirror_f_min) >> 1);

  unsigned int nc = (n >> 1) + 1;
  unsigned long STEP = step_msec*(sample_freq / 1000); // in samples

  if(STEP >= n/2) error("segment-length to long\n");

  f_min_slot = (mirror_f_min * nc / f_max);
  f_max_slot = (mirror_f_max * nc / f_max);
  f_c_slot = f_min_slot + ((f_max_slot - f_min_slot) >> 1);


  fprintf(stderr,
         "sample freq  = %d Hz\n"
         "step-size    = %d samples\n"
         "DFT-size     = %d samples\n"
         "             = %d complex numbers\n"
         "f_min        = %d Hz (slot: %d)\n"
         "f_center     = %d Hz (slot: %d)\n"
         "f_max        = %d Hz (slot: %d)\n",
         sample_freq,
         STEP,
         n, nc,
         mirror_f_min, f_min_slot,
         mirror_f_c, f_c_slot,
         mirror_f_max, f_max_slot);

  in_r = fftw_malloc ( sizeof ( double ) * n );
  out_c = fftw_malloc ( sizeof ( fftw_complex ) * nc );
  out_r = fftw_malloc ( sizeof ( double ) * n );

  plan_forward = fftw_plan_dft_r2c_1d ( n, in_r, out_c, FFTW_ESTIMATE );
  plan_backward = fftw_plan_dft_c2r_1d ( n, out_c, out_r, FFTW_ESTIMATE );

  /*** open input file and determine file size ***/
  if(!strcmp(argv[1], "-")) in_file = stdin;
  else if((in_file = fopen(argv[1], "r")) == NULL)
    perror("can't open input file\n");

  if(!strcmp(argv[2], "-")) out_file = stdout;
  else if((out_file = fopen(argv[2], "w")) == NULL)
    perror("can't open output file:");

  /*** main loop ***/
  memset(in_buf, 0, sizeof(int16_t) * n);
  memset(out_buf, 0, sizeof(int16_t) * n);

  while((n_in = fread(&in_buf[n-STEP], 2, STEP, in_file)) == STEP) {

    invert(in_buf, out_buf, n, STEP);
    memmove(in_buf, &in_buf[STEP], (n-STEP+1)*sizeof(int16_t));
    memmove(out_buf, &out_buf[STEP], (n-STEP+1)*sizeof(int16_t));
    memset(&out_buf[n-STEP], 0, STEP*sizeof(int16_t));

    n_out = fwrite(out_buf, 2, STEP, out_file);
    if(n_in != n_out) {
      printf("error: num of bytes written is not equal to num of bytes read.\n");
      exit(1);
    }
  }

  /*** cleanup ***/
  fclose(in_file);
  fclose(out_file);

  fftw_destroy_plan ( plan_forward );
  fftw_destroy_plan ( plan_backward );

  fftw_free ( in_r );
  fftw_free ( out_c );
  fftw_free ( out_r );

  return 0;
}

Makefile

### INVERTER
SRATE=8000
FMIN=0
FMAX=3500
INVERT_ARGS=--sample-rate $(SRATE) --f-min $(FMIN) --f-max $(FMAX) \
       --chunk-len 25 --n 8000

### SOX

RAW_PARAMS=-s -c 1 -w -r $(SRATE) -t .raw
WAV_PARAMS=-s -c 1 -w -r 44100 -t .wav
PLAY_RAW_PARAMS=--type=.raw --format=s --channels=1 --size=w --rate=$(SRATE)
EFFECTS=highpass 1000

### FILES

INFILE=sine_1-3khz

INFILE_RAW=$(INFILE).raw
INFILE_WAV=$(INFILE).wav
OUTFILE_RAW=out.raw
OUTFILE_WAV=out.wav

### COMPILER

CFLAGS=-O3 -ggdb -I/usr/local/include
CLIBS=-L/usr/local/lib -lfftw3 -lm

it:
       @echo "--------------------------------------------------"
       @echo " Make sure the following packages are installed:"
       @echo "    + sox"
       @echo "    + libfftw"
       @echo
       @echo " Edit the Makefile first. Than start using "
       @echo "    make play "
       @echo "    make file "
       @echo "    make live "
       @echo "--------------------------------------------------"

compile: invert.c
       gcc $(CFLAGS) $(CLIBS) -o invert invert.c

file: compile
       sox $(WAV_PARAMS) $(INFILE_WAV) $(RAW_PARAMS) - $(EFFECTS)| \
               ./invert - - $(INVERT_ARGS) | \
               sox $(RAW_PARAMS) - $(WAV_PARAMS) $(OUTFILE_WAV)

play: compile
       sox $(WAV_PARAMS) $(INFILE_WAV) $(RAW_PARAMS) - $(EFFECTS)| \
               ./invert - - $(INVERT_ARGS) | \
               play $(PLAY_RAW_PARAMS) -

live: compile
       rec $(PLAY_RAW_PARAMS) - $(EFFECTS)| \
               ./invert - - $(INVERT_ARGS) | \
               play $(PLAY_RAW_PARAMS) -

clean:
       -rm *~ *.raw *.core invert $(OUTFILE_WAV) $(OUTFILE_RAW)

Pascal Version - Faster-smaller-simpler

PROGRAM invert;

CONST sfreq=48000; {Abtastfrequenz in Hertz}

     mfreq=6000;  {Spiegelfrequenz in Hertz}
     buflen=1024;
     offset=128;

VAR infile:file;

   outfile:file;
   sample:ARRAY [0..buflen-1] OF byte; {Abtasttyp}
   n,m,l:integer;

BEGIN

 assign(infile,'infile.raw');
 reset(infile,1);
 assign(outfile,'outfile.raw');
 rewrite(outfile,1);
 l:=0;
 REPEAT
   blockread(infile,sample,sizeof(sample),m);
   FOR n:=0 TO buflen-1 DO
   BEGIN
     sample[n]:=round((sample[n]*1.0-offset)*sin((l/(sfreq/mfreq))*2*pi)+offset);
     inc(l);
   END;
   blockwrite(outfile,sample,m);
 UNTIL eof(infile);
 close(outfile);
 close(infile);

END.

shell-script to use Pascal programm

  1. !/bin/sh

echo sox1 sox temp.mp3 -c 1 -r 48000 -u -b infile.raw lowpass 3000 echo invert ./a.out echo sox2 sox -r 48000 -c 1 -u -b outfile.raw output.wav lowpass 7000 echo sox3 sox output.wav -c 1 -r 48000 -u -b infile.raw echo invert ./a.out echo sox4 sox -r 48000 -c 1 -u -b outfile.raw -w output2.wav lowpass 3000


Vergleich

Links