#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_info * | ast_module_info = &__mod_info |
static struct ast_custom_function | pitch_shift_function |
static struct ast_datastore_info | pitchshift_datastore |
Definition in file func_pitchshift.c.
#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 |
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 |
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.
00501 { 00502 int res = ast_custom_function_register(&pitch_shift_function); 00503 return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; 00504 }
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.
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 }
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().