Mon Oct 8 12:39:23 2012

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 = "ac1f6a56484a8820659555499174e588" , .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

Definition at line 116 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 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.

00154 {
00155    struct pitchshift_data *shift = data;
00156 
00157    ast_audiohook_destroy(&shift->audiohook);
00158    ast_free(shift);
00159 };

static int load_module ( void   )  [static]

Definition at line 504 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 478 of file func_pitchshift.c.

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

Referenced by pitchshift_cb().

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

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

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

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

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

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

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

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

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

static int unload_module ( void   )  [static]

Definition at line 499 of file func_pitchshift.c.

References ast_custom_function_unregister(), and pitch_shift_function.

00500 {
00501    return ast_custom_function_unregister(&pitch_shift_function);
00502 }


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

Definition at line 510 of file func_pitchshift.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 510 of file func_pitchshift.c.

struct ast_custom_function pitch_shift_function [static]

Initial value:

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

Definition at line 494 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 161 of file func_pitchshift.c.

Referenced by pitchshift_cb(), and pitchshift_helper().


Generated on Mon Oct 8 12:39:23 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7