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: 328259 $")
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 ast_channel_lock(chan);
00204 if (!(datastore = ast_channel_datastore_find(chan, &pitchshift_datastore, NULL))) {
00205 ast_channel_unlock(chan);
00206
00207 if (!(datastore = ast_datastore_alloc(&pitchshift_datastore, NULL))) {
00208 return 0;
00209 }
00210 if (!(shift = ast_calloc(1, sizeof(*shift)))) {
00211 ast_datastore_free(datastore);
00212 return 0;
00213 }
00214
00215 ast_audiohook_init(&shift->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "pitch_shift", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
00216 shift->audiohook.manipulate_callback = pitchshift_cb;
00217 datastore->data = shift;
00218 new = 1;
00219 } else {
00220 ast_channel_unlock(chan);
00221 shift = datastore->data;
00222 }
00223
00224
00225 if (!strcasecmp(value, "highest")) {
00226 amount = HIGHEST;
00227 } else if (!strcasecmp(value, "higher")) {
00228 amount = HIGHER;
00229 } else if (!strcasecmp(value, "high")) {
00230 amount = HIGH;
00231 } else if (!strcasecmp(value, "lowest")) {
00232 amount = LOWEST;
00233 } else if (!strcasecmp(value, "lower")) {
00234 amount = LOWER;
00235 } else if (!strcasecmp(value, "low")) {
00236 amount = LOW;
00237 } else {
00238 if (!sscanf(value, "%30f", &amount) || (amount <= 0) || (amount > 4)) {
00239 goto cleanup_error;
00240 }
00241 }
00242
00243 if (!strcasecmp(data, "rx")) {
00244 shift->rx.shift_amount = amount;
00245 } else if (!strcasecmp(data, "tx")) {
00246 shift->tx.shift_amount = amount;
00247 } else if (!strcasecmp(data, "both")) {
00248 shift->rx.shift_amount = amount;
00249 shift->tx.shift_amount = amount;
00250 } else {
00251 goto cleanup_error;
00252 }
00253
00254 if (new) {
00255 ast_channel_lock(chan);
00256 ast_channel_datastore_add(chan, datastore);
00257 ast_channel_unlock(chan);
00258 ast_audiohook_attach(chan, &shift->audiohook);
00259 }
00260
00261 return 0;
00262
00263 cleanup_error:
00264
00265 ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
00266 if (new) {
00267 ast_datastore_free(datastore);
00268 }
00269 return -1;
00270 }
00271
00272 static void smb_fft(float *fft_buffer, long fft_frame_size, long sign)
00273 {
00274 float wr, wi, arg, *p1, *p2, temp;
00275 float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i;
00276 long i, bitm, j, le, le2, k;
00277
00278 for (i = 2; i < 2 * fft_frame_size - 2; i += 2) {
00279 for (bitm = 2, j = 0; bitm < 2 * fft_frame_size; bitm <<= 1) {
00280 if (i & bitm) {
00281 j++;
00282 }
00283 j <<= 1;
00284 }
00285 if (i < j) {
00286 p1 = fft_buffer + i; p2 = fft_buffer + j;
00287 temp = *p1; *(p1++) = *p2;
00288 *(p2++) = temp; temp = *p1;
00289 *p1 = *p2; *p2 = temp;
00290 }
00291 }
00292 for (k = 0, le = 2; k < (long) (log(fft_frame_size) / log(2.) + .5); k++) {
00293 le <<= 1;
00294 le2 = le>>1;
00295 ur = 1.0;
00296 ui = 0.0;
00297 arg = M_PI / (le2>>1);
00298 wr = cos(arg);
00299 wi = sign * sin(arg);
00300 for (j = 0; j < le2; j += 2) {
00301 p1r = fft_buffer+j; p1i = p1r + 1;
00302 p2r = p1r + le2; p2i = p2r + 1;
00303 for (i = j; i < 2 * fft_frame_size; i += le) {
00304 tr = *p2r * ur - *p2i * ui;
00305 ti = *p2r * ui + *p2i * ur;
00306 *p2r = *p1r - tr; *p2i = *p1i - ti;
00307 *p1r += tr; *p1i += ti;
00308 p1r += le; p1i += le;
00309 p2r += le; p2i += le;
00310 }
00311 tr = ur * wr - ui * wi;
00312 ui = ur * wi + ui * wr;
00313 ur = tr;
00314 }
00315 }
00316 }
00317
00318 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)
00319 {
00320 float *in_fifo = fft_data->in_fifo;
00321 float *out_fifo = fft_data->out_fifo;
00322 float *fft_worksp = fft_data->fft_worksp;
00323 float *last_phase = fft_data->last_phase;
00324 float *sum_phase = fft_data->sum_phase;
00325 float *output_accum = fft_data->output_accum;
00326 float *ana_freq = fft_data->ana_freq;
00327 float *ana_magn = fft_data->ana_magn;
00328 float *syn_freq = fft_data->syn_freq;
00329 float *sys_magn = fft_data->sys_magn;
00330
00331 double magn, phase, tmp, window, real, imag;
00332 double freq_per_bin, expct;
00333 long i,k, qpd, index, in_fifo_latency, step_size, fft_frame_size2;
00334
00335
00336 fft_frame_size2 = fft_frame_size / 2;
00337 step_size = fft_frame_size / osamp;
00338 freq_per_bin = sample_rate / (double) fft_frame_size;
00339 expct = 2. * M_PI * (double) step_size / (double) fft_frame_size;
00340 in_fifo_latency = fft_frame_size-step_size;
00341
00342 if (fft_data->gRover == 0) {
00343 fft_data->gRover = in_fifo_latency;
00344 }
00345
00346
00347 for (i = 0; i < num_samps_to_process; i++){
00348
00349
00350 in_fifo[fft_data->gRover] = indata[i];
00351 outdata[i] = out_fifo[fft_data->gRover - in_fifo_latency];
00352 fft_data->gRover++;
00353
00354
00355 if (fft_data->gRover >= fft_frame_size) {
00356 fft_data->gRover = in_fifo_latency;
00357
00358
00359 for (k = 0; k < fft_frame_size;k++) {
00360 window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5;
00361 fft_worksp[2*k] = in_fifo[k] * window;
00362 fft_worksp[2*k+1] = 0.;
00363 }
00364
00365
00366
00367 smb_fft(fft_worksp, fft_frame_size, -1);
00368
00369
00370 for (k = 0; k <= fft_frame_size2; k++) {
00371
00372
00373 real = fft_worksp[2*k];
00374 imag = fft_worksp[2*k+1];
00375
00376
00377 magn = 2. * sqrt(real * real + imag * imag);
00378 phase = atan2(imag, real);
00379
00380
00381 tmp = phase - last_phase[k];
00382 last_phase[k] = phase;
00383
00384
00385 tmp -= (double) k * expct;
00386
00387
00388 qpd = tmp / M_PI;
00389 if (qpd >= 0) {
00390 qpd += qpd & 1;
00391 } else {
00392 qpd -= qpd & 1;
00393 }
00394 tmp -= M_PI * (double) qpd;
00395
00396
00397 tmp = osamp * tmp / (2. * M_PI);
00398
00399
00400 tmp = (double) k * freq_per_bin + tmp * freq_per_bin;
00401
00402
00403 ana_magn[k] = magn;
00404 ana_freq[k] = tmp;
00405
00406 }
00407
00408
00409
00410 memset(sys_magn, 0, fft_frame_size * sizeof(float));
00411 memset(syn_freq, 0, fft_frame_size * sizeof(float));
00412 for (k = 0; k <= fft_frame_size2; k++) {
00413 index = k * pitchShift;
00414 if (index <= fft_frame_size2) {
00415 sys_magn[index] += ana_magn[k];
00416 syn_freq[index] = ana_freq[k] * pitchShift;
00417 }
00418 }
00419
00420
00421
00422 for (k = 0; k <= fft_frame_size2; k++) {
00423
00424
00425 magn = sys_magn[k];
00426 tmp = syn_freq[k];
00427
00428
00429 tmp -= (double) k * freq_per_bin;
00430
00431
00432 tmp /= freq_per_bin;
00433
00434
00435 tmp = 2. * M_PI * tmp / osamp;
00436
00437
00438 tmp += (double) k * expct;
00439
00440
00441 sum_phase[k] += tmp;
00442 phase = sum_phase[k];
00443
00444
00445 fft_worksp[2*k] = magn * cos(phase);
00446 fft_worksp[2*k+1] = magn * sin(phase);
00447 }
00448
00449
00450 for (k = fft_frame_size + 2; k < 2 * fft_frame_size; k++) {
00451 fft_worksp[k] = 0.;
00452 }
00453
00454
00455 smb_fft(fft_worksp, fft_frame_size, 1);
00456
00457
00458 for (k = 0; k < fft_frame_size; k++) {
00459 window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5;
00460 output_accum[k] += 2. * window * fft_worksp[2*k] / (fft_frame_size2 * osamp);
00461 }
00462 for (k = 0; k < step_size; k++) {
00463 out_fifo[k] = output_accum[k];
00464 }
00465
00466
00467 memmove(output_accum, output_accum+step_size, fft_frame_size * sizeof(float));
00468
00469
00470 for (k = 0; k < in_fifo_latency; k++) {
00471 in_fifo[k] = in_fifo[k+step_size];
00472 }
00473 }
00474 }
00475 }
00476
00477 static int pitch_shift(struct ast_frame *f, float amount, struct fft_data *fft)
00478 {
00479 int16_t *fun = (int16_t *) f->data.ptr;
00480 int samples;
00481
00482
00483 if (!amount || amount == 1 || !fun || (f->samples % 32)) {
00484 return 0;
00485 }
00486 for (samples = 0; samples < f->samples; samples += 32) {
00487 smb_pitch_shift(amount, 32, MAX_FRAME_LENGTH, 32, ast_format_rate(&f->subclass.format), fun+samples, fun+samples, fft);
00488 }
00489
00490 return 0;
00491 }
00492
00493 static struct ast_custom_function pitch_shift_function = {
00494 .name = "PITCH_SHIFT",
00495 .write = pitchshift_helper,
00496 };
00497
00498 static int unload_module(void)
00499 {
00500 return ast_custom_function_unregister(&pitch_shift_function);
00501 }
00502
00503 static int load_module(void)
00504 {
00505 int res = ast_custom_function_register(&pitch_shift_function);
00506 return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
00507 }
00508
00509 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Audio Effects Dialplan Functions");