00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 #include "asterisk.h"
00066
00067 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411314 $")
00068
00069 #include "asterisk/module.h"
00070 #include "asterisk/channel.h"
00071 #include "asterisk/pbx.h"
00072 #include "asterisk/utils.h"
00073 #include "asterisk/audiohook.h"
00074 #include <math.h>
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 #ifndef M_PI
00116 #define M_PI 3.14159265358979323846
00117 #endif
00118 #define MAX_FRAME_LENGTH 256
00119
00120 #define HIGHEST 2
00121 #define HIGHER 1.5
00122 #define HIGH 1.25
00123 #define LOW .85
00124 #define LOWER .7
00125 #define LOWEST .5
00126
00127 struct fft_data {
00128 float in_fifo[MAX_FRAME_LENGTH];
00129 float out_fifo[MAX_FRAME_LENGTH];
00130 float fft_worksp[2*MAX_FRAME_LENGTH];
00131 float last_phase[MAX_FRAME_LENGTH/2+1];
00132 float sum_phase[MAX_FRAME_LENGTH/2+1];
00133 float output_accum[2*MAX_FRAME_LENGTH];
00134 float ana_freq[MAX_FRAME_LENGTH];
00135 float ana_magn[MAX_FRAME_LENGTH];
00136 float syn_freq[MAX_FRAME_LENGTH];
00137 float sys_magn[MAX_FRAME_LENGTH];
00138 long gRover;
00139 float shift_amount;
00140 };
00141
00142 struct pitchshift_data {
00143 struct ast_audiohook audiohook;
00144
00145 struct fft_data rx;
00146 struct fft_data tx;
00147 };
00148
00149 static void smb_fft(float *fft_buffer, long fft_frame_size, long sign);
00150 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);
00151 static int pitch_shift(struct ast_frame *f, float amount, struct fft_data *fft_data);
00152
00153 static void destroy_callback(void *data)
00154 {
00155 struct pitchshift_data *shift = data;
00156
00157 ast_audiohook_destroy(&shift->audiohook);
00158 ast_free(shift);
00159 };
00160
00161 static const struct ast_datastore_info pitchshift_datastore = {
00162 .type = "pitchshift",
00163 .destroy = destroy_callback
00164 };
00165
00166 static int pitchshift_cb(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *f, enum ast_audiohook_direction direction)
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 !(ast_format_is_slinear(&f->subclass.format))) {
00178 return -1;
00179 }
00180
00181 if (!(datastore = ast_channel_datastore_find(chan, &pitchshift_datastore, NULL))) {
00182 return -1;
00183 }
00184
00185 shift = datastore->data;
00186
00187 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
00188 pitch_shift(f, shift->tx.shift_amount, &shift->tx);
00189 } else {
00190 pitch_shift(f, shift->rx.shift_amount, &shift->rx);
00191 }
00192
00193 return 0;
00194 }
00195
00196 static int pitchshift_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00197 {
00198 struct ast_datastore *datastore = NULL;
00199 struct pitchshift_data *shift = NULL;
00200 int new = 0;
00201 float amount = 0;
00202
00203 if (!chan) {
00204 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00205 return -1;
00206 }
00207
00208 ast_channel_lock(chan);
00209 if (!(datastore = ast_channel_datastore_find(chan, &pitchshift_datastore, NULL))) {
00210 ast_channel_unlock(chan);
00211
00212 if (!(datastore = ast_datastore_alloc(&pitchshift_datastore, NULL))) {
00213 return 0;
00214 }
00215 if (!(shift = ast_calloc(1, sizeof(*shift)))) {
00216 ast_datastore_free(datastore);
00217 return 0;
00218 }
00219
00220 ast_audiohook_init(&shift->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "pitch_shift", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
00221 shift->audiohook.manipulate_callback = pitchshift_cb;
00222 datastore->data = shift;
00223 new = 1;
00224 } else {
00225 ast_channel_unlock(chan);
00226 shift = datastore->data;
00227 }
00228
00229
00230 if (!strcasecmp(value, "highest")) {
00231 amount = HIGHEST;
00232 } else if (!strcasecmp(value, "higher")) {
00233 amount = HIGHER;
00234 } else if (!strcasecmp(value, "high")) {
00235 amount = HIGH;
00236 } else if (!strcasecmp(value, "lowest")) {
00237 amount = LOWEST;
00238 } else if (!strcasecmp(value, "lower")) {
00239 amount = LOWER;
00240 } else if (!strcasecmp(value, "low")) {
00241 amount = LOW;
00242 } else {
00243 if (!sscanf(value, "%30f", &amount) || (amount <= 0) || (amount > 4)) {
00244 goto cleanup_error;
00245 }
00246 }
00247
00248 if (!strcasecmp(data, "rx")) {
00249 shift->rx.shift_amount = amount;
00250 } else if (!strcasecmp(data, "tx")) {
00251 shift->tx.shift_amount = amount;
00252 } else if (!strcasecmp(data, "both")) {
00253 shift->rx.shift_amount = amount;
00254 shift->tx.shift_amount = amount;
00255 } else {
00256 goto cleanup_error;
00257 }
00258
00259 if (new) {
00260 ast_channel_lock(chan);
00261 ast_channel_datastore_add(chan, datastore);
00262 ast_channel_unlock(chan);
00263 ast_audiohook_attach(chan, &shift->audiohook);
00264 }
00265
00266 return 0;
00267
00268 cleanup_error:
00269
00270 ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
00271 if (new) {
00272 ast_datastore_free(datastore);
00273 }
00274 return -1;
00275 }
00276
00277 static void smb_fft(float *fft_buffer, long fft_frame_size, long sign)
00278 {
00279 float wr, wi, arg, *p1, *p2, temp;
00280 float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i;
00281 long i, bitm, j, le, le2, k;
00282
00283 for (i = 2; i < 2 * fft_frame_size - 2; i += 2) {
00284 for (bitm = 2, j = 0; bitm < 2 * fft_frame_size; bitm <<= 1) {
00285 if (i & bitm) {
00286 j++;
00287 }
00288 j <<= 1;
00289 }
00290 if (i < j) {
00291 p1 = fft_buffer + i; p2 = fft_buffer + j;
00292 temp = *p1; *(p1++) = *p2;
00293 *(p2++) = temp; temp = *p1;
00294 *p1 = *p2; *p2 = temp;
00295 }
00296 }
00297 for (k = 0, le = 2; k < (long) (log(fft_frame_size) / log(2.) + .5); k++) {
00298 le <<= 1;
00299 le2 = le>>1;
00300 ur = 1.0;
00301 ui = 0.0;
00302 arg = M_PI / (le2>>1);
00303 wr = cos(arg);
00304 wi = sign * sin(arg);
00305 for (j = 0; j < le2; j += 2) {
00306 p1r = fft_buffer+j; p1i = p1r + 1;
00307 p2r = p1r + le2; p2i = p2r + 1;
00308 for (i = j; i < 2 * fft_frame_size; i += le) {
00309 tr = *p2r * ur - *p2i * ui;
00310 ti = *p2r * ui + *p2i * ur;
00311 *p2r = *p1r - tr; *p2i = *p1i - ti;
00312 *p1r += tr; *p1i += ti;
00313 p1r += le; p1i += le;
00314 p2r += le; p2i += le;
00315 }
00316 tr = ur * wr - ui * wi;
00317 ui = ur * wi + ui * wr;
00318 ur = tr;
00319 }
00320 }
00321 }
00322
00323 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)
00324 {
00325 float *in_fifo = fft_data->in_fifo;
00326 float *out_fifo = fft_data->out_fifo;
00327 float *fft_worksp = fft_data->fft_worksp;
00328 float *last_phase = fft_data->last_phase;
00329 float *sum_phase = fft_data->sum_phase;
00330 float *output_accum = fft_data->output_accum;
00331 float *ana_freq = fft_data->ana_freq;
00332 float *ana_magn = fft_data->ana_magn;
00333 float *syn_freq = fft_data->syn_freq;
00334 float *sys_magn = fft_data->sys_magn;
00335
00336 double magn, phase, tmp, window, real, imag;
00337 double freq_per_bin, expct;
00338 long i,k, qpd, index, in_fifo_latency, step_size, fft_frame_size2;
00339
00340
00341 fft_frame_size2 = fft_frame_size / 2;
00342 step_size = fft_frame_size / osamp;
00343 freq_per_bin = sample_rate / (double) fft_frame_size;
00344 expct = 2. * M_PI * (double) step_size / (double) fft_frame_size;
00345 in_fifo_latency = fft_frame_size-step_size;
00346
00347 if (fft_data->gRover == 0) {
00348 fft_data->gRover = in_fifo_latency;
00349 }
00350
00351
00352 for (i = 0; i < num_samps_to_process; i++){
00353
00354
00355 in_fifo[fft_data->gRover] = indata[i];
00356 outdata[i] = out_fifo[fft_data->gRover - in_fifo_latency];
00357 fft_data->gRover++;
00358
00359
00360 if (fft_data->gRover >= fft_frame_size) {
00361 fft_data->gRover = in_fifo_latency;
00362
00363
00364 for (k = 0; k < fft_frame_size;k++) {
00365 window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5;
00366 fft_worksp[2*k] = in_fifo[k] * window;
00367 fft_worksp[2*k+1] = 0.;
00368 }
00369
00370
00371
00372 smb_fft(fft_worksp, fft_frame_size, -1);
00373
00374
00375 for (k = 0; k <= fft_frame_size2; k++) {
00376
00377
00378 real = fft_worksp[2*k];
00379 imag = fft_worksp[2*k+1];
00380
00381
00382 magn = 2. * sqrt(real * real + imag * imag);
00383 phase = atan2(imag, real);
00384
00385
00386 tmp = phase - last_phase[k];
00387 last_phase[k] = phase;
00388
00389
00390 tmp -= (double) k * expct;
00391
00392
00393 qpd = tmp / M_PI;
00394 if (qpd >= 0) {
00395 qpd += qpd & 1;
00396 } else {
00397 qpd -= qpd & 1;
00398 }
00399 tmp -= M_PI * (double) qpd;
00400
00401
00402 tmp = osamp * tmp / (2. * M_PI);
00403
00404
00405 tmp = (double) k * freq_per_bin + tmp * freq_per_bin;
00406
00407
00408 ana_magn[k] = magn;
00409 ana_freq[k] = tmp;
00410
00411 }
00412
00413
00414
00415 memset(sys_magn, 0, fft_frame_size * sizeof(float));
00416 memset(syn_freq, 0, fft_frame_size * sizeof(float));
00417 for (k = 0; k <= fft_frame_size2; k++) {
00418 index = k * pitchShift;
00419 if (index <= fft_frame_size2) {
00420 sys_magn[index] += ana_magn[k];
00421 syn_freq[index] = ana_freq[k] * pitchShift;
00422 }
00423 }
00424
00425
00426
00427 for (k = 0; k <= fft_frame_size2; k++) {
00428
00429
00430 magn = sys_magn[k];
00431 tmp = syn_freq[k];
00432
00433
00434 tmp -= (double) k * freq_per_bin;
00435
00436
00437 tmp /= freq_per_bin;
00438
00439
00440 tmp = 2. * M_PI * tmp / osamp;
00441
00442
00443 tmp += (double) k * expct;
00444
00445
00446 sum_phase[k] += tmp;
00447 phase = sum_phase[k];
00448
00449
00450 fft_worksp[2*k] = magn * cos(phase);
00451 fft_worksp[2*k+1] = magn * sin(phase);
00452 }
00453
00454
00455 for (k = fft_frame_size + 2; k < 2 * fft_frame_size; k++) {
00456 fft_worksp[k] = 0.;
00457 }
00458
00459
00460 smb_fft(fft_worksp, fft_frame_size, 1);
00461
00462
00463 for (k = 0; k < fft_frame_size; k++) {
00464 window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5;
00465 output_accum[k] += 2. * window * fft_worksp[2*k] / (fft_frame_size2 * osamp);
00466 }
00467 for (k = 0; k < step_size; k++) {
00468 out_fifo[k] = output_accum[k];
00469 }
00470
00471
00472 memmove(output_accum, output_accum+step_size, fft_frame_size * sizeof(float));
00473
00474
00475 for (k = 0; k < in_fifo_latency; k++) {
00476 in_fifo[k] = in_fifo[k+step_size];
00477 }
00478 }
00479 }
00480 }
00481
00482 static int pitch_shift(struct ast_frame *f, float amount, struct fft_data *fft)
00483 {
00484 int16_t *fun = (int16_t *) f->data.ptr;
00485 int samples;
00486
00487
00488 if (!amount || amount == 1 || !fun || (f->samples % 32)) {
00489 return 0;
00490 }
00491 for (samples = 0; samples < f->samples; samples += 32) {
00492 smb_pitch_shift(amount, 32, MAX_FRAME_LENGTH, 32, ast_format_rate(&f->subclass.format), fun+samples, fun+samples, fft);
00493 }
00494
00495 return 0;
00496 }
00497
00498 static struct ast_custom_function pitch_shift_function = {
00499 .name = "PITCH_SHIFT",
00500 .write = pitchshift_helper,
00501 };
00502
00503 static int unload_module(void)
00504 {
00505 return ast_custom_function_unregister(&pitch_shift_function);
00506 }
00507
00508 static int load_module(void)
00509 {
00510 int res = ast_custom_function_register(&pitch_shift_function);
00511 return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
00512 }
00513
00514 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Audio Effects Dialplan Functions");