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 | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Audio Effects Dialplan Functions") | |
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_custom_function | pitch_shift_function |
static struct ast_datastore_info | pitchshift_datastore |
Pitch Shift Audio Effect.
Definition in file func_pitchshift.c.
#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().
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Audio Effects Dialplan Functions" | ||||
) |
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, and AST_MODULE_LOAD_SUCCESS.
00505 { 00506 int res = ast_custom_function_register(&pitch_shift_function); 00507 return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; 00508 }
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().
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, ast_frame_subclass::codec, ast_datastore::data, ast_frame::frametype, pitch_shift(), pitchshift_data::rx, fft_data::shift_amount, ast_audiohook::status, ast_frame::subclass, 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, ast_audiohook::manipulate_callback, pitchshift_cb(), 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.
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().
00500 { 00501 return ast_custom_function_unregister(&pitch_shift_function); 00502 }
struct ast_custom_function pitch_shift_function [static] |
{ .name = "PITCH_SHIFT", .write = pitchshift_helper, }
Definition at line 494 of file func_pitchshift.c.
struct ast_datastore_info pitchshift_datastore [static] |
{ .type = "pitchshift", .destroy = destroy_callback }
Definition at line 161 of file func_pitchshift.c.