2020-11-21 13:54:47 -05:00
|
|
|
/*
|
|
|
|
* High Speed modem to transfer data in a 2,7kHz SSB channel
|
|
|
|
* =========================================================
|
|
|
|
* Author: DJ0ABR
|
|
|
|
*
|
|
|
|
* (c) DJ0ABR
|
|
|
|
* www.dj0abr.de
|
|
|
|
*
|
|
|
|
* 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 2 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*
|
|
|
|
* codec2.c ... function to handle voice transfer via codec2
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "hsmodem.h"
|
|
|
|
|
|
|
|
void sendCodecToModulator(uint8_t* pdata, int len);
|
|
|
|
|
|
|
|
struct CODEC2 *pc2 = NULL;
|
|
|
|
int samplesPerPacket = 160;
|
|
|
|
int bytesPerPacket = 8;
|
|
|
|
|
|
|
|
void init_codec2()
|
|
|
|
{
|
|
|
|
close_codec2();
|
|
|
|
|
|
|
|
if (speedmode == 0)
|
|
|
|
pc2 = codec2_create(CODEC2_MODE_1600);
|
|
|
|
else if(speedmode == 1)
|
|
|
|
pc2 = codec2_create(CODEC2_MODE_2400);
|
|
|
|
else
|
|
|
|
pc2 = codec2_create(CODEC2_MODE_3200);
|
|
|
|
|
|
|
|
if (pc2 == NULL)
|
|
|
|
{
|
|
|
|
printf("cannot create CODEC2\n");
|
|
|
|
}
|
|
|
|
codec2_set_natural_or_gray(pc2, 0);
|
|
|
|
bytesPerPacket = codec2_bits_per_frame(pc2) / 8;
|
|
|
|
samplesPerPacket = codec2_samples_per_frame(pc2);
|
|
|
|
printf("Codec2: BytesPerFrame:%d SamplesPerFrame:%d\n", bytesPerPacket, samplesPerPacket);
|
|
|
|
}
|
|
|
|
|
|
|
|
void close_codec2()
|
|
|
|
{
|
|
|
|
if (pc2 != NULL)
|
|
|
|
{
|
|
|
|
codec2_destroy(pc2);
|
|
|
|
}
|
|
|
|
pc2 = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// encode 160 voice samples (8kS/s) into 64 bits output
|
|
|
|
void encode_codec2(float f)
|
|
|
|
{
|
|
|
|
static int decim = 0;
|
|
|
|
static int16_t sbuf[500]; // this is easily more than "samplesPerPacket" in any cases
|
|
|
|
static int fbuf_idx = 0;
|
|
|
|
uint8_t outbuf[50]; // this is easily more than "bytesPerPacket" in any cases
|
|
|
|
|
|
|
|
if (pc2 == NULL) return;
|
|
|
|
|
|
|
|
// this encoder is called with a sound card sample rate of 48000
|
|
|
|
// codec2 needs 8 kS/s, so we have to decimate by 6
|
|
|
|
if (++decim >= 6)
|
|
|
|
{
|
|
|
|
decim = 0;
|
|
|
|
|
|
|
|
// here we have a sample rate of 8 kS/s
|
|
|
|
// one encoding call needs 160 samples
|
|
|
|
sbuf[fbuf_idx] = (int16_t)(f * 32768); // convert to short
|
|
|
|
if (++fbuf_idx >= samplesPerPacket)
|
|
|
|
{
|
|
|
|
fbuf_idx = 0;
|
|
|
|
|
|
|
|
// we have 160 samples in fbuf, encode them now
|
|
|
|
codec2_encode(pc2, outbuf, sbuf);
|
|
|
|
|
|
|
|
// outbuf is 64bit = 8byte long
|
|
|
|
|
|
|
|
// send Codec data to modulator
|
|
|
|
if (VoiceAudioMode == VOICEMODE_DV_FULLDUPLEX)
|
|
|
|
{
|
|
|
|
memmove(outbuf + 1, outbuf, bytesPerPacket);
|
|
|
|
outbuf[0] = 0xff; // start of codec2 packet marker
|
|
|
|
sendCodecToModulator(outbuf, bytesPerPacket+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VoiceAudioMode == VOICEMODE_CODECLOOP)
|
|
|
|
{
|
|
|
|
// codec loop mode: decode and play it
|
|
|
|
int16_t spbbuf[500];
|
|
|
|
codec2_decode(pc2, spbbuf, outbuf);
|
|
|
|
|
|
|
|
for (int i = 0; i < samplesPerPacket; i++)
|
|
|
|
{
|
|
|
|
float f = (float)spbbuf[i];
|
|
|
|
f /= 32768;
|
|
|
|
// here we have 8kS/s, need to interpolate to 48 kS/s
|
|
|
|
for(int x=0; x<6; x++)
|
2020-12-10 13:14:40 -05:00
|
|
|
io_ls_write_fifo(f);
|
2020-11-21 13:54:47 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CHUNKSIZE_VOICE 40
|
|
|
|
|
|
|
|
void toCodecDecoder_codec2(uint8_t* pdata, int len)
|
|
|
|
{
|
|
|
|
static uint8_t chunk[50];
|
|
|
|
|
|
|
|
// go through all data bytes
|
|
|
|
for (int vd = 0; vd < len; vd++)
|
|
|
|
{
|
|
|
|
// shift the data through the chunk buffer
|
|
|
|
for (int i = 0; i < CHUNKSIZE_VOICE - 1; i++)
|
|
|
|
chunk[i] = chunk[i + 1];
|
|
|
|
chunk[CHUNKSIZE_VOICE - 1] = pdata[vd];
|
|
|
|
|
|
|
|
// an Codec-2 packet has max length of max 8 Byte
|
|
|
|
// in the chunk size of 40 fit minimum 4 chunks
|
|
|
|
// so lets test if 4 chunks are there, by looking for the marker
|
|
|
|
// at distance bytesPerPacket
|
|
|
|
int mfound = 1;
|
|
|
|
for (int m = 0; m < 4; m++)
|
|
|
|
{
|
|
|
|
if (chunk[(bytesPerPacket + 1) * m] != 0xff)
|
|
|
|
{
|
|
|
|
mfound = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mfound)
|
|
|
|
{
|
|
|
|
//showbytestring("OPUS:", chunk + 1, opusPacketSize, opusPacketSize);
|
|
|
|
|
|
|
|
// codec loop mode: decode and play it
|
|
|
|
int16_t spbbuf[500];
|
|
|
|
codec2_decode(pc2, spbbuf, chunk+1);
|
|
|
|
|
|
|
|
for (int i = 0; i < samplesPerPacket; i++)
|
|
|
|
{
|
|
|
|
float f = (float)spbbuf[i];
|
|
|
|
f /= 32768;
|
|
|
|
// here we have 8kS/s, need to interpolate to 48 kS/s
|
|
|
|
for (int x = 0; x < 6; x++)
|
2020-12-10 13:14:40 -05:00
|
|
|
io_ls_write_fifo(f);
|
2020-11-21 13:54:47 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|