Add user space tone generation code

This commit is contained in:
Andreas Eversberg 2022-08-21 07:39:50 +02:00
parent be40b44515
commit 9bbca1fb9e
2 changed files with 478 additions and 0 deletions

465
src/isdn/tones.c Normal file
View File

@ -0,0 +1,465 @@
/*
* Tone generation
*
* Copyright Andreas Eversberg (jolly@eversberg.eu)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stddef.h>
#include "../libdebug/debug.h"
#include "../libg711/g711.h"
#include <mISDN/mbuffer.h>
#include "tones.h"
#define DATA_S sample_silence
#define SIZE_S (&sizeof_silence)
#define DATA_GA sample_german_all
#define SIZE_GA (&sizeof_german_all)
#define DATA_GO sample_german_old
#define SIZE_GO (&sizeof_german_old)
#define DATA_DT sample_american_dialtone
#define SIZE_DT (&sizeof_american_dialtone)
#define DATA_RI sample_american_ringing
#define SIZE_RI (&sizeof_american_ringing)
#define DATA_BU sample_american_busy
#define SIZE_BU (&sizeof_american_busy)
#define DATA_S1 sample_special1
#define SIZE_S1 (&sizeof_special1)
#define DATA_S2 sample_special2
#define SIZE_S2 (&sizeof_special2)
#define DATA_S3 sample_special3
#define SIZE_S3 (&sizeof_special3)
/***************/
/* tones loops */
/***************/
/* all tones are alaw encoded */
/* the last sample+1 is in phase with the first sample. the error is low */
static uint8_t sample_german_all[] = {
0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d,
0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c,
0xdc, 0xfc, 0x6c,
0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d,
0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c,
0xdc, 0xfc, 0x6c,
0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d,
0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c,
0xdc, 0xfc, 0x6c,
0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d,
0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c,
0xdc, 0xfc, 0x6c,
};
static int sizeof_german_all = sizeof(sample_german_all);
static uint8_t sample_german_old[] = {
0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed,
0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70,
0x8c,
0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed,
0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70,
0x8c,
0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed,
0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70,
0x8c,
0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed,
0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70,
0x8c,
};
static int sizeof_german_old = sizeof(sample_german_old);
static uint8_t sample_american_dialtone[] = {
0x2a, 0x18, 0x90, 0x6c, 0x4c, 0xbc, 0x4c, 0x6c,
0x10, 0x58, 0x32, 0xb9, 0x31, 0x2d, 0x8d, 0x0d,
0x8d, 0x2d, 0x31, 0x99, 0x0f, 0x28, 0x60, 0xf0,
0xd0, 0x50, 0xd0, 0x30, 0x60, 0x08, 0x8e, 0x67,
0x09, 0x19, 0x21, 0xe1, 0xd9, 0xb9, 0x29, 0x67,
0x83, 0x02, 0xce, 0xbe, 0xee, 0x1a, 0x1b, 0xef,
0xbf, 0xcf, 0x03, 0x82, 0x66, 0x28, 0xb8, 0xd8,
0xe0, 0x20, 0x18, 0x08, 0x66, 0x8f, 0x09, 0x61,
0x31, 0xd1, 0x51, 0xd1, 0xf1, 0x61, 0x29, 0x0e,
0x98, 0x30, 0x2c, 0x8c, 0x0c, 0x8c, 0x2c, 0x30,
0xb8, 0x33, 0x59, 0x11, 0x6d, 0x4d, 0xbd, 0x4d,
0x6d, 0x91, 0x19,
};
static int sizeof_american_dialtone = sizeof(sample_american_dialtone);
static uint8_t sample_american_ringing[] = {
0x2a, 0xe0, 0xac, 0x0c, 0xbc, 0x4c, 0x8c, 0x90,
0x48, 0xc7, 0xc1, 0xed, 0xcd, 0x4d, 0xcd, 0xed,
0xc1, 0xb7, 0x08, 0x30, 0xec, 0xcc, 0xcc, 0x8c,
0x10, 0x58, 0x1a, 0x99, 0x71, 0xed, 0x8d, 0x8d,
0x2d, 0x41, 0x89, 0x9e, 0x20, 0x70, 0x2c, 0xec,
0x2c, 0x70, 0x20, 0x86, 0x77, 0xe1, 0x31, 0x11,
0xd1, 0xf1, 0x81, 0x09, 0xa3, 0x56, 0x58, 0x00,
0x40, 0xc0, 0x60, 0x38, 0x46, 0x43, 0x57, 0x39,
0xd9, 0x59, 0x99, 0xc9, 0x77, 0x2f, 0x2e, 0xc6,
0xd6, 0x28, 0xd6, 0x36, 0x26, 0x2e, 0x8a, 0xa3,
0x43, 0x63, 0x4b, 0x4a, 0x62, 0x42, 0xa2, 0x8b,
0x2f, 0x27, 0x37, 0xd7, 0x29, 0xd7, 0xc7, 0x2f,
0x2e, 0x76, 0xc8, 0x98, 0x58, 0xd8, 0x38, 0x56,
0x42, 0x47, 0x39, 0x61, 0xc1, 0x41, 0x01, 0x59,
0x57, 0xa2, 0x08, 0x80, 0xf0, 0xd0, 0x10, 0x30,
0xe0, 0x76, 0x87, 0x21, 0x71, 0x2d, 0xed, 0x2d,
0x71, 0x21, 0x9f, 0x88, 0x40, 0x2c, 0x8c, 0x8c,
0xec, 0x70, 0x98, 0x1b, 0x59, 0x11, 0x8d, 0xcd,
0xcd, 0xed, 0x31, 0x09, 0xb6, 0xc0, 0xec, 0xcc,
0x4c, 0xcc, 0xec, 0xc0, 0xc6, 0x49, 0x91, 0x8d,
0x4d, 0xbd, 0x0d, 0xad, 0xe1,
};
static int sizeof_american_ringing = sizeof(sample_american_ringing);
static uint8_t sample_american_busy[] = {
0x2a, 0x00, 0x6c, 0x4c, 0x4c, 0x6c, 0xb0, 0x66,
0x99, 0x11, 0x6d, 0x8d, 0x2d, 0x41, 0xd7, 0x96,
0x60, 0xf0, 0x70, 0x40, 0x58, 0xf6, 0x53, 0x57,
0x09, 0x89, 0xd7, 0x5f, 0xe3, 0x2a, 0xe3, 0x5f,
0xd7, 0x89, 0x09, 0x57, 0x53, 0xf6, 0x58, 0x40,
0x70, 0xf0, 0x60, 0x96, 0xd7, 0x41, 0x2d, 0x8d,
0x6d, 0x11, 0x99, 0x66, 0xb0, 0x6c, 0x4c, 0x4c,
0x6c, 0x00, 0x2a, 0x01, 0x6d, 0x4d, 0x4d, 0x6d,
0xb1, 0x67, 0x98, 0x10, 0x6c, 0x8c, 0x2c, 0x40,
0xd6, 0x97, 0x61, 0xf1, 0x71, 0x41, 0x59, 0xf7,
0x52, 0x56, 0x08, 0x88, 0xd6, 0x5e, 0xe2, 0x2a,
0xe2, 0x5e, 0xd6, 0x88, 0x08, 0x56, 0x52, 0xf7,
0x59, 0x41, 0x71, 0xf1, 0x61, 0x97, 0xd6, 0x40,
0x2c, 0x8c, 0x6c, 0x10, 0x98, 0x67, 0xb1, 0x6d,
0x4d, 0x4d, 0x6d, 0x01,
};
static int sizeof_american_busy = sizeof(sample_american_busy);
static uint8_t sample_special1[] = {
0x2a, 0x2c, 0xbc, 0x6c, 0xd6, 0x71, 0xbd, 0x0d,
0xd9, 0x80, 0xcc, 0x4c, 0x40, 0x39, 0x0d, 0xbd,
0x11, 0x86, 0xec, 0xbc, 0xec, 0x0e, 0x51, 0xbd,
0x8d, 0x89, 0x30, 0x4c, 0xcc, 0xe0, 0xe1, 0xcd,
0x4d, 0x31, 0x88, 0x8c, 0xbc, 0x50, 0x0f, 0xed,
0xbd, 0xed, 0x87, 0x10, 0xbc, 0x0c, 0x38, 0x41,
0x4d, 0xcd, 0x81, 0xd8, 0x0c, 0xbc, 0x70, 0xd7,
0x6d, 0xbd, 0x2d,
};
static int sizeof_special1 = sizeof(sample_special1);
static uint8_t sample_special2[] = {
0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc,
0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d,
0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6,
0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0,
0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd,
0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc,
0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d,
0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6,
0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0,
0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd,
};
static int sizeof_special2 = sizeof(sample_special2);
static uint8_t sample_special3[] = {
0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1,
0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c,
0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc,
0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7,
0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd,
0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1,
0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c,
0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc,
0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7,
0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd,
};
static int sizeof_special3 = sizeof(sample_special3);
static uint8_t sample_silence[] = {
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
};
static int sizeof_silence = sizeof(sample_silence);
struct tones_samples {
int *len;
uint8_t *data;
};
static struct
tones_samples samples[] = {
{&sizeof_german_all, sample_german_all},
{&sizeof_german_old, sample_german_old},
{&sizeof_american_dialtone, sample_american_dialtone},
{&sizeof_american_ringing, sample_american_ringing},
{&sizeof_american_busy, sample_american_busy},
{&sizeof_special1, sample_special1},
{&sizeof_special2, sample_special2},
{&sizeof_special3, sample_special3},
{NULL, NULL},
};
/***********************************
* generate ulaw from alaw samples *
***********************************/
void isdn_tone_generate_ulaw_samples(void)
{
int i;
int16_t *audio;
int audio_len;
uint8_t *data;
int len;
i = 0;
while (samples[i].len) {
g711_decode_alaw_flipped(samples[i].data, *samples[i].len, (uint8_t **)&audio, &audio_len);
g711_encode_ulaw_flipped((uint8_t *)audio, audio_len, &data, &len);
memcpy(samples[i].data, data, len);
free(audio);
free(data);
i++;
}
}
/****************************
* tone sequence definition *
****************************/
static struct pattern {
int tone;
uint8_t *data[10];
int *siz[10];
int seq[10];
} pattern[] = {
{TONE_GERMAN_DIALTONE,
{DATA_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{1900, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_GERMAN_OLDDIALTONE,
{DATA_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{7956, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_AMERICAN_DIALTONE,
{DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{8008, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_GERMAN_DIALPBX,
{DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL,
NULL},
{SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL,
NULL},
{2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
{TONE_GERMAN_OLDDIALPBX,
{DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL,
NULL},
{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL,
NULL},
{2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
{TONE_AMERICAN_DIALPBX,
{DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL,
NULL},
{SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL,
NULL},
{2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
{TONE_GERMAN_RINGING,
{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_GERMAN_OLDRINGING,
{DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{8000, 40000, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_AMERICAN_RINGING,
{DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_GERMAN_RINGPBX,
{DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
{4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} },
{TONE_GERMAN_OLDRINGPBX,
{DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
{4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} },
{TONE_AMERICAN_RINGPBX,
{DATA_RI, DATA_S, DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
{4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} },
{TONE_GERMAN_BUSY,
{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_GERMAN_OLDBUSY,
{DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_AMERICAN_BUSY,
{DATA_BU, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_BU, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_GERMAN_HANGUP,
{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_GERMAN_OLDHANGUP,
{DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_AMERICAN_HANGUP,
{DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_SPECIAL_INFO,
{DATA_S1, DATA_S2, DATA_S3, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
{2666, 2666, 2666, 8002, 0, 0, 0, 0, 0, 0} },
{TONE_GERMAN_GASSENBESETZT,
{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{2000, 2000, 0, 0, 0, 0, 0, 0, 0, 0} },
{TONE_GERMAN_AUFSCHALTTON,
{DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
{1000, 5000, 1000, 17000, 0, 0, 0, 0, 0, 0} },
{0,
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
};
/******************
* copy tone data *
******************/
/* the count will be changed and may begin from 0 each pattern period.
* the clue is to precalculate the pointers and legths to use only one
* memcpy per function call, or two memcpy if the tone sequence changes.
*
* pattern - the type of the pattern
* count - the sample from the beginning of the pattern (phase)
* len - the number of bytes
*/
void isdn_tone_copy(struct isdn_tone *t, uint8_t *data, int len)
{
int index, count, start, num;
struct pattern *pat;
/* if we have no tone, we do not overwrite data */
if (!t->tone)
return;
/* process pattern */
pat = (struct pattern *)t->pattern;
/* points to the current pattern */
index = t->index; /* gives current sequence index */
count = t->count; /* gives current sample */
/* copy sample */
while (len) {
/* find sample to start with */
while (42) {
/* wrap around */
if (!pat->seq[index]) {
count = 0;
index = 0;
}
/* check if we are currently playing this tone */
if (count < pat->seq[index])
break;
count -= pat->seq[index];
index++;
}
/* calculate start and number of samples */
start = count % (*(pat->siz[index]));
num = len;
if (num + count > pat->seq[index])
num = pat->seq[index] - count;
if (num + start > (*(pat->siz[index])))
num = (*(pat->siz[index])) - start;
/* copy memory */
memcpy(data, pat->data[index] + start, num);
/* reduce length */
data += num;
count += num;
len -= num;
}
t->index = index;
t->count = count;
}
/********************
* set/release tone *
********************/
int isdn_tone_set(struct isdn_tone *t, int tone)
{
struct pattern *pat;
int i;
/* we turn off the tone */
if (!tone) {
t->tone = 0;
return 0;
}
pat = NULL;
i = 0;
while (pattern[i].tone) {
if (pattern[i].tone == tone) {
pat = &pattern[i];
break;
}
i++;
}
if (!pat) {
PDEBUG(DISDN, DEBUG_ERROR, "given tone 0x%x is invalid\n", tone);
return -EINVAL;
}
PDEBUG(DISDN, DEBUG_DEBUG, "playing given tone 0x%x\n", tone);
t->tone = tone;
t->pattern = pat;
t->index = 0;
t->count = 0;
return 0;
}

13
src/isdn/tones.h Normal file
View File

@ -0,0 +1,13 @@
struct isdn_tone {
int tone;
void *pattern;
int count;
int index;
};
void isdn_tone_generate_ulaw_samples(void);
void isdn_tone_copy(struct isdn_tone *t, uint8_t *data, int len);
int isdn_tone_set(struct isdn_tone *t, int tone);