Mon Mar 12 2012 21:39:59

Asterisk developer's documentation


func_pitchshift.c File Reference

Pitch Shift Audio Effect. More...

#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/audiohook.h"
#include <math.h>
Include dependency graph for func_pitchshift.c:

Go to the source code of this file.

Data Structures

struct  fft_data
struct  pitchshift_data

Defines

#define HIGH   1.25
#define HIGHER   1.5
#define HIGHEST   2
#define LOW   .85
#define LOWER   .7
#define LOWEST   .5
#define M_PI   3.14159265358979323846
#define MAX_FRAME_LENGTH   256

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void destroy_callback (void *data)
static int load_module (void)
static int pitch_shift (struct ast_frame *f, float amount, struct fft_data *fft_data)
static int pitchshift_cb (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *f, enum ast_audiohook_direction direction)
static int pitchshift_helper (struct ast_channel *chan, const char *cmd, char *data, const char *value)
static void smb_fft (float *fft_buffer, long fft_frame_size, long sign)
static void smb_pitch_shift (float pitchShift, long num_samps_to_process, long fft_frame_size, long osamp, float sample_rate, int16_t *indata, int16_t *outdata, struct fft_data *fft_data)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Audio Effects Dialplan Functions" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_custom_function pitch_shift_function
static struct ast_datastore_info pitchshift_datastore

Detailed Description

Pitch Shift Audio Effect.

Author:
David Vossel <dvossel@digium.com>

Definition in file func_pitchshift.c.


Define Documentation

#define HIGH   1.25

Definition at line 122 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define HIGHER   1.5

Definition at line 121 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define HIGHEST   2

Definition at line 120 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define LOW   .85

Definition at line 123 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define LOWER   .7

Definition at line 124 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define LOWEST   .5

Definition at line 125 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define M_PI   3.14159265358979323846
#define MAX_FRAME_LENGTH   256

Definition at line 118 of file func_pitchshift.c.

Referenced by pitch_shift().


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 510 of file func_pitchshift.c.

static void __unreg_module ( void  ) [static]

Definition at line 510 of file func_pitchshift.c.

static void destroy_callback ( void *  data) [static]

Definition at line 153 of file func_pitchshift.c.

References ast_audiohook_destroy(), ast_free, and pitchshift_data::audiohook.

{
   struct pitchshift_data *shift = data;

   ast_audiohook_destroy(&shift->audiohook);
   ast_free(shift);
};
static int load_module ( void  ) [static]
static int pitch_shift ( struct ast_frame f,
float  amount,
struct fft_data fft_data 
) [static]

Definition at line 478 of file func_pitchshift.c.

References ast_format_rate(), ast_frame_subclass::codec, ast_frame::data, MAX_FRAME_LENGTH, ast_frame::ptr, ast_frame::samples, smb_pitch_shift(), and ast_frame::subclass.

Referenced by pitchshift_cb().

{
   int16_t *fun = (int16_t *) f->data.ptr;
   int samples;

   /* an amount of 1 has no effect */
   if (!amount || amount == 1 || !fun || (f->samples % 32)) {
      return 0;
   }
   for (samples = 0; samples < f->samples; samples += 32) {
      smb_pitch_shift(amount, 32, MAX_FRAME_LENGTH, 32, ast_format_rate(f->subclass.codec), fun+samples, fun+samples, fft);
   }

   return 0;
}
static int pitchshift_cb ( struct ast_audiohook audiohook,
struct ast_channel chan,
struct ast_frame f,
enum ast_audiohook_direction  direction 
) [static]
static int pitchshift_helper ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

Definition at line 197 of file func_pitchshift.c.

References ast_audiohook_attach(), ast_audiohook_init(), AST_AUDIOHOOK_TYPE_MANIPULATE, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc(), ast_datastore_free(), ast_log(), pitchshift_data::audiohook, ast_datastore::data, HIGH, HIGHER, HIGHEST, LOG_ERROR, LOW, LOWER, LOWEST, ast_audiohook::manipulate_callback, pitchshift_cb(), pitchshift_data::rx, fft_data::shift_amount, and pitchshift_data::tx.

{
   struct ast_datastore *datastore = NULL;
   struct pitchshift_data *shift = NULL;
   int new = 0;
   float amount = 0;

   ast_channel_lock(chan);
   if (!(datastore = ast_channel_datastore_find(chan, &pitchshift_datastore, NULL))) {
      ast_channel_unlock(chan);

      if (!(datastore = ast_datastore_alloc(&pitchshift_datastore, NULL))) {
         return 0;
      }
      if (!(shift = ast_calloc(1, sizeof(*shift)))) {
         ast_datastore_free(datastore);
         return 0;
      }

      ast_audiohook_init(&shift->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "pitch_shift");
      shift->audiohook.manipulate_callback = pitchshift_cb;
      datastore->data = shift;
      new = 1;
   } else {
      ast_channel_unlock(chan);
      shift = datastore->data;
   }


   if (!strcasecmp(value, "highest")) {
      amount = HIGHEST;
   } else if (!strcasecmp(value, "higher")) {
      amount = HIGHER;
   } else if (!strcasecmp(value, "high")) {
      amount = HIGH;
   } else if (!strcasecmp(value, "lowest")) {
      amount = LOWEST;
   } else if (!strcasecmp(value, "lower")) {
      amount = LOWER;
   } else if (!strcasecmp(value, "low")) {
      amount = LOW;
   } else {
      if (!sscanf(value, "%30f", &amount) || (amount <= 0) || (amount > 4)) {
         goto cleanup_error;
      }
   }

   if (!strcasecmp(data, "rx")) {
      shift->rx.shift_amount = amount;
   } else if (!strcasecmp(data, "tx")) {
      shift->tx.shift_amount = amount;
   } else if (!strcasecmp(data, "both")) {
      shift->rx.shift_amount = amount;
      shift->tx.shift_amount = amount;
   } else {
      goto cleanup_error;
   }

   if (new) {
      ast_channel_lock(chan);
      ast_channel_datastore_add(chan, datastore);
      ast_channel_unlock(chan);
      ast_audiohook_attach(chan, &shift->audiohook);
   }

   return 0;

cleanup_error:

   ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
   if (new) {
      ast_datastore_free(datastore);
   }
   return -1;
}
static void smb_fft ( float *  fft_buffer,
long  fft_frame_size,
long  sign 
) [static]

Definition at line 273 of file func_pitchshift.c.

References cos, and M_PI.

Referenced by smb_pitch_shift().

{
   float wr, wi, arg, *p1, *p2, temp;
   float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i;
   long i, bitm, j, le, le2, k;

   for (i = 2; i < 2 * fft_frame_size - 2; i += 2) {
      for (bitm = 2, j = 0; bitm < 2 * fft_frame_size; bitm <<= 1) {
         if (i & bitm) {
            j++;
         }
         j <<= 1;
      }
      if (i < j) {
         p1 = fft_buffer + i; p2 = fft_buffer + j;
         temp = *p1; *(p1++) = *p2;
         *(p2++) = temp; temp = *p1;
         *p1 = *p2; *p2 = temp;
      }
   }
   for (k = 0, le = 2; k < (long) (log(fft_frame_size) / log(2.) + .5); k++) {
      le <<= 1;
      le2 = le>>1;
      ur = 1.0;
      ui = 0.0;
      arg = M_PI / (le2>>1);
      wr = cos(arg);
      wi = sign * sin(arg);
      for (j = 0; j < le2; j += 2) {
         p1r = fft_buffer+j; p1i = p1r + 1;
         p2r = p1r + le2; p2i = p2r + 1;
         for (i = j; i < 2 * fft_frame_size; i += le) {
            tr = *p2r * ur - *p2i * ui;
            ti = *p2r * ui + *p2i * ur;
            *p2r = *p1r - tr; *p2i = *p1i - ti;
            *p1r += tr; *p1i += ti;
            p1r += le; p1i += le;
            p2r += le; p2i += le;
         }
         tr = ur * wr - ui * wi;
         ui = ur * wi + ui * wr;
         ur = tr;
      }
   }
}
static void smb_pitch_shift ( float  pitchShift,
long  num_samps_to_process,
long  fft_frame_size,
long  osamp,
float  sample_rate,
int16_t *  indata,
int16_t *  outdata,
struct fft_data fft_data 
) [static]

Definition at line 319 of file func_pitchshift.c.

References fft_data::ana_freq, fft_data::ana_magn, cos, fft_data::fft_worksp, fft_data::gRover, fft_data::in_fifo, fft_data::last_phase, M_PI, fft_data::out_fifo, fft_data::output_accum, smb_fft(), step_size(), fft_data::sum_phase, fft_data::syn_freq, and fft_data::sys_magn.

Referenced by pitch_shift().

{
   float *in_fifo = fft_data->in_fifo;
   float *out_fifo = fft_data->out_fifo;
   float *fft_worksp = fft_data->fft_worksp;
   float *last_phase = fft_data->last_phase;
   float *sum_phase = fft_data->sum_phase;
   float *output_accum = fft_data->output_accum;
   float *ana_freq = fft_data->ana_freq;
   float *ana_magn = fft_data->ana_magn;
   float *syn_freq = fft_data->syn_freq;
   float *sys_magn = fft_data->sys_magn;

   double magn, phase, tmp, window, real, imag;
   double freq_per_bin, expct;
   long i,k, qpd, index, in_fifo_latency, step_size, fft_frame_size2;

   /* set up some handy variables */
   fft_frame_size2 = fft_frame_size / 2;
   step_size = fft_frame_size / osamp;
   freq_per_bin = sample_rate / (double) fft_frame_size;
   expct = 2. * M_PI * (double) step_size / (double) fft_frame_size;
   in_fifo_latency = fft_frame_size-step_size;

   if (fft_data->gRover == 0) {
      fft_data->gRover = in_fifo_latency;
   }

   /* main processing loop */
   for (i = 0; i < num_samps_to_process; i++){

      /* As long as we have not yet collected enough data just read in */
      in_fifo[fft_data->gRover] = indata[i];
      outdata[i] = out_fifo[fft_data->gRover - in_fifo_latency];
      fft_data->gRover++;

      /* now we have enough data for processing */
      if (fft_data->gRover >= fft_frame_size) {
         fft_data->gRover = in_fifo_latency;

         /* do windowing and re,im interleave */
         for (k = 0; k < fft_frame_size;k++) {
            window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5;
            fft_worksp[2*k] = in_fifo[k] * window;
            fft_worksp[2*k+1] = 0.;
         }

         /* ***************** ANALYSIS ******************* */
         /* do transform */
         smb_fft(fft_worksp, fft_frame_size, -1);

         /* this is the analysis step */
         for (k = 0; k <= fft_frame_size2; k++) {

            /* de-interlace FFT buffer */
            real = fft_worksp[2*k];
            imag = fft_worksp[2*k+1];

            /* compute magnitude and phase */
            magn = 2. * sqrt(real * real + imag * imag);
            phase = atan2(imag, real);

            /* compute phase difference */
            tmp = phase - last_phase[k];
            last_phase[k] = phase;

            /* subtract expected phase difference */
            tmp -= (double) k * expct;

            /* map delta phase into +/- Pi interval */
            qpd = tmp / M_PI;
            if (qpd >= 0) {
               qpd += qpd & 1;
            } else {
               qpd -= qpd & 1;
            }
            tmp -= M_PI * (double) qpd;

            /* get deviation from bin frequency from the +/- Pi interval */
            tmp = osamp * tmp / (2. * M_PI);

            /* compute the k-th partials' true frequency */
            tmp = (double) k * freq_per_bin + tmp * freq_per_bin;

            /* store magnitude and true frequency in analysis arrays */
            ana_magn[k] = magn;
            ana_freq[k] = tmp;

         }

         /* ***************** PROCESSING ******************* */
         /* this does the actual pitch shifting */
         memset(sys_magn, 0, fft_frame_size * sizeof(float));
         memset(syn_freq, 0, fft_frame_size * sizeof(float));
         for (k = 0; k <= fft_frame_size2; k++) {
            index = k * pitchShift;
            if (index <= fft_frame_size2) {
               sys_magn[index] += ana_magn[k];
               syn_freq[index] = ana_freq[k] * pitchShift;
            }
         }

         /* ***************** SYNTHESIS ******************* */
         /* this is the synthesis step */
         for (k = 0; k <= fft_frame_size2; k++) {

            /* get magnitude and true frequency from synthesis arrays */
            magn = sys_magn[k];
            tmp = syn_freq[k];

            /* subtract bin mid frequency */
            tmp -= (double) k * freq_per_bin;

            /* get bin deviation from freq deviation */
            tmp /= freq_per_bin;

            /* take osamp into account */
            tmp = 2. * M_PI * tmp / osamp;

            /* add the overlap phase advance back in */
            tmp += (double) k * expct;

            /* accumulate delta phase to get bin phase */
            sum_phase[k] += tmp;
            phase = sum_phase[k];

            /* get real and imag part and re-interleave */
            fft_worksp[2*k] = magn * cos(phase);
            fft_worksp[2*k+1] = magn * sin(phase);
         }

         /* zero negative frequencies */
         for (k = fft_frame_size + 2; k < 2 * fft_frame_size; k++) {
            fft_worksp[k] = 0.;
         }

         /* do inverse transform */
         smb_fft(fft_worksp, fft_frame_size, 1);

         /* do windowing and add to output accumulator */
         for (k = 0; k < fft_frame_size; k++) {
            window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5;
            output_accum[k] += 2. * window * fft_worksp[2*k] / (fft_frame_size2 * osamp);
         }
         for (k = 0; k < step_size; k++) {
            out_fifo[k] = output_accum[k];
         }

         /* shift accumulator */
         memmove(output_accum, output_accum+step_size, fft_frame_size * sizeof(float));

         /* move input FIFO */
         for (k = 0; k < in_fifo_latency; k++) {
            in_fifo[k] = in_fifo[k+step_size];
         }
      }
   }
}
static int unload_module ( void  ) [static]

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Audio Effects Dialplan Functions" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 510 of file func_pitchshift.c.

Definition at line 510 of file func_pitchshift.c.

Initial value:
 {
   .name = "PITCH_SHIFT",
   .write = pitchshift_helper,
}

Definition at line 494 of file func_pitchshift.c.

Initial value:
 {
   .type = "pitchshift",
   .destroy = destroy_callback
}

Definition at line 161 of file func_pitchshift.c.