Browse Source

Add A-Law mode

master
Jeroen Vreeken 5 years ago
parent
commit
e25bb642fa
5 changed files with 225 additions and 41 deletions
  1. +1
    -0
      Makefile
  2. +122
    -0
      alaw.c
  3. +27
    -0
      alaw.h
  4. +73
    -41
      analog_trx.c
  5. +2
    -0
      eth_ar.h

+ 1
- 0
Makefile View File

@ -8,6 +8,7 @@ SRCS = \
eth_ar.c \
interface.c \
sound.c \
alaw.c \
dsp.c
OBJS = $(SRCS:.c=.o)


+ 122
- 0
alaw.c View File

@ -0,0 +1,122 @@
/* A-law code from GStreamer
* Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
* PCM - A-Law conversion
* Copyright (C) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "alaw.h"
#include <stdint.h>
static int16_t alaw_to_s16 (uint8_t a_val)
{
int t;
int seg;
a_val ^= 0x55;
t = a_val & 0x7f;
if (t < 16)
t = (t << 4) + 8;
else {
seg = (t >> 4) & 0x07;
t = ((t & 0x0f) << 4) + 0x108;
t <<= seg - 1;
}
return ((a_val & 0x80) ? t : -t);
}
void alaw_decode(int16_t *samples, uint8_t *alaw, int nr)
{
int i;
for (i = 0; i < nr; i++) {
samples[i] = alaw_to_s16(alaw[i]);
}
}
/*
* s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
*
* s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
*
* Linear Input Code Compressed Code
* ------------------------ ---------------
* 0000000wxyza 000wxyz
* 0000001wxyza 001wxyz
* 000001wxyzab 010wxyz
* 00001wxyzabc 011wxyz
* 0001wxyzabcd 100wxyz
* 001wxyzabcde 101wxyz
* 01wxyzabcdef 110wxyz
* 1wxyzabcdefg 111wxyz
*
* For further information see John C. Bellamy's Digital Telephony, 1982,
* John Wiley & Sons, pps 98-111 and 472-476.
*/
static int val_seg (int val)
{
int r = 1;
val >>= 8;
if (val & 0xf0) {
val >>= 4;
r += 4;
}
if (val & 0x0c) {
val >>= 2;
r += 2;
}
if (val & 0x02)
r += 1;
return r;
}
static uint8_t s16_to_alaw (int16_t pcm_val)
{
int seg;
uint8_t mask;
uint8_t aval;
if (pcm_val >= 0) {
mask = 0xD5;
} else {
mask = 0x55;
pcm_val = -pcm_val;
if (pcm_val > 0x7fff)
pcm_val = 0x7fff;
}
if (pcm_val < 256)
aval = pcm_val >> 4;
else {
/* Convert the scaled magnitude to segment number. */
seg = val_seg (pcm_val);
aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
}
return aval ^ mask;
}
void alaw_encode(uint8_t *alaw, int16_t *samples, int nr)
{
int i;
for (i = 0; i < nr; i++) {
alaw[i] = s16_to_alaw(samples[i]);
}
}

+ 27
- 0
alaw.h View File

@ -0,0 +1,27 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2016
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INCLUDE_ALAW_H_
#define _INCLUDE_ALAW_H_
#include <stdint.h>
void alaw_decode(int16_t *samples, uint8_t *alaw, int nr);
void alaw_encode(uint8_t *alaw, int16_t *samples, int nr);
#endif /* _INCLUDE_ALAW_H_ */

+ 73
- 41
analog_trx.c View File

@ -34,6 +34,7 @@
#include "eth_ar.h"
#include "sound.h"
#include "dtmf.h"
#include "alaw.h"
static bool verbose = false;
@ -153,28 +154,36 @@ static void cb_sound_in(int16_t *samples, int nr)
dtmf_rx(samples, nr, cb_control);
while (nr) {
int copy = nr_samples - nr_rx;
if (copy > nr)
copy = nr;
if (rx_codec) {
while (nr) {
int copy = nr_samples - nr_rx;
if (copy > nr)
copy = nr;
memcpy(samples_rx + nr_rx, samples, copy);
samples += copy;
nr -= copy;
nr_rx += copy;
memcpy(samples_rx + nr_rx, samples, copy);
samples += copy;
nr -= copy;
nr_rx += copy;
if (nr_rx == nr_samples) {
if (rx_state) {
int bytes_per_codec_frame = (codec2_bits_per_frame(rx_codec) + 7)/8;
unsigned char packed_codec_bits[bytes_per_codec_frame];
codec2_encode(rx_codec, packed_codec_bits, samples_rx);
interface_rx(packed_codec_bits, bytes_per_codec_frame,
ETH_P_CODEC2_1600);
if (nr_rx == nr_samples) {
if (rx_state) {
int bytes_per_codec_frame = (codec2_bits_per_frame(rx_codec) + 7)/8;
unsigned char packed_codec_bits[bytes_per_codec_frame];
codec2_encode(rx_codec, packed_codec_bits, samples_rx);
interface_rx(packed_codec_bits, bytes_per_codec_frame,
ETH_P_CODEC2_3200);
}
nr_rx = 0;
}
nr_rx = 0;
}
} else {
uint8_t alaw[nr];
alaw_encode(alaw, samples, nr);
interface_rx(alaw, nr, ETH_P_ALAW);
}
}
@ -187,6 +196,8 @@ static int tx_bytes_per_codec_frame = 8;
static int cb_int_tx(uint8_t *data, size_t len, uint16_t eth_type)
{
int newmode = 0;
bool is_c2 = true;
switch (eth_type) {
case ETH_P_CODEC2_3200:
newmode = CODEC2_MODE_3200;
@ -212,11 +223,14 @@ static int cb_int_tx(uint8_t *data, size_t len, uint16_t eth_type)
case ETH_P_CODEC2_700B:
newmode = CODEC2_MODE_700B;
break;
case ETH_P_ALAW:
is_c2 = false;
break;
default:
return 0;
}
if (newmode != tx_mode) {
if (is_c2 && newmode != tx_mode) {
if (tx_codec)
codec2_destroy(tx_codec);
tx_codec = codec2_create(newmode);
@ -225,28 +239,36 @@ static int cb_int_tx(uint8_t *data, size_t len, uint16_t eth_type)
tx_bytes_per_codec_frame = (codec2_bits_per_frame(tx_codec) + 7)/8;
}
while (len) {
size_t copy = len;
if (copy + tx_data_len > tx_bytes_per_codec_frame)
copy = tx_bytes_per_codec_frame - tx_data_len;
memcpy(tx_data + tx_data_len, data, copy);
tx_data_len += copy;
data += copy;
len -= copy;
if (tx_data_len == tx_bytes_per_codec_frame) {
int nr = codec2_samples_per_frame(tx_codec);
int16_t mod_out[nr];
if (is_c2) {
while (len) {
size_t copy = len;
if (copy + tx_data_len > tx_bytes_per_codec_frame)
copy = tx_bytes_per_codec_frame - tx_data_len;
codec2_decode(tx_codec, mod_out, tx_data);
memcpy(tx_data + tx_data_len, data, copy);
tx_data_len += copy;
data += copy;
len -= copy;
if (nr > 0) {
sound_out(mod_out, nr);
if (tx_data_len == tx_bytes_per_codec_frame) {
int nr = codec2_samples_per_frame(tx_codec);
int16_t mod_out[nr];
codec2_decode(tx_codec, mod_out, tx_data);
if (nr > 0) {
sound_out(mod_out, nr);
}
tx_data_len = 0;
}
tx_data_len = 0;
}
} else {
int16_t mod_out[len];
alaw_decode(mod_out, data, len);
sound_out(mod_out, len);
}
return 0;
@ -361,6 +383,7 @@ static void usage(void)
{
printf("Options:\n");
printf("-v\tverbose\n");
printf("-a\tUse A-Law encoding\n");
printf("-c [call]\town callsign\n");
printf("-f\tfull-duplex\n");
printf("-s [dev]\tSound device (default: \"default\")\n");
@ -388,15 +411,19 @@ int main(int argc, char **argv)
int poll_int;
int poll_tty;
int opt;
int mode = CODEC2_MODE_1600;
int mode = CODEC2_MODE_3200;
bool is_c2 = true;
rig_model = 1; // set to dummy.
while ((opt = getopt(argc, argv, "vc:s:n:m:d:t:p:P:D:f")) != -1) {
while ((opt = getopt(argc, argv, "vac:s:n:m:d:t:p:P:D:f")) != -1) {
switch(opt) {
case 'v':
verbose = true;
break;
case 'a':
is_c2 = false;
break;
case 'c':
call = optarg;
break;
@ -464,8 +491,13 @@ int main(int argc, char **argv)
eth_ar_call2mac(mac, call, ssid, false);
rx_codec = codec2_create(mode);
nr_samples = codec2_samples_per_frame(rx_codec);
if (is_c2) {
rx_codec = codec2_create(mode);
nr_samples = codec2_samples_per_frame(rx_codec);
} else {
rx_codec = NULL;
nr_samples = 160;
}
samples_rx = calloc(nr_samples, sizeof(samples_rx[0]));
tx_data = calloc(16, sizeof(uint8_t));


+ 2
- 0
eth_ar.h View File

@ -32,6 +32,8 @@
#define ETH_P_AR_CONTROL 0x7342
#define ETH_P_ALAW 0x7365
#define ETH_AR_CALL_LEN_MAX 8
#define ETH_AR_CALL_SIZE 9


Loading…
Cancel
Save