Mon Jun 27 16:51:14 2011

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>

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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 118 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define HIGHER   1.5

Definition at line 117 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define HIGHEST   2

Definition at line 116 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define LOW   .85

Definition at line 119 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define LOWER   .7

Definition at line 120 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define LOWEST   .5

Definition at line 121 of file func_pitchshift.c.

Referenced by pitchshift_helper().

#define M_PI   3.14159265358979323846

Definition at line 112 of file func_pitchshift.c.

Referenced by ast_playtones_start(), callerid_init(), goertzel_init(), make_tone_burst(), smb_fft(), smb_pitch_shift(), tdd_init(), and tonepair_alloc().

#define MAX_FRAME_LENGTH   256

Definition at line 114 of file func_pitchshift.c.

Referenced by pitch_shift().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 506 of file func_pitchshift.c.

static void __unreg_module ( void   )  [static]

Definition at line 506 of file func_pitchshift.c.

static void destroy_callback ( void *  data  )  [static]

Definition at line 149 of file func_pitchshift.c.

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

00150 {
00151    struct pitchshift_data *shift = data;
00152 
00153    ast_audiohook_destroy(&shift->audiohook);
00154    ast_free(shift);
00155 };

static int load_module ( void   )  [static]

Definition at line 500 of file func_pitchshift.c.

References ast_custom_function_register, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and pitch_shift_function.

static int pitch_shift ( struct ast_frame f,
float  amount,
struct fft_data fft_data 
) [static]

Definition at line 474 of file func_pitchshift.c.

References ast_format_rate(), f, MAX_FRAME_LENGTH, and smb_pitch_shift().

Referenced by pitchshift_cb().

00475 {
00476    int16_t *fun = (int16_t *) f->data.ptr;
00477    int samples;
00478 
00479    /* an amount of 1 has no effect */
00480    if (!amount || amount == 1 || !fun || (f->samples % 32)) {
00481       return 0;
00482    }
00483    for (samples = 0; samples < f->samples; samples += 32) {
00484       smb_pitch_shift(amount, 32, MAX_FRAME_LENGTH, 32, ast_format_rate(f->subclass.codec), fun+samples, fun+samples, fft);
00485    }
00486 
00487    return 0;
00488 }

static int pitchshift_cb ( struct ast_audiohook audiohook,
struct ast_channel chan,
struct ast_frame f,
enum ast_audiohook_direction  direction 
) [static]

Definition at line 162 of file func_pitchshift.c.

References AST_AUDIOHOOK_DIRECTION_WRITE, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), AST_FORMAT_SLINEAR, AST_FORMAT_SLINEAR16, AST_FRAME_VOICE, pitchshift_data::audiohook, ast_datastore::data, f, pitch_shift(), pitchshift_datastore, pitchshift_data::rx, fft_data::shift_amount, ast_audiohook::status, and pitchshift_data::tx.

Referenced by pitchshift_helper().

00163 {
00164    struct ast_datastore *datastore = NULL;
00165    struct pitchshift_data *shift = NULL;
00166 
00167 
00168    if (!f) {
00169       return 0;
00170    }
00171    if ((audiohook->status == AST_AUDIOHOOK_STATUS_DONE) ||
00172       (f->frametype != AST_FRAME_VOICE) ||
00173       ((f->subclass.codec != AST_FORMAT_SLINEAR) &&
00174       (f->subclass.codec != AST_FORMAT_SLINEAR16))) {
00175       return -1;
00176    }
00177 
00178    if (!(datastore = ast_channel_datastore_find(chan, &pitchshift_datastore, NULL))) {
00179       return -1;
00180    }
00181 
00182    shift = datastore->data;
00183 
00184    if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
00185       pitch_shift(f, shift->tx.shift_amount, &shift->tx);
00186    } else {
00187       pitch_shift(f, shift->rx.shift_amount, &shift->rx);
00188    }
00189 
00190    return 0;
00191 }

static int pitchshift_helper ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

Definition at line 193 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, pitchshift_cb(), pitchshift_datastore, pitchshift_data::rx, fft_data::shift_amount, and pitchshift_data::tx.

00194 {
00195    struct ast_datastore *datastore = NULL;
00196    struct pitchshift_data *shift = NULL;
00197    int new = 0;
00198    float amount = 0;
00199 
00200    ast_channel_lock(chan);
00201    if (!(datastore = ast_channel_datastore_find(chan, &pitchshift_datastore, NULL))) {
00202       ast_channel_unlock(chan);
00203 
00204       if (!(datastore = ast_datastore_alloc(&pitchshift_datastore, NULL))) {
00205          return 0;
00206       }
00207       if (!(shift = ast_calloc(1, sizeof(*shift)))) {
00208          ast_datastore_free(datastore);
00209          return 0;
00210       }
00211 
00212       ast_audiohook_init(&shift->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "pitch_shift");
00213       shift->audiohook.manipulate_callback = pitchshift_cb;
00214       datastore->data = shift;
00215       new = 1;
00216    } else {
00217       ast_channel_unlock(chan);
00218       shift = datastore->data;
00219    }
00220 
00221 
00222    if (!strcasecmp(value, "highest")) {
00223       amount = HIGHEST;
00224    } else if (!strcasecmp(value, "higher")) {
00225       amount = HIGHER;
00226    } else if (!strcasecmp(value, "high")) {
00227       amount = HIGH;
00228    } else if (!strcasecmp(value, "lowest")) {
00229       amount = LOWEST;
00230    } else if (!strcasecmp(value, "lower")) {
00231       amount = LOWER;
00232    } else if (!strcasecmp(value, "low")) {
00233       amount = LOW;
00234    } else {
00235       if (!sscanf(value, "%30f", &amount) || (amount <= 0) || (amount > 4)) {
00236          goto cleanup_error;
00237       }
00238    }
00239 
00240    if (!strcasecmp(data, "rx")) {
00241       shift->rx.shift_amount = amount;
00242    } else if (!strcasecmp(data, "tx")) {
00243       shift->tx.shift_amount = amount;
00244    } else if (!strcasecmp(data, "both")) {
00245       shift->rx.shift_amount = amount;
00246       shift->tx.shift_amount = amount;
00247    } else {
00248       goto cleanup_error;
00249    }
00250 
00251    if (new) {
00252       ast_channel_lock(chan);
00253       ast_channel_datastore_add(chan, datastore);
00254       ast_channel_unlock(chan);
00255       ast_audiohook_attach(chan, &shift->audiohook);
00256    }
00257 
00258    return 0;
00259 
00260 cleanup_error:
00261 
00262    ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
00263    if (new) {
00264       ast_datastore_free(datastore);
00265    }
00266    return -1;
00267 }

static void smb_fft ( float *  fft_buffer,
long  fft_frame_size,
long  sign 
) [static]

Definition at line 269 of file func_pitchshift.c.

References cos, and M_PI.

Referenced by smb_pitch_shift().

00270 {
00271    float wr, wi, arg, *p1, *p2, temp;
00272    float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i;
00273    long i, bitm, j, le, le2, k;
00274 
00275    for (i = 2; i < 2 * fft_frame_size - 2; i += 2) {
00276       for (bitm = 2, j = 0; bitm < 2 * fft_frame_size; bitm <<= 1) {
00277          if (i & bitm) {
00278             j++;
00279          }
00280          j <<= 1;
00281       }
00282       if (i < j) {
00283          p1 = fft_buffer + i; p2 = fft_buffer + j;
00284          temp = *p1; *(p1++) = *p2;
00285          *(p2++) = temp; temp = *p1;
00286          *p1 = *p2; *p2 = temp;
00287       }
00288    }
00289    for (k = 0, le = 2; k < (long) (log(fft_frame_size) / log(2.) + .5); k++) {
00290       le <<= 1;
00291       le2 = le>>1;
00292       ur = 1.0;
00293       ui = 0.0;
00294       arg = M_PI / (le2>>1);
00295       wr = cos(arg);
00296       wi = sign * sin(arg);
00297       for (j = 0; j < le2; j += 2) {
00298          p1r = fft_buffer+j; p1i = p1r + 1;
00299          p2r = p1r + le2; p2i = p2r + 1;
00300          for (i = j; i < 2 * fft_frame_size; i += le) {
00301             tr = *p2r * ur - *p2i * ui;
00302             ti = *p2r * ui + *p2i * ur;
00303             *p2r = *p1r - tr; *p2i = *p1i - ti;
00304             *p1r += tr; *p1i += ti;
00305             p1r += le; p1i += le;
00306             p2r += le; p2i += le;
00307          }
00308          tr = ur * wr - ui * wi;
00309          ui = ur * wi + ui * wr;
00310          ur = tr;
00311       }
00312    }
00313 }

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 315 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().

00316 {
00317    float *in_fifo = fft_data->in_fifo;
00318    float *out_fifo = fft_data->out_fifo;
00319    float *fft_worksp = fft_data->fft_worksp;
00320    float *last_phase = fft_data->last_phase;
00321    float *sum_phase = fft_data->sum_phase;
00322    float *output_accum = fft_data->output_accum;
00323    float *ana_freq = fft_data->ana_freq;
00324    float *ana_magn = fft_data->ana_magn;
00325    float *syn_freq = fft_data->syn_freq;
00326    float *sys_magn = fft_data->sys_magn;
00327 
00328    double magn, phase, tmp, window, real, imag;
00329    double freq_per_bin, expct;
00330    long i,k, qpd, index, in_fifo_latency, step_size, fft_frame_size2;
00331 
00332    /* set up some handy variables */
00333    fft_frame_size2 = fft_frame_size / 2;
00334    step_size = fft_frame_size / osamp;
00335    freq_per_bin = sample_rate / (double) fft_frame_size;
00336    expct = 2. * M_PI * (double) step_size / (double) fft_frame_size;
00337    in_fifo_latency = fft_frame_size-step_size;
00338 
00339    if (fft_data->gRover == 0) {
00340       fft_data->gRover = in_fifo_latency;
00341    }
00342 
00343    /* main processing loop */
00344    for (i = 0; i < num_samps_to_process; i++){
00345 
00346       /* As long as we have not yet collected enough data just read in */
00347       in_fifo[fft_data->gRover] = indata[i];
00348       outdata[i] = out_fifo[fft_data->gRover - in_fifo_latency];
00349       fft_data->gRover++;
00350 
00351       /* now we have enough data for processing */
00352       if (fft_data->gRover >= fft_frame_size) {
00353          fft_data->gRover = in_fifo_latency;
00354 
00355          /* do windowing and re,im interleave */
00356          for (k = 0; k < fft_frame_size;k++) {
00357             window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5;
00358             fft_worksp[2*k] = in_fifo[k] * window;
00359             fft_worksp[2*k+1] = 0.;
00360          }
00361 
00362          /* ***************** ANALYSIS ******************* */
00363          /* do transform */
00364          smb_fft(fft_worksp, fft_frame_size, -1);
00365 
00366          /* this is the analysis step */
00367          for (k = 0; k <= fft_frame_size2; k++) {
00368 
00369             /* de-interlace FFT buffer */
00370             real = fft_worksp[2*k];
00371             imag = fft_worksp[2*k+1];
00372 
00373             /* compute magnitude and phase */
00374             magn = 2. * sqrt(real * real + imag * imag);
00375             phase = atan2(imag, real);
00376 
00377             /* compute phase difference */
00378             tmp = phase - last_phase[k];
00379             last_phase[k] = phase;
00380 
00381             /* subtract expected phase difference */
00382             tmp -= (double) k * expct;
00383 
00384             /* map delta phase into +/- Pi interval */
00385             qpd = tmp / M_PI;
00386             if (qpd >= 0) {
00387                qpd += qpd & 1;
00388             } else {
00389                qpd -= qpd & 1;
00390             }
00391             tmp -= M_PI * (double) qpd;
00392 
00393             /* get deviation from bin frequency from the +/- Pi interval */
00394             tmp = osamp * tmp / (2. * M_PI);
00395 
00396             /* compute the k-th partials' true frequency */
00397             tmp = (double) k * freq_per_bin + tmp * freq_per_bin;
00398 
00399             /* store magnitude and true frequency in analysis arrays */
00400             ana_magn[k] = magn;
00401             ana_freq[k] = tmp;
00402 
00403          }
00404 
00405          /* ***************** PROCESSING ******************* */
00406          /* this does the actual pitch shifting */
00407          memset(sys_magn, 0, fft_frame_size * sizeof(float));
00408          memset(syn_freq, 0, fft_frame_size * sizeof(float));
00409          for (k = 0; k <= fft_frame_size2; k++) {
00410             index = k * pitchShift;
00411             if (index <= fft_frame_size2) {
00412                sys_magn[index] += ana_magn[k];
00413                syn_freq[index] = ana_freq[k] * pitchShift;
00414             }
00415          }
00416 
00417          /* ***************** SYNTHESIS ******************* */
00418          /* this is the synthesis step */
00419          for (k = 0; k <= fft_frame_size2; k++) {
00420 
00421             /* get magnitude and true frequency from synthesis arrays */
00422             magn = sys_magn[k];
00423             tmp = syn_freq[k];
00424 
00425             /* subtract bin mid frequency */
00426             tmp -= (double) k * freq_per_bin;
00427 
00428             /* get bin deviation from freq deviation */
00429             tmp /= freq_per_bin;
00430 
00431             /* take osamp into account */
00432             tmp = 2. * M_PI * tmp / osamp;
00433 
00434             /* add the overlap phase advance back in */
00435             tmp += (double) k * expct;
00436 
00437             /* accumulate delta phase to get bin phase */
00438             sum_phase[k] += tmp;
00439             phase = sum_phase[k];
00440 
00441             /* get real and imag part and re-interleave */
00442             fft_worksp[2*k] = magn * cos(phase);
00443             fft_worksp[2*k+1] = magn * sin(phase);
00444          }
00445 
00446          /* zero negative frequencies */
00447          for (k = fft_frame_size + 2; k < 2 * fft_frame_size; k++) {
00448             fft_worksp[k] = 0.;
00449          }
00450 
00451          /* do inverse transform */
00452          smb_fft(fft_worksp, fft_frame_size, 1);
00453 
00454          /* do windowing and add to output accumulator */
00455          for (k = 0; k < fft_frame_size; k++) {
00456             window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5;
00457             output_accum[k] += 2. * window * fft_worksp[2*k] / (fft_frame_size2 * osamp);
00458          }
00459          for (k = 0; k < step_size; k++) {
00460             out_fifo[k] = output_accum[k];
00461          }
00462 
00463          /* shift accumulator */
00464          memmove(output_accum, output_accum+step_size, fft_frame_size * sizeof(float));
00465 
00466          /* move input FIFO */
00467          for (k = 0; k < in_fifo_latency; k++) {
00468             in_fifo[k] = in_fifo[k+step_size];
00469          }
00470       }
00471    }
00472 }

static int unload_module ( void   )  [static]

Definition at line 495 of file func_pitchshift.c.

References ast_custom_function_unregister(), and pitch_shift_function.

00496 {
00497    return ast_custom_function_unregister(&pitch_shift_function);
00498 }


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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 506 of file func_pitchshift.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 506 of file func_pitchshift.c.

struct ast_custom_function pitch_shift_function [static]

Initial value:

 {
   .name = "PITCH_SHIFT",
   .write = pitchshift_helper,
}

Definition at line 490 of file func_pitchshift.c.

Referenced by load_module(), and unload_module().

struct ast_datastore_info pitchshift_datastore [static]

Initial value:

 {
   .type = "pitchshift",
   .destroy = destroy_callback
}

Definition at line 157 of file func_pitchshift.c.

Referenced by pitchshift_cb(), and pitchshift_helper().


Generated on Mon Jun 27 16:51:14 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7