This commit is contained in:
Kurt Moraw 2020-11-21 19:54:47 +01:00
parent e335d4efbf
commit 327efc82e3
112 changed files with 7468 additions and 591 deletions

Binary file not shown.

View File

@ -2,7 +2,7 @@
The purpose of this project is to transfer data (pictures...) via a 2,7kHz SSB channel on the narrow band transponder as fast as possible.
# this is work in progress
Version 0.2 is working on:
Version 0.4 is working on:
Windows 10 (should work on Win7, not tested)
linux Desktop PC,
Odroid SBC
@ -27,6 +27,7 @@ this software uses these programs:
* liquid-SDR: https://github.com/jgaeddert/liquid-dsp (MIT License)
* BASS Audio: https://www.un4seen.com/ (free for non-commercial use)
* fftw3: http://www.fftw.org (GPL V.2 or later)
* libcodec2 (Linux: standard lib, Windows: from freeDV)
# building the software
* Linux
@ -42,12 +43,18 @@ this software uses these programs:
you need to run 2 programs, the first one is "hsmodem" which runs in a termimal without GUI. This is the modem doing all modulation and demodulation staff.
The second program is the user interface "oscardata.exe".
1. go into the folder "WinRelease" or "LinuxRelease"
* Windows
copy all files from "WinRelease" into any folder of your choice. Start oscardata.exe by double-clicking.
The application oscardata.exe can also run on a different PC in your home network, see Linux version.
Even a mix between Linux and Windows is possible, so running oscardata.exe on a Windows PC and
running the hsmodem on another computer in the shack.
* Linux
1. go into the folder "LinuxRelease"
2. run the software: ./hs100modem.exe or ./hsmodem
optional command line parameter:
no parameter ... normal usage
-m IP ... specify the V4 IP adress of the device where the application software is running. This is useful if you have more than one qo100modem running simultaneously. Without this parameter the app will search the modem automatically.
3. start the user application on any PC in your home network. It will find the modem automatically
The file is located in oscardata/oscardata/bin/Release
On windows just start oscardata.exe
@ -58,8 +65,6 @@ On Linux start it with: mono oscardata.exe
* QO-100 via IC-9700, IC-7300 or IC-7100 ... working
* Short Wave 6m band via IC-7300, IC-7100 ... working. In case of significant noise, use the lowest bit rate (3000 bit/s)
# TODOs
the current version V0.2 runs very fine on Linux but shows a higher bit error rate on Windows. This has to do with the initialisation of the sound card. The default sound bitrate setting in the Windows-Sound-Settings implement some kind of "filtering". This is currently under evaluation.
# usage

Binary file not shown.

BIN
WinRelease/libcodec2.dll Executable file

Binary file not shown.

BIN
WinRelease/libgcc_s_sjlj-1.dll Executable file

Binary file not shown.

BIN
WinRelease/liblpcnetfreedv.dll Executable file

Binary file not shown.

BIN
WinRelease/libwinpthread-1.dll Executable file

Binary file not shown.

Binary file not shown.

View File

@ -1,8 +1,8 @@
# makefile for dv_serial
# makefile for hsmodem
CXXFLAGS = -Wall -O3 -std=c++0x -Wno-write-strings -Wno-narrowing
LDFLAGS = -lpthread -lrt -lsndfile -lasound -lm -lbass -lbassflac -lfftw3 -lfftw3_threads -lliquid
OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o scrambler.o speed.o fec.o audio.o udp.o fft.o liquid_if.o symboltracker.o
LDFLAGS = -lpthread -lrt -lsndfile -lasound -lm -lopus -lbassopus -lbass -lbassenc_opus -lbassenc -lfftw3 -lfftw3_threads -lliquid -lcodec2
OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o scrambler.o speed.o fec.o audio.o udp.o fft.o liquid_if.o symboltracker.o audio_voice.o voiceprocessor.o codec2.o
default: $(OBJ)
g++ $(CXXFLAGS) -o ../LinuxRelease/hsmodem $(OBJ) $(LDFLAGS)

View File

@ -38,7 +38,6 @@
BOOL CALLBACK RecordingCallback(HRECORD handle, const void *buffer, DWORD length, void *user);
DWORD CALLBACK WriteStream(HSTREAM handle, float *buffer, DWORD length, void *user);
int pb_read_fifo(float *data, int elements);
void close_audio();
void cap_write_fifo(float sample);
int pb_fifo_freespace(int nolock);
void init_pipes();
@ -96,12 +95,6 @@ uint8_t devstring[MAXDEVSTRLEN +100];
char PBdevs[100][256]; // stores the device names, just for diagnosis, has no real fuction
char CAPdevs[100][256];
// audio device description table
typedef struct {
int bassdev; // bass (basswasapi) dev no
char name[256]; // DEV name
} AUDIODEVS;
// index is enumerated number, 0=default
AUDIODEVS audioPBdevs[100];
AUDIODEVS audioCAPdevs[100];
@ -111,6 +104,8 @@ int pbanz = 0, capanz = 0;
void readAudioDevs()
{
int a;
pbanz = 0;
capanz = 0;
// enter default device manually
audioPBdevs[pbanz].bassdev = -1;
@ -125,7 +120,7 @@ void readAudioDevs()
BASS_DEVICEINFO info;
for (a = 1; BASS_GetDeviceInfo(a, &info); a++)
{
showDeviceInfo(info);
//showDeviceInfo(info);
if (info.flags & BASS_DEVICE_ENABLED && !(info.flags & BASS_DEVICE_LOOPBACK))
{
if (!strstr(info.name, "efault"))
@ -133,6 +128,7 @@ void readAudioDevs()
audioPBdevs[pbanz].bassdev = a;
strncpy(audioPBdevs[pbanz].name, info.name, 255);
audioPBdevs[pbanz].name[255] = 0;
strncpy(audioPBdevs[pbanz].id, info.driver, 255);
pbanz++;
}
}
@ -148,6 +144,7 @@ void readAudioDevs()
audioCAPdevs[capanz].bassdev = a;
strncpy(audioCAPdevs[capanz].name, info.name, 255);
audioCAPdevs[capanz].name[255] = 0;
strncpy(audioCAPdevs[capanz].id, info.driver, 255);
capanz++;
}
}
@ -166,6 +163,7 @@ void readAudioDevs()
audioPBdevs[pbanz].bassdev = a;
strncpy(audioPBdevs[pbanz].name, info.name, 255);
audioPBdevs[pbanz].name[255] = 0;
strncpy(audioPBdevs[pbanz].id, info.id, 255);
pbanz++;
}
}
@ -177,6 +175,7 @@ void readAudioDevs()
audioCAPdevs[capanz].bassdev = a;
strncpy(audioCAPdevs[capanz].name, info.name, 255);
audioCAPdevs[capanz].name[255] = 0;
strncpy(audioCAPdevs[capanz].id, info.id, 255);
capanz++;
}
}
@ -188,11 +187,11 @@ void printAudioDevs()
{
printf("PB devices:\n");
for (int i = 0; i < pbanz; i++)
printf("idx:%d bass:%d name:%s\n", i, audioPBdevs[i].bassdev, audioPBdevs[i].name);
printf("idx:%d ID:%s bass:%d name:%s\n", i, audioPBdevs[i].id, audioPBdevs[i].bassdev, audioPBdevs[i].name);
printf("CAP devices:\n");
for (int i = 0; i < capanz; i++)
printf("idx:%d bass:%d name:%s\n", i, audioCAPdevs[i].bassdev, audioCAPdevs[i].name);
printf("idx:%d ID:%s bass:%d name:%s\n", i, audioCAPdevs[i].id, audioCAPdevs[i].bassdev, audioCAPdevs[i].name);
}
// build string of audio device name, to be sent to application as response to Broadcast search
@ -202,6 +201,11 @@ void buildUdpAudioList()
{
memset(devstring, 0, sizeof(devstring));
devstring[0] = ' '; // placeholder for ID for this UDP message
devstring[1] = '0' + init_audio_result;
devstring[2] = '0' + init_voice_result;
//printf("init_voice_result:%d\n", devstring[2]);
// playback devices
for (int i = 0; i < pbanz; i++)
@ -226,22 +230,34 @@ void buildUdpAudioList()
uint8_t* getAudioDevicelist(int *len)
{
// update Status
devstring[1] = '0' + init_audio_result;
devstring[2] = '0' + init_voice_result;
*len = strlen((char*)(devstring+1))+1;
return devstring;
}
// pbdev, capdev: -1=default device
// read audio device list at program start, or if something went wrong
void readAudioDevices()
{
readAudioDevs();
//printAudioDevs();
buildUdpAudioList();
return;
}
// ret: 0=ok, -1=system error, 1=pb error 2=cap error 3=pb+cap error
int init_audio(int setpbdev, int setcapdev)
{
static int f = 1;
int ret = 0;
if (f == 1)
{
// do only once after program start
f = 0;
readAudioDevs();
printAudioDevs();
buildUdpAudioList();
readAudioDevices();
init_pipes();
}
@ -262,7 +278,7 @@ static int f = 1;
if (HIWORD(BASS_GetVersion()) != BASSVERSION)
{
printf("An incorrect version of BASS was loaded\n");
return -1;
return 3;
}
#ifdef _WIN32_
@ -279,25 +295,31 @@ static int f = 1;
if (!BASS_Init(pbdev, caprate, 0, NULL, NULL))
{
printf("Can't initialize output device: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
ret = 1;
}
// read real device number
int ret = BASS_GetDevice();
if (ret == -1)
else
{
printf("BASS_GetDevice: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
}
pbdev = ret;
openpbdev = pbdev;
printf("real BASS PB Device No: %d\n", pbdev);
// set play callback
BASS_GetInfo(&info);
stream = BASS_StreamCreate(info.freq, CHANNELS, BASS_SAMPLE_FLOAT, (STREAMPROC*)WriteStream, 0); // sample: 32 bit float
BASS_ChannelSetAttribute(stream, BASS_ATTRIB_BUFFER, 0); // no buffering for minimum latency
BASS_ChannelPlay(stream, FALSE); // start it
// read real device number
int device = BASS_GetDevice();
if (device == -1)
{
printf("BASS_GetDevice: %d err:%d\n", pbdev, BASS_ErrorGetCode());
ret = 1;
}
else
{
pbdev = device;
openpbdev = pbdev;
printf("real BASS PB Device No: %d\n", pbdev);
// set play callback
BASS_GetInfo(&info);
stream = BASS_StreamCreate(info.freq, CHANNELS, BASS_SAMPLE_FLOAT, (STREAMPROC*)WriteStream, 0); // sample: 32 bit float
BASS_ChannelSetAttribute(stream, BASS_ATTRIB_BUFFER, 0); // no buffering for minimum latency
BASS_ChannelPlay(stream, FALSE); // start it
}
}
// ===== CAPTURE ====
@ -305,51 +327,56 @@ static int f = 1;
if (!BASS_RecordInit(capdev))
{
printf("Can't initialize recording device: %d err:%d\n", capdev, BASS_ErrorGetCode());
return -1;
ret |= 2;
}
// read real device number
ret = BASS_GetDevice();
if (ret == -1)
else
{
printf("BASS_GetDevice: %d err:%d\n", capdev, BASS_ErrorGetCode());
return -1;
}
capdev = ret;
printf("real BASS CAP Device No: %d\n", capdev);
// set capture callback
rchan = BASS_RecordStart(caprate, CHANNELS, BASS_SAMPLE_FLOAT, RecordingCallback, 0);
if (!rchan) {
printf("Can't start capturing: %d\n", BASS_ErrorGetCode());
return -1;
// read real device number
int device = BASS_RecordGetDevice();
if (device == -1)
{
printf("BASS_GetDevice: %d err:%d\n", capdev, BASS_ErrorGetCode());
ret |= 2;
}
else
{
capdev = device;
printf("real BASS CAP Device No: %d\n", capdev);
// set capture callback
if (rchan) BASS_ChannelStop(rchan);
rchan = BASS_RecordStart(caprate, CHANNELS, BASS_SAMPLE_FLOAT, RecordingCallback, 0);
if (!rchan)
{
printf("Can't start capturing: %d\n", BASS_ErrorGetCode());
ret |= 2;
}
else
opencapdev = capdev;
}
}
printf("audio initialized\n");
if(ret == 0)
printf("audio started successfully for PBdev:%d and CAPdev:%d\n", openpbdev, opencapdev);
else
{
opencapdev = -1;
openpbdev = -1;
readAudioDevices();
}
if (ret == 1)
printf("audio initialized: PBerror CapOK\n");
if (ret == 2)
printf("audio initialized: PBOK CapERROR\n");
if (ret == 3)
printf("audio initialized: PBerror CapERROR\n");
opencapdev = capdev;
return 0;
return ret;
#endif
}
#ifdef _LINUX_
void close_audio()
{
if(stream != 0)
{
printf("close Audio Devices\n");
BASS_ChannelStop(rchan);
int rr = BASS_RecordFree();
if (!rr) printf("Bass_RecordFree error: %d\n", BASS_ErrorGetCode());
BASS_StreamFree(stream);
int r = BASS_Free();
if(!r) printf("Bass_Free error: %d\n", BASS_ErrorGetCode());
stream = 0;
}
}
void selectPBdevice()
{
if (!BASS_SetDevice(openpbdev))
@ -362,6 +389,24 @@ void selectCAPdevice()
printf("BASS_SetDevice: %d err:%d\n", opencapdev, BASS_ErrorGetCode());
}
void close_audio()
{
if(stream != 0)
{
printf("close Audio Devices\n");
selectCAPdevice();
BASS_ChannelStop(rchan);
int rr = BASS_RecordFree();
if (!rr) printf("Bass_RecordFree error: %d\n", BASS_ErrorGetCode());
selectPBdevice();
BASS_StreamFree(stream);
int r = BASS_Free();
if(!r) printf("Bass_Free error: %d\n", BASS_ErrorGetCode());
stream = 0;
}
}
void setPBvolume(int v)
{
// the volume comes in % 0..99
@ -429,7 +474,7 @@ void setVolume(int pbcap, int v)
{
if (pbcap == 0) setPBvolume(v);
else setCAPvolume(v);
}
}
// ================ thread safe fifo for audio callback routines ===============
@ -460,9 +505,8 @@ void CAP_UNLOCK() { pthread_mutex_unlock(&cap_crit_sec); }
void PB_UNLOCK() { pthread_mutex_unlock(&pb_crit_sec); }
#endif
#define AUDIO_BUFFERMAXTIME 2 // fifo can buffer this time in [s]
#define AUDIO_PLAYBACK_BUFLEN (48000 * 10) // space for 10 seconds of samples
#define AUDIO_CAPTURE_BUFLEN (48000) // space for 1s
#define AUDIO_CAPTURE_BUFLEN 24000 // space for 0.5s
int cap_wridx=0;
int cap_rdidx=0;
@ -496,6 +540,10 @@ void cap_write_fifo(float sample)
cap_buffer[cap_wridx] = sample;
if(++cap_wridx >= AUDIO_CAPTURE_BUFLEN) cap_wridx = 0;
CAP_UNLOCK();
// if monitoring is activated then write it also to the voice fifo
if (VoiceAudioMode == VOICEMODE_LISTENAUDIOIN)
toVoice(sample);
}
int cap_read_fifo(float *data)
@ -516,6 +564,35 @@ int cap_read_fifo(float *data)
return 1;
}
void cap_write_fifo_clear()
{
cap_wridx = cap_rdidx = 0;
}
int cap_fifo_freespace()
{
int freebuf = 0;
CAP_LOCK;
int elemInFifo = (cap_wridx + AUDIO_CAPTURE_BUFLEN - cap_rdidx) % AUDIO_CAPTURE_BUFLEN;
freebuf = AUDIO_CAPTURE_BUFLEN - elemInFifo;
CAP_UNLOCK();
return freebuf;
}
int cap_fifo_usedPercent()
{
int fs = cap_fifo_freespace();
int used = AUDIO_CAPTURE_BUFLEN - fs;
used = (used * 100) / AUDIO_CAPTURE_BUFLEN;
if (used < 5) printf("used:%d\n", used);
return used;
}
void pb_write_fifo(float sample)
{
PB_LOCK;
@ -580,6 +657,7 @@ int pb_read_fifo(float *data, int elements)
{
// Fifo empty, no data available
PB_UNLOCK();
//printf("pb fifo empty: TX underrun\n");
//printf("pb fifo empty, need:%d have:%d size:%d\n",elements,e,AUDIO_PLAYBACK_BUFLEN);
return 0;
}
@ -595,7 +673,13 @@ int pb_read_fifo(float *data, int elements)
return 1;
}
// ================ Play FLAC Audio File ===========================
void clear_audio_fifos()
{
pb_write_fifo_clear();
cap_write_fifo_clear();
}
// ================ Play PCM Audio File ===========================
typedef struct _AUDIOFILES_ {
char fn[256];

Binary file not shown.

500
hsmodem/audio_voice.cpp Executable file
View File

@ -0,0 +1,500 @@
/*
* 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.
*
* audio.c ... very similar to audio.c but is used for Microphone / Loudspeaker
*
*/
#include "hsmodem.h"
void init_pipes_voice();
BOOL CALLBACK RecordingCallback_voice(HRECORD handle, const void* buffer, DWORD length, void* user);
DWORD CALLBACK WriteStream_voice(HSTREAM handle, float* buffer, DWORD length, void* user);
//void CALLBACK EncodeProc(HENCODE handle, DWORD channel, const void* buffer, DWORD length, void* user);
void cap_write_fifo_voice(float sample);
int pb_read_fifo_voice(float* data, int elements);
void setLSvolume(int v);
void setMICvolume(int v);
extern AUDIODEVS audioPBdevs[100];
extern AUDIODEVS audioCAPdevs[100];
extern int pbanz;
extern int capanz;
HRECORD rchan_voice = 0; // recording channel
BASS_INFO info_voice;
HSTREAM stream_voice = 0;
int openpbdev_voice = -1;
int opencapdev_voice = -1;
int caprate_voice = VOICE_SAMPRATE;
int initialLSvol = -1;
int initialMICvol = -1;
float softwareCAPvolume_voice = 1;
// pbdev, capdev: -1=default device
int init_audio_voice(int setpbdev, int setcapdev)
{
static int f = 1;
int ret = 0;
if (f == 1)
{
// do only once after program start
f = 0;
init_pipes_voice();
}
// translate requested device numbers to bass device numbers
if (setpbdev < 0 || setpbdev >= pbanz) setpbdev = 0;
if (setcapdev < 0 || setcapdev >= capanz) setcapdev = 0;
int pbdev = -1;
if (setpbdev >= 0 && setpbdev < pbanz) pbdev = audioPBdevs[setpbdev].bassdev;
int capdev = -2;
if (setcapdev >= 0 && setcapdev < capanz) capdev = audioCAPdevs[setcapdev].bassdev;
printf("voice: init audio_voice, caprate:%d\n", caprate_voice);
printf("voice: requested LS device: %d bassno:%d name:%s\n", setpbdev, pbdev, audioPBdevs[setpbdev].name);
printf("voice: requested MIC device: %d bassno:%d name:%s\n", setcapdev, capdev, audioCAPdevs[setcapdev].name);
#ifdef _WIN32_
// use WASAPI for Windows to get exclusive access to sound card
return init_wasapi_voice(pbdev, capdev);
#endif
#ifdef _LINUX_
close_audio_voice();
if (VoiceAudioMode == 0) return 0; // Voice off
// ===== PLAYBACK ======
// initialize default output device
if (!BASS_Init(pbdev, caprate_voice, 0, NULL, NULL))
{
printf("voice: Can't initialize output device: %d err:%d\n", pbdev, BASS_ErrorGetCode());
close_audio_voice();
ret = 1;
}
else
{
// read real device number
int device = BASS_GetDevice();
if (device == -1)
{
printf("voice: BASS_GetDevice: %d err:%d\n", pbdev, BASS_ErrorGetCode());
close_audio_voice();
ret = 1;
}
else
{
pbdev = device;
openpbdev_voice = pbdev;
printf("voice: real BASS PB Device No: %d\n", pbdev);
// set play callback
BASS_GetInfo(&info_voice);
stream_voice = BASS_StreamCreate(info_voice.freq, 2, BASS_SAMPLE_FLOAT, (STREAMPROC*)WriteStream_voice, 0); // sample: 32 bit float
BASS_ChannelSetAttribute(stream_voice, BASS_ATTRIB_BUFFER, 0); // no buffering for minimum latency
BASS_ChannelPlay(stream_voice, FALSE); // start it
setLSvolume(initialLSvol);
}
}
// ===== CAPTURE ====
// initalize default recording device
if (!BASS_RecordInit(capdev))
{
printf("voice: Can't initialize recording device: %d err:%d\n", capdev, BASS_ErrorGetCode());
close_audio_voice();
ret |= 2;
}
else
{
// read real device number
int device = BASS_RecordGetDevice();
if (device == -1)
{
printf("voice: BASS_GetDevice: %d err:%d\n", capdev, BASS_ErrorGetCode());
close_audio_voice();
ret |= 2;
}
else
{
capdev = device;
printf("voice: real BASS CAP Device No: %d\n", capdev);
// set capture callback
rchan_voice = BASS_RecordStart(caprate_voice, 2, BASS_SAMPLE_FLOAT, RecordingCallback_voice, 0);
if (!rchan_voice) {
printf("voice: Can't start capturing: %d\n", BASS_ErrorGetCode());
close_audio_voice();
ret |= 2;
}
else
{
opencapdev_voice = capdev;
setMICvolume(initialMICvol);
}
}
}
if (ret == 0)
printf("voice started successfully for PBdev:%d and CAPdev:%d\n", openpbdev_voice, opencapdev_voice);
else
{
opencapdev_voice = -1;
openpbdev_voice = -1;
readAudioDevices();
}
if (ret == 1)
printf("voice initialized: PBerror CapOK\n");
if (ret == 2)
printf("voice initialized: PBOK CapERROR\n");
if (ret == 3)
printf("voice initialized: PBerror CapERROR\n");
#endif
return ret;
}
#ifdef _LINUX_
void selectPBdevice_voice()
{
if (!BASS_SetDevice(openpbdev_voice))
printf("BASS_SetDevice: %d err:%d\n", openpbdev_voice, BASS_ErrorGetCode());
}
void selectCAPdevice_voice()
{
if (!BASS_SetDevice(opencapdev_voice))
printf("BASS_SetDevice: %d err:%d\n", opencapdev_voice, BASS_ErrorGetCode());
}
void close_audio_voice()
{
printf("voice: close Audio Devices\n");
if (stream_voice > 0)
BASS_StreamFree(stream_voice);
if (openpbdev_voice != -1)
{
selectPBdevice_voice();
int r = BASS_Free();
if (!r) printf("voice: Bass_Free error: %d\n", BASS_ErrorGetCode());
}
if (rchan_voice > 0)
BASS_ChannelStop(rchan_voice);
if (opencapdev_voice != -1)
{
selectCAPdevice_voice();
int rr = BASS_RecordFree();
if (!rr) printf("voice: Bass_RecordFree error: %d\n", BASS_ErrorGetCode());
}
openpbdev_voice = -1;
opencapdev_voice = -1;
rchan_voice = 0;
stream_voice = 0;
}
void setLSvolume(int v)
{
if (v < 0 || v>100) return;
// the volume comes in % 0..99
// map to 0..1
float vf = v;
vf /= 100;
//printf("set PB volume to:%d / %f [0..1]\n", v, vf );
selectPBdevice_voice();
if (!BASS_SetVolume(vf))
printf("setPBvolume: %d err:%d\n", openpbdev_voice, BASS_ErrorGetCode());
}
void setMICvolume(int v)
{
if (v < 0 || v>100) return;
// the volume comes in % 0..99
// map to min/maxPBvol
float vf = v;
vf /= 100;
//printf("set CAP volume to:%d / %f [0..1]\n", v, vf);
selectCAPdevice_voice();
if (!BASS_RecordSetInput(-1, BASS_INPUT_ON, vf))
{
printf("setCAPvolume: %d err:%d, using software level\n", opencapdev_voice, BASS_ErrorGetCode());
softwareCAPvolume_voice = ((float)v / 100);
}
}
// capture callback
BOOL CALLBACK RecordingCallback_voice(HRECORD handle, const void* buffer, DWORD length, void* user)
{
//printf("captured %ld samples, channels:%d\n",length/sizeof(float),2);
//measure_speed(length/sizeof(float));
float* fbuffer = (float*)buffer;
//showbytestringf((char*)"cap:", fbuffer, 10);
//printf("w:%ld ",length/sizeof(float));
for (unsigned int i = 0; i < (length / sizeof(float)); i += 2)
{
//printf("%f\n",fbuffer[i]);
cap_write_fifo_voice(fbuffer[i]);
}
return TRUE; // continue recording
}
// play callback
// length: bytes. float=4byte, 2channels, so it requests samples*8
DWORD CALLBACK WriteStream_voice(HSTREAM handle, float* buffer, DWORD length, void* user)
{
//printf("requested %ld samples\n", length / sizeof(float));
int ret = pb_read_fifo_voice(buffer, length / sizeof(float));
if (ret == 0)
{
// fifo empty, send 00
memset(buffer, 0, length);
}
return length;
}
#endif
// set volume
void setVolume_voice(int pbcap, int v)
{
if (pbcap == 0) setLSvolume(v);
else setMICvolume(v);
}
// ================= resampling and other tasks for voice audio =================
// samples come from the data-audio capture with a speed of caprate
// resample (if required) to VOICE_SAMPRATE, which is the voice-audio rate
void toVoice(float sample)
{
if (caprate == VOICE_SAMPRATE)
{
// resampling not required, just put in LS fifo
pb_write_fifo_voice(sample);
}
else
{
pb_write_fifo_voice(sample);
// samprate of incoming signal is 44100, voice needs 48000
// we have 44100 samples/s, so we ar missing 3900 S/s.
// if we insert an additional sample every 11 samples
// this results in a rate of 48109 S/s
static int cnt = 0;
if (++cnt >= 11)
{
cnt = 0;
pb_write_fifo_voice(sample);
}
}
}
// ================= VOICE FIFOs ===================
#ifdef _WIN32_
CRITICAL_SECTION cap_crit_sec_voice;
CRITICAL_SECTION pb_crit_sec_voice;
#define CAP_LOCK_VOICE EnterCriticalSection(&cap_crit_sec_voice)
#define PB_LOCK_VOICE EnterCriticalSection(&pb_crit_sec_voice)
void CAP_UNLOCK_VOICE()
{
if (&cap_crit_sec_voice != NULL)
LeaveCriticalSection(&cap_crit_sec_voice);
}
void PB_UNLOCK_VOICE()
{
if (&pb_crit_sec_voice != NULL)
LeaveCriticalSection(&pb_crit_sec_voice);
}
#endif
#ifdef _LINUX_
pthread_mutex_t cap_crit_sec_voice;
pthread_mutex_t pb_crit_sec_voice;
#define CAP_LOCK_VOICE pthread_mutex_lock(&cap_crit_sec_voice)
void CAP_UNLOCK_VOICE() { pthread_mutex_unlock(&cap_crit_sec_voice); }
#define PB_LOCK_VOICE pthread_mutex_lock(&pb_crit_sec_voice)
void PB_UNLOCK_VOICE() { pthread_mutex_unlock(&pb_crit_sec_voice); }
#endif
#define AUDIO_PLAYBACK_BUFLEN_VOICE (48000)
#define AUDIO_CAPTURE_BUFLEN_VOICE (48000)
int cap_wridx_voice = 0;
int cap_rdidx_voice = 0;
float cap_buffer_voice[AUDIO_CAPTURE_BUFLEN_VOICE];
int pb_wridx_voice = 0;
int pb_rdidx_voice = 0;
float pb_buffer_voice[AUDIO_PLAYBACK_BUFLEN_VOICE];
void init_pipes_voice()
{
#ifdef _WIN32_
if (&cap_crit_sec_voice != NULL) DeleteCriticalSection(&cap_crit_sec_voice);
InitializeCriticalSection(&cap_crit_sec_voice);
if (&pb_crit_sec_voice != NULL) DeleteCriticalSection(&pb_crit_sec_voice);
InitializeCriticalSection(&pb_crit_sec_voice);
#endif
}
// write one sample into the fifo
// overwrite old data if the fifo is full
void cap_write_fifo_voice(float sample)
{
if (((cap_wridx_voice + 1) % AUDIO_CAPTURE_BUFLEN_VOICE) == cap_rdidx_voice)
{
//printf("cap_voice fifo full\n");
CAP_UNLOCK_VOICE();
return;
}
CAP_LOCK_VOICE;
cap_buffer_voice[cap_wridx_voice] = sample;
if (++cap_wridx_voice >= AUDIO_CAPTURE_BUFLEN_VOICE) cap_wridx_voice = 0;
CAP_UNLOCK_VOICE();
}
int cap_read_fifo_voice(float* data)
{
CAP_LOCK_VOICE;
if (cap_rdidx_voice == cap_wridx_voice)
{
// Fifo empty, no data available
CAP_UNLOCK_VOICE();
return 0;
}
*data = cap_buffer_voice[cap_rdidx_voice];
if (++cap_rdidx_voice >= AUDIO_CAPTURE_BUFLEN_VOICE) cap_rdidx_voice = 0;
CAP_UNLOCK_VOICE();
return 1;
}
void cap_write_fifo_clear_voice()
{
cap_wridx_voice = cap_rdidx_voice = 0;
}
void pb_write_fifo_clear_voice()
{
pb_wridx_voice = pb_rdidx_voice = 0;
}
int pb_fifo_freespace_voice(int nolock)
{
int freebuf = 0;
if (nolock == 0) PB_LOCK_VOICE;
int elemInFifo = (pb_wridx_voice + AUDIO_PLAYBACK_BUFLEN_VOICE - pb_rdidx_voice) % AUDIO_PLAYBACK_BUFLEN_VOICE;
freebuf = AUDIO_PLAYBACK_BUFLEN_VOICE - elemInFifo;
if (nolock == 0) PB_UNLOCK_VOICE();
return freebuf;
}
void pb_write_fifo_voice(float sample)
{
PB_LOCK_VOICE;
// check if there is free space in fifo
if (pb_fifo_freespace_voice(1) == 0)
{
PB_UNLOCK_VOICE();
//printf("************* pb fifo_voice full\n");
return;
}
pb_buffer_voice[pb_wridx_voice] = sample;
if (++pb_wridx_voice >= AUDIO_PLAYBACK_BUFLEN_VOICE) pb_wridx_voice = 0;
PB_UNLOCK_VOICE();
}
int pb_fifo_usedspace_voice()
{
int anz = pb_fifo_freespace_voice(0);
return AUDIO_PLAYBACK_BUFLEN_VOICE - anz;
}
// read elements floats from fifo or return 0 if not enough floats are available
int pb_read_fifo_voice(float* data, int elements)
{
//printf("pb read fifo_voice: %d\n",elements);
PB_LOCK_VOICE;
int e = AUDIO_PLAYBACK_BUFLEN_VOICE - pb_fifo_freespace_voice(1);
if (e < elements)
{
// Fifo empty, no data available
PB_UNLOCK_VOICE();
//printf("pb fifo empty, need:%d have:%d size:%d\n",elements,e,AUDIO_PLAYBACK_BUFLEN);
return 0;
}
for (int i = 0; i < elements; i+=2)
{
// channel1 and the same for channel 2
data[i] = pb_buffer_voice[pb_rdidx_voice];
data[i+1] = pb_buffer_voice[pb_rdidx_voice];
if (++pb_rdidx_voice >= AUDIO_PLAYBACK_BUFLEN_VOICE) pb_rdidx_voice = 0;
}
//printf("read %d floats\n",elements);
PB_UNLOCK_VOICE();
return 1;
}
void clear_voice_fifos()
{
pb_write_fifo_clear_voice();
cap_write_fifo_clear_voice();
}

270
hsmodem/audio_voice_wasapi.cpp Executable file
View File

@ -0,0 +1,270 @@
/*
* 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.
*
* audio.c ... very similar to audio.c but is used for Microphone / Loudspeaker
*
*/
#include "hsmodem.h"
void cap_write_fifo(float sample);
int pb_read_fifo(float* data, int elements);
void close_wasapi_voice();
DWORD CALLBACK PBcallback_wasapi_voice(void* buffer, DWORD length, void* user);
DWORD CALLBACK CAPcallback_wasapi_voice(void* buffer, DWORD length, void* user);
void cap_write_fifo_voice(float sample);
int pb_read_fifo_voice(float* data, int elements);
#define WASAPI_CHANNELS_VOICE 2
float minPBvol_voice = 0;
float maxPBvol_voice = 99;
float minCAPvol_voice = 0;
float maxCAPvol_voice = 99;
extern int openpbdev_voice;
extern int opencapdev_voice;
extern float softwareCAPvolume_voice;
int mic_channel_num = 2;
#ifdef _WIN32_
int init_wasapi_voice(int pbdev, int capdev)
{
int ret = 0;
close_wasapi_voice();
if (VoiceAudioMode == VOICEMODE_OFF) return 0; // Voice off
// ======= init PLAYBACK device ========
// initialize default output device
if (!BASS_WASAPI_Init(pbdev, VOICE_SAMPRATE, WASAPI_CHANNELS_VOICE, BASS_WASAPI_EXCLUSIVE, 0.1f, 0, PBcallback_wasapi_voice, NULL))
{
printf("Can't initialize wasapi voice output device: %d err:%d\n", pbdev, BASS_ErrorGetCode());
ret = 1;
}
else
{
// read real device number since a -1 cannot be started
int device = BASS_WASAPI_GetDevice();
if (device == -1)
{
printf("BASS_WASAPI_GetDevice_voice: %d err:%d\n", pbdev, BASS_ErrorGetCode());
ret = 1;
}
else
{
pbdev = device;
// read the possible volume settings
BASS_WASAPI_INFO info;
if (!BASS_WASAPI_GetInfo(&info))
{
printf("BASS_WASAPI_GetInfo: %d err:%d\n", pbdev, BASS_ErrorGetCode());
ret = 1;
}
else
{
minPBvol_voice = info.volmin;
maxPBvol_voice = info.volmax;
// start playback
if (!BASS_WASAPI_Start())
{
printf("BASS_WASAPI_Start voice: %d err:%d\n", pbdev, BASS_ErrorGetCode());
ret = 1;
}
else
openpbdev_voice = pbdev;
}
}
}
// ======= init CAPTURE device ========
// initalize default recording device
if (capdev == -1) capdev = -2; // cap: -2 is the default device for input
BOOL micret = false;
mic_channel_num = 2;
micret = BASS_WASAPI_Init(capdev, VOICE_SAMPRATE, mic_channel_num, BASS_WASAPI_EXCLUSIVE, 0.1f, 0, CAPcallback_wasapi_voice, NULL);
if (!micret)
{
micret = BASS_WASAPI_Init(capdev, VOICE_SAMPRATE, 1, BASS_WASAPI_EXCLUSIVE, 0.1f, 0, CAPcallback_wasapi_voice, NULL);
if (!micret)
{
printf("Can't initialize wasapi voice recording device: %d err:%d\n", capdev, BASS_ErrorGetCode());
ret |= 2;
}
else
{
mic_channel_num = 1;
}
}
if(micret)
{
printf("mic opened with %d channels\n", mic_channel_num);
// read real device number since a -2 cannot be started
int device = BASS_WASAPI_GetDevice();
if (device == -1)
{
printf("BASS_WASAPI_GetDevice: voice: %d err:%d\n", capdev, BASS_ErrorGetCode());
ret |= 2;
}
else
{
capdev = device;
// read the possible volume settings
BASS_WASAPI_INFO info;
if (!BASS_WASAPI_GetInfo(&info))
{
printf("BASS_WASAPI_GetInfo: %d err:%d\n", pbdev, BASS_ErrorGetCode());
ret |= 2;
}
else
{
minCAPvol_voice = info.volmin;
maxCAPvol_voice = info.volmax;
// start recording
if (!BASS_WASAPI_Start())
{
printf("BASS_WASAPI_Start voice: %d err:%d\n", capdev, BASS_ErrorGetCode());
ret |= 2;
}
else
opencapdev_voice = capdev;
}
}
}
if (ret == 0)
printf("wasapi voice started successfully for PBdev:%d and CAPdev:%d\n", openpbdev_voice, opencapdev_voice);
else
{
opencapdev_voice = -1;
openpbdev_voice = -1;
readAudioDevices();
}
if (ret == 1)
printf("wasapi voice initialized: PBerror CapOK\n");
if (ret == 2)
printf("wasapi voice initialized: PBOK CapERROR\n");
if (ret == 3)
printf("wasapi voice initialized: PBerror CapERROR\n");
return ret;
}
int selectPBdevice_wasapi_voice()
{
if (!BASS_WASAPI_SetDevice(openpbdev_voice))
{
printf("BASS_WASAPI_SetDevice VOICE: %d err:%d\n", openpbdev_voice, BASS_ErrorGetCode());
return 0;
}
return 1;
}
int selectCAPdevice_wasapi_voice()
{
if (!BASS_WASAPI_SetDevice(opencapdev_voice))
{
printf("BASS_WASAPI_SetDevice VOICE: %d err:%d\n", opencapdev_voice, BASS_ErrorGetCode());
return 0;
}
return 1;
}
void close_wasapi_voice()
{
printf("close WASAPI Voice Devices\n");
if (openpbdev_voice != -1)
{
if(selectPBdevice_wasapi_voice())
if (!BASS_WASAPI_Free()) printf("BASS_WASAPI_Free voice: dev:%d err:%d\n", openpbdev_voice, BASS_ErrorGetCode());
}
if (opencapdev_voice != -1)
{
if(selectCAPdevice_wasapi_voice())
if (!BASS_WASAPI_Free()) printf("BASS_WASAPI_Free voice: dev:%d err:%d\n", opencapdev_voice, BASS_ErrorGetCode());
}
printf("closed WASAPI Voice Devices\n");
}
void setLSvolume(int v)
{
// the volume comes in % 0..99
// map to min/maxPBvol
float vf = v * (maxPBvol_voice - minPBvol_voice) / 100 + minPBvol_voice;
if (vf < minPBvol_voice) vf = minPBvol_voice;
if (vf > maxPBvol_voice) vf = maxPBvol_voice;
//printf("set PB volume to:%d / %f [%f..%f]\n", v, vf, minPBvol_voice, maxPBvol_voice);
if(selectPBdevice_wasapi_voice())
if (!BASS_WASAPI_SetVolume(BASS_WASAPI_CURVE_DB, vf))
printf("setPBvolume: %d err:%d\n", openpbdev_voice, BASS_ErrorGetCode());
}
void setMICvolume(int v)
{
// non of the BASS input level functions are working in WASAPI exclusive mode
// so we adjust the input level by software
softwareCAPvolume_voice = (float)v;
softwareCAPvolume_voice /= 50;
}
DWORD CALLBACK PBcallback_wasapi_voice(void* buffer, DWORD length, void* user)
{
float* fbuffer = (float*)buffer;
int ret = pb_read_fifo_voice(fbuffer, length / sizeof(float));
if (ret == 0)
{
// fifo empty, send 00
memset(buffer, 0, length);
}
return length;
}
DWORD CALLBACK CAPcallback_wasapi_voice(void* buffer, DWORD length, void* user)
{
float* fbuffer = (float*)buffer;
for (unsigned int i = 0; i < (length / sizeof(float)); i += mic_channel_num)
{
cap_write_fifo_voice(fbuffer[i]);
}
return TRUE; // continue recording
}
#endif

View File

@ -24,14 +24,12 @@
* wasapi is needed because we need exclusive access to the sound card which is not provided for Windows with the normal bass.lib
*/
#include "hsmodem.h"
#ifdef _WIN32_
#define WASAPI_CHANNELS 2 // wasapi works with 2 only
void init_pipes();
void cap_write_fifo(float sample);
int pb_read_fifo(float* data, int elements);
void close_wasapi();
@ -48,104 +46,143 @@ extern int opencapdev;
float softwareCAPvolume = 0.5;
int use_wasapi = -1;
int init_wasapi(int pbdev, int capdev)
{
close_wasapi();
int ret = 0;
use_wasapi = -1;
close_wasapi();
// ======= init PLAYBACK device ========
// initialize default output device
if (!BASS_WASAPI_Init(pbdev, caprate, WASAPI_CHANNELS, BASS_WASAPI_EXCLUSIVE, 0.1f/*buffer in seconds*/, 0, PBcallback_wasapi, NULL))
if (!BASS_WASAPI_Init(pbdev, caprate, WASAPI_CHANNELS, BASS_WASAPI_EXCLUSIVE, 0.1f, 0, PBcallback_wasapi, NULL))
{
printf("Can't initialize output device: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
ret = 1;
}
// read real device number since a -1 cannot be started
int ret = BASS_WASAPI_GetDevice();
if (ret == -1)
else
{
printf("BASS_WASAPI_GetDevice: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
}
pbdev = ret;
// read the possible volume settings
BASS_WASAPI_INFO info;
if (!BASS_WASAPI_GetInfo(&info))
{
printf("BASS_WASAPI_GetInfo: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
}
minPBvol = info.volmin;
maxPBvol = info.volmax;
// read real device number since a -1 cannot be started
int device = BASS_WASAPI_GetDevice();
if (device == -1)
{
printf("BASS_WASAPI_GetDevice: %d err:%d\n", pbdev, BASS_ErrorGetCode());
ret = 1;
}
else
{
pbdev = device;
// start playback
if (!BASS_WASAPI_Start())
{
printf("BASS_WASAPI_Start: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
// read the possible volume settings
BASS_WASAPI_INFO info;
if (!BASS_WASAPI_GetInfo(&info))
{
printf("BASS_WASAPI_GetInfo: %d err:%d\n", pbdev, BASS_ErrorGetCode());
ret = 1;
}
else
{
minPBvol = info.volmin;
maxPBvol = info.volmax;
// start playback
if (!BASS_WASAPI_Start())
{
printf("BASS_WASAPI_Start: %d err:%d\n", pbdev, BASS_ErrorGetCode());
ret = 1;
}
else
openpbdev = pbdev;
}
}
}
// ======= init CAPTURE device ========
// initalize default recording device
if (capdev == -1) capdev = -2; // cap: -2 is the default device for input
if (!BASS_WASAPI_Init(capdev, caprate, WASAPI_CHANNELS, BASS_WASAPI_EXCLUSIVE, 0.1f/*buffer in seconds*/, 0, CAPcallback_wasapi, NULL))
if (!BASS_WASAPI_Init(capdev, caprate, WASAPI_CHANNELS, BASS_WASAPI_EXCLUSIVE, 0.1f, 0, CAPcallback_wasapi, NULL))
{
printf("Can't initialize recording device: %d err:%d\n", capdev, BASS_ErrorGetCode());
return -1;
ret |= 2;
}
// read real device number since a -2 cannot be started
ret = BASS_WASAPI_GetDevice();
if (ret == -1)
else
{
printf("BASS_WASAPI_GetDevice: %d err:%d\n", capdev, BASS_ErrorGetCode());
return -1;
}
capdev = ret;
// read the possible volume settings
if (!BASS_WASAPI_GetInfo(&info))
// read real device number since a -2 cannot be started
int device = BASS_WASAPI_GetDevice();
if (device == -1)
{
printf("BASS_WASAPI_GetDevice: %d err:%d\n", capdev, BASS_ErrorGetCode());
ret |= 2;
}
else
{
capdev = device;
// read the possible volume settings
BASS_WASAPI_INFO info;
if (!BASS_WASAPI_GetInfo(&info))
{
printf("BASS_WASAPI_GetInfo: %d err:%d\n", pbdev, BASS_ErrorGetCode());
ret |= 2;
}
else
{
minCAPvol = info.volmin;
maxCAPvol = info.volmax;
// start recording
if (!BASS_WASAPI_Start())
{
printf("BASS_WASAPI_Start: %d err:%d\n", capdev, BASS_ErrorGetCode());
ret |= 2;
}
else
opencapdev = capdev;
}
}
}
if (ret == 0)
printf("WASAPI started successfully for PBdev:%d and CAPdev:%d\n", openpbdev, opencapdev);
else
{
printf("BASS_WASAPI_GetInfo: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
opencapdev = -1;
openpbdev = -1;
readAudioDevices();
}
minCAPvol = info.volmin;
maxCAPvol = info.volmax;
if (ret == 1)
printf("wasapi audio initialized: PBerror CapOK\n");
if (ret == 2)
printf("wasapi audio initialized: PBOK CapERROR\n");
if (ret == 3)
printf("wasapi audio initialized: PBerror CapERROR\n");
// start recording
if (!BASS_WASAPI_Start())
{
printf("BASS_WASAPI_Start: %d err:%d\n", capdev, BASS_ErrorGetCode());
return -1;
}
printf("WASAPI started successfully for PBdev:%d and CAPdev:%d\n", pbdev, capdev);
openpbdev = pbdev;
opencapdev = capdev;
use_wasapi = 0;
return 0;
return ret;
}
void selectPBdevice_wasapi()
int selectPBdevice_wasapi()
{
if (!BASS_WASAPI_SetDevice(openpbdev))
{
printf("BASS_WASAPI_SetDevice: %d err:%d\n", openpbdev, BASS_ErrorGetCode());
return 0;
}
return 1;
}
void selectCAPdevice_wasapi()
int selectCAPdevice_wasapi()
{
if (!BASS_WASAPI_SetDevice(opencapdev))
{
printf("BASS_WASAPI_SetDevice: %d err:%d\n", opencapdev, BASS_ErrorGetCode());
return 0;
}
return 1;
}
void setPBvolume(int v)
@ -159,9 +196,9 @@ void setPBvolume(int v)
//printf("set PB volume to:%d / %f [%f..%f]\n", v, vf, minPBvol, maxPBvol);
selectPBdevice_wasapi();
if (!BASS_WASAPI_SetVolume(BASS_WASAPI_CURVE_DB, vf))
printf("setPBvolume: %d err:%d\n", openpbdev, BASS_ErrorGetCode());
if(selectPBdevice_wasapi())
if (!BASS_WASAPI_SetVolume(BASS_WASAPI_CURVE_DB, vf))
printf("setPBvolume: %d err:%d\n", openpbdev, BASS_ErrorGetCode());
}
void setCAPvolume(int v)
@ -178,14 +215,14 @@ void close_wasapi()
if (openpbdev != -1)
{
selectPBdevice_wasapi();
if (!BASS_WASAPI_Free()) printf("BASS_WASAPI_Free: dev:%d err:%d\n", openpbdev, BASS_ErrorGetCode());
if(selectPBdevice_wasapi())
if (!BASS_WASAPI_Free()) printf("BASS_WASAPI_Free: dev:%d err:%d\n", openpbdev, BASS_ErrorGetCode());
}
if (opencapdev != -1)
{
selectCAPdevice_wasapi();
if (!BASS_WASAPI_Free()) printf("BASS_WASAPI_Free: dev:%d err:%d\n", opencapdev, BASS_ErrorGetCode());
if(selectCAPdevice_wasapi())
if (!BASS_WASAPI_Free()) printf("BASS_WASAPI_Free: dev:%d err:%d\n", opencapdev, BASS_ErrorGetCode());
}
}
@ -216,44 +253,7 @@ DWORD CALLBACK PBcallback_wasapi(void* buffer, DWORD length, void* user)
free(fdata);
return length;
}
/*
#define MCHECK 10
void nullChecker(float fv, float *pbuf, DWORD len)
{
static float farr[MCHECK];
static int idx = 0;
static int f = 1;
static int anz = 0;
if (f)
{
f = 0;
for (int i = 0; i < MCHECK; i++)
farr[i] = 1;
}
farr[idx] = fv;
idx++;
if (idx == MCHECK) idx = 0;
float nu = 0;
for (int i = 0; i < MCHECK; i++)
{
nu += farr[i];
}
if (nu == 0)
{
// how many 00s ar in the current buffer
int a = 0;
for (unsigned int i = 0; i < len-1; i++)
{
if (pbuf[i] == 0 && pbuf[i+1] == 0) a++;
}
printf("=============== null sequence detected: %d len:%d nullanz:%d\n",anz++,len,a);
}
}
*/
DWORD CALLBACK CAPcallback_wasapi(void* buffer, DWORD length, void* user)
{
//printf("CAP callback, len:%d\n",length);

207
hsmodem/bassenc.h Normal file
View File

@ -0,0 +1,207 @@
/*
BASSenc 2.4 C/C++ header file
Copyright (c) 2003-2018 Un4seen Developments Ltd.
See the BASSENC.CHM file for more detailed documentation
*/
#ifndef BASSENC_H
#define BASSENC_H
#include "bass.h"
#if BASSVERSION!=0x204
#error conflicting BASS and BASSenc versions
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef BASSENCDEF
#define BASSENCDEF(f) WINAPI f
#endif
typedef DWORD HENCODE; // encoder handle
// Additional error codes returned by BASS_ErrorGetCode
#define BASS_ERROR_ACM_CANCEL 2000 // ACM codec selection cancelled
#define BASS_ERROR_CAST_DENIED 2100 // access denied (invalid password)
// Additional BASS_SetConfig options
#define BASS_CONFIG_ENCODE_PRIORITY 0x10300
#define BASS_CONFIG_ENCODE_QUEUE 0x10301
#define BASS_CONFIG_ENCODE_CAST_TIMEOUT 0x10310
// Additional BASS_SetConfigPtr options
#define BASS_CONFIG_ENCODE_ACM_LOAD 0x10302
#define BASS_CONFIG_ENCODE_CAST_PROXY 0x10311
// BASS_Encode_Start flags
#define BASS_ENCODE_NOHEAD 1 // don't send a WAV header to the encoder
#define BASS_ENCODE_FP_8BIT 2 // convert floating-point sample data to 8-bit integer
#define BASS_ENCODE_FP_16BIT 4 // convert floating-point sample data to 16-bit integer
#define BASS_ENCODE_FP_24BIT 6 // convert floating-point sample data to 24-bit integer
#define BASS_ENCODE_FP_32BIT 8 // convert floating-point sample data to 32-bit integer
#define BASS_ENCODE_FP_AUTO 14 // convert floating-point sample data back to channel's format
#define BASS_ENCODE_BIGEND 16 // big-endian sample data
#define BASS_ENCODE_PAUSE 32 // start encording paused
#define BASS_ENCODE_PCM 64 // write PCM sample data (no encoder)
#define BASS_ENCODE_RF64 128 // send an RF64 header
#define BASS_ENCODE_MONO 0x100 // convert to mono (if not already)
#define BASS_ENCODE_QUEUE 0x200 // queue data to feed encoder asynchronously
#define BASS_ENCODE_WFEXT 0x400 // WAVEFORMATEXTENSIBLE "fmt" chunk
#define BASS_ENCODE_CAST_NOLIMIT 0x1000 // don't limit casting data rate
#define BASS_ENCODE_LIMIT 0x2000 // limit data rate to real-time
#define BASS_ENCODE_AIFF 0x4000 // send an AIFF header rather than WAV
#define BASS_ENCODE_DITHER 0x8000 // apply dither when converting floating-point sample data to integer
#define BASS_ENCODE_AUTOFREE 0x40000 // free the encoder when the channel is freed
// BASS_Encode_GetACMFormat flags
#define BASS_ACM_DEFAULT 1 // use the format as default selection
#define BASS_ACM_RATE 2 // only list formats with same sample rate as the source channel
#define BASS_ACM_CHANS 4 // only list formats with same number of channels (eg. mono/stereo)
#define BASS_ACM_SUGGEST 8 // suggest a format (HIWORD=format tag)
// BASS_Encode_GetCount counts
#define BASS_ENCODE_COUNT_IN 0 // sent to encoder
#define BASS_ENCODE_COUNT_OUT 1 // received from encoder
#define BASS_ENCODE_COUNT_CAST 2 // sent to cast server
#define BASS_ENCODE_COUNT_QUEUE 3 // queued
#define BASS_ENCODE_COUNT_QUEUE_LIMIT 4 // queue limit
#define BASS_ENCODE_COUNT_QUEUE_FAIL 5 // failed to queue
// BASS_Encode_CastInit content MIME types
#define BASS_ENCODE_TYPE_MP3 "audio/mpeg"
#define BASS_ENCODE_TYPE_OGG "audio/ogg"
#define BASS_ENCODE_TYPE_AAC "audio/aacp"
// BASS_Encode_CastGetStats types
#define BASS_ENCODE_STATS_SHOUT 0 // Shoutcast stats
#define BASS_ENCODE_STATS_ICE 1 // Icecast mount-point stats
#define BASS_ENCODE_STATS_ICESERV 2 // Icecast server stats
typedef void (CALLBACK ENCODEPROC)(HENCODE handle, DWORD channel, const void *buffer, DWORD length, void *user);
/* Encoding callback function.
handle : The encoder
channel: The channel handle
buffer : Buffer containing the encoded data
length : Number of bytes
user : The 'user' parameter value given when starting the encoder */
typedef void (CALLBACK ENCODEPROCEX)(HENCODE handle, DWORD channel, const void *buffer, DWORD length, QWORD offset, void *user);
/* Encoding callback function with offset info.
handle : The encoder
channel: The channel handle
buffer : Buffer containing the encoded data
length : Number of bytes
offset : File offset of the data
user : The 'user' parameter value given when starting the encoder */
typedef DWORD (CALLBACK ENCODERPROC)(HENCODE handle, DWORD channel, void *buffer, DWORD length, DWORD maxout, void *user);
/* Encoder callback function.
handle : The encoder
channel: The channel handle
buffer : Buffer containing the PCM data (input) and receiving the encoded data (output)
length : Number of bytes in (-1=closing)
maxout : Maximum number of bytes out
user : The 'user' parameter value given when calling BASS_Encode_StartUser
RETURN : The amount of encoded data (-1=stop) */
typedef BOOL (CALLBACK ENCODECLIENTPROC)(HENCODE handle, BOOL connect, const char *client, char *headers, void *user);
/* Client connection notification callback function.
handle : The encoder
connect: TRUE/FALSE=client is connecting/disconnecting
client : The client's address (xxx.xxx.xxx.xxx:port)
headers: Request headers (optionally response headers on return)
user : The 'user' parameter value given when calling BASS_Encode_ServerInit
RETURN : TRUE/FALSE=accept/reject connection (ignored if connect=FALSE) */
typedef void (CALLBACK ENCODENOTIFYPROC)(HENCODE handle, DWORD status, void *user);
/* Encoder death notification callback function.
handle : The encoder
status : Notification (BASS_ENCODE_NOTIFY_xxx)
user : The 'user' parameter value given when calling BASS_Encode_SetNotify */
// Encoder notifications
#define BASS_ENCODE_NOTIFY_ENCODER 1 // encoder died
#define BASS_ENCODE_NOTIFY_CAST 2 // cast server connection died
#define BASS_ENCODE_NOTIFY_CAST_TIMEOUT 0x10000 // cast timeout
#define BASS_ENCODE_NOTIFY_QUEUE_FULL 0x10001 // queue is out of space
#define BASS_ENCODE_NOTIFY_FREE 0x10002 // encoder has been freed
// BASS_Encode_ServerInit flags
#define BASS_ENCODE_SERVER_NOHTTP 1 // no HTTP headers
#define BASS_ENCODE_SERVER_META 2 // Shoutcast metadata
DWORD BASSENCDEF(BASS_Encode_GetVersion)();
HENCODE BASSENCDEF(BASS_Encode_Start)(DWORD handle, const char *cmdline, DWORD flags, ENCODEPROC *proc, void *user);
HENCODE BASSENCDEF(BASS_Encode_StartLimit)(DWORD handle, const char *cmdline, DWORD flags, ENCODEPROC *proc, void *user, DWORD limit);
HENCODE BASSENCDEF(BASS_Encode_StartUser)(DWORD handle, const char *filename, DWORD flags, ENCODERPROC *proc, void *user);
BOOL BASSENCDEF(BASS_Encode_AddChunk)(HENCODE handle, const char *id, const void *buffer, DWORD length);
DWORD BASSENCDEF(BASS_Encode_IsActive)(DWORD handle);
BOOL BASSENCDEF(BASS_Encode_Stop)(DWORD handle);
BOOL BASSENCDEF(BASS_Encode_StopEx)(DWORD handle, BOOL queue);
BOOL BASSENCDEF(BASS_Encode_SetPaused)(DWORD handle, BOOL paused);
BOOL BASSENCDEF(BASS_Encode_Write)(DWORD handle, const void *buffer, DWORD length);
BOOL BASSENCDEF(BASS_Encode_SetNotify)(DWORD handle, ENCODENOTIFYPROC *proc, void *user);
QWORD BASSENCDEF(BASS_Encode_GetCount)(DWORD handle, DWORD count);
BOOL BASSENCDEF(BASS_Encode_SetChannel)(DWORD handle, DWORD channel);
DWORD BASSENCDEF(BASS_Encode_GetChannel)(HENCODE handle);
BOOL BASSENCDEF(BASS_Encode_UserOutput)(DWORD handle, QWORD offset, const void *buffer, DWORD length);
#ifdef _WIN32
DWORD BASSENCDEF(BASS_Encode_GetACMFormat)(DWORD handle, void *form, DWORD formlen, const char *title, DWORD flags);
HENCODE BASSENCDEF(BASS_Encode_StartACM)(DWORD handle, const void *form, DWORD flags, ENCODEPROC *proc, void *user);
HENCODE BASSENCDEF(BASS_Encode_StartACMFile)(DWORD handle, const void *form, DWORD flags, const char *filename);
#endif
#ifdef __APPLE__
HENCODE BASSENCDEF(BASS_Encode_StartCA)(DWORD handle, DWORD ftype, DWORD atype, DWORD flags, DWORD bitrate, ENCODEPROCEX *proc, void *user);
HENCODE BASSENCDEF(BASS_Encode_StartCAFile)(DWORD handle, DWORD ftype, DWORD atype, DWORD flags, DWORD bitrate, const char *filename);
void *BASSENCDEF(BASS_Encode_GetCARef)(DWORD handle);
#endif
#ifndef _WIN32_WCE
BOOL BASSENCDEF(BASS_Encode_CastInit)(HENCODE handle, const char *server, const char *pass, const char *content, const char *name, const char *url, const char *genre, const char *desc, const char *headers, DWORD bitrate, BOOL pub);
BOOL BASSENCDEF(BASS_Encode_CastSetTitle)(HENCODE handle, const char *title, const char *url);
BOOL BASSENCDEF(BASS_Encode_CastSendMeta)(HENCODE handle, DWORD type, const void *data, DWORD length);
const char *BASSENCDEF(BASS_Encode_CastGetStats)(HENCODE handle, DWORD type, const char *pass);
DWORD BASSENCDEF(BASS_Encode_ServerInit)(HENCODE handle, const char *port, DWORD buffer, DWORD burst, DWORD flags, ENCODECLIENTPROC *proc, void *user);
BOOL BASSENCDEF(BASS_Encode_ServerKick)(HENCODE handle, const char *client);
#endif
#ifdef __cplusplus
}
#ifdef _WIN32
static inline HENCODE BASS_Encode_Start(DWORD handle, const WCHAR *cmdline, DWORD flags, ENCODEPROC *proc, void *user)
{
return BASS_Encode_Start(handle, (const char*)cmdline, flags|BASS_UNICODE, proc, user);
}
static inline HENCODE BASS_Encode_StartLimit(DWORD handle, const WCHAR *cmdline, DWORD flags, ENCODEPROC *proc, void *user, DWORD limit)
{
return BASS_Encode_StartLimit(handle, (const char *)cmdline, flags|BASS_UNICODE, proc, user, limit);
}
static inline HENCODE BASS_Encode_StartUser(DWORD handle, const WCHAR *filename, DWORD flags, ENCODERPROC *proc, void *user)
{
return BASS_Encode_StartUser(handle, (const char *)filename, flags|BASS_UNICODE, proc, user);
}
static inline DWORD BASS_Encode_GetACMFormat(DWORD handle, void *form, DWORD formlen, const WCHAR *title, DWORD flags)
{
return BASS_Encode_GetACMFormat(handle, form, formlen, (const char *)title, flags|BASS_UNICODE);
}
static inline HENCODE BASS_Encode_StartACMFile(DWORD handle, const void *form, DWORD flags, const WCHAR *filename)
{
return BASS_Encode_StartACMFile(handle, form, flags|BASS_UNICODE, (const char *)filename);
}
#endif
#endif
#endif

46
hsmodem/bassenc_opus.h Normal file
View File

@ -0,0 +1,46 @@
/*
BASSenc_OPUS 2.4 C/C++ header file
Copyright (c) 2016 Un4seen Developments Ltd.
See the BASSENC_OPUS.CHM file for more detailed documentation
*/
#ifndef BASSENC_OPUS_H
#define BASSENC_OPUS_H
#include "bassenc.h"
#if BASSVERSION!=0x204
#error conflicting BASS and BASSenc_OPUS versions
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef BASSENCOPUSDEF
#define BASSENCOPUSDEF(f) WINAPI f
#endif
DWORD BASSENCOPUSDEF(BASS_Encode_OPUS_GetVersion)();
HENCODE BASSENCOPUSDEF(BASS_Encode_OPUS_Start)(DWORD handle, const char *options, DWORD flags, ENCODEPROC *proc, void *user);
HENCODE BASSENCOPUSDEF(BASS_Encode_OPUS_StartFile)(DWORD handle, const char *options, DWORD flags, const char *filename);
#ifdef __cplusplus
}
#ifdef _WIN32
static inline HENCODE BASS_Encode_OPUS_Start(DWORD handle, const WCHAR *options, DWORD flags, ENCODEPROC *proc, void *user)
{
return BASS_Encode_OPUS_Start(handle, (const char*)options, flags|BASS_UNICODE, proc, user);
}
static inline HENCODE BASS_Encode_OPUS_StartFile(DWORD handle, const WCHAR *options, DWORD flags, const WCHAR *filename)
{
return BASS_Encode_OPUS_StartFile(handle, (const char*)options, flags|BASS_UNICODE, (const char*)filename);
}
#endif
#endif
#endif

166
hsmodem/codec2.cpp Executable file
View File

@ -0,0 +1,166 @@
/*
* 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++)
pb_write_fifo_voice(f);
}
}
}
}
}
#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++)
pb_write_fifo_voice(f);
}
}
}
}

122
hsmodem/codec2.h Executable file
View File

@ -0,0 +1,122 @@
/*---------------------------------------------------------------------------*\
FILE........: codec2.h
AUTHOR......: David Rowe
DATE CREATED: 21 August 2010
Codec 2 fully quantised encoder and decoder functions. If you want use
Codec 2, these are the functions you need to call.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2010 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. 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 Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CODEC2__
#define __CODEC2__
#include "version.h"
#ifdef __cplusplus
extern "C" {
#endif
#define CODEC2_MODE_3200 0
#define CODEC2_MODE_2400 1
#define CODEC2_MODE_1600 2
#define CODEC2_MODE_1400 3
#define CODEC2_MODE_1300 4
#define CODEC2_MODE_1200 5
#define CODEC2_MODE_700C 8
#define CODEC2_MODE_450 10
#define CODEC2_MODE_450PWB 11
#ifndef CODEC2_MODE_EN_DEFAULT
#define CODEC2_MODE_EN_DEFAULT 1
#endif
// by default we enable all modes
// disable during compile time with -DCODEC2_MODE_1600_EN=0
// all but CODEC2 1600 are enabled then
//or the other way round
// -DCODEC2_MODE_EN_DEFAULT=0 -DCODEC2_MODE_1600_EN=1
// only CODEC2 Mode 1600
#if !defined(CODEC2_MODE_3200_EN)
#define CODEC2_MODE_3200_EN CODEC2_MODE_EN_DEFAULT
#endif
#if !defined(CODEC2_MODE_2400_EN)
#define CODEC2_MODE_2400_EN CODEC2_MODE_EN_DEFAULT
#endif
#if !defined(CODEC2_MODE_1600_EN)
#define CODEC2_MODE_1600_EN CODEC2_MODE_EN_DEFAULT
#endif
#if !defined(CODEC2_MODE_1400_EN)
#define CODEC2_MODE_1400_EN CODEC2_MODE_EN_DEFAULT
#endif
#if !defined(CODEC2_MODE_1300_EN)
#define CODEC2_MODE_1300_EN CODEC2_MODE_EN_DEFAULT
#endif
#if !defined(CODEC2_MODE_1200_EN)
#define CODEC2_MODE_1200_EN CODEC2_MODE_EN_DEFAULT
#endif
#if !defined(CODEC2_MODE_700C_EN)
#define CODEC2_MODE_700C_EN CODEC2_MODE_EN_DEFAULT
#endif
#if !defined(CODEC2_MODE_450_EN)
#define CODEC2_MODE_450_EN CODEC2_MODE_EN_DEFAULT
#endif
#if !defined(CODEC2_MODE_450PWB_EN)
#define CODEC2_MODE_450PWB_EN CODEC2_MODE_EN_DEFAULT
#endif
#define CODEC2_MODE_ACTIVE(mode_name, var) ((mode_name##_EN) == 0 ? 0: (var) == mode_name)
struct CODEC2;
struct CODEC2 * codec2_create(int mode);
void codec2_destroy(struct CODEC2 *codec2_state);
void codec2_encode(struct CODEC2 *codec2_state, unsigned char * bits, short speech_in[]);
void codec2_decode(struct CODEC2 *codec2_state, short speech_out[], const unsigned char *bits);
void codec2_decode_ber(struct CODEC2 *codec2_state, short speech_out[], const unsigned char *bits, float ber_est);
int codec2_samples_per_frame(struct CODEC2 *codec2_state);
int codec2_bits_per_frame(struct CODEC2 *codec2_state);
void codec2_set_lpc_post_filter(struct CODEC2 *codec2_state, int enable, int bass_boost, float beta, float gamma);
int codec2_get_spare_bit_index(struct CODEC2 *codec2_state);
int codec2_rebuild_spare_bit(struct CODEC2 *codec2_state, char unpacked_bits[]);
void codec2_set_natural_or_gray(struct CODEC2 *codec2_state, int gray);
void codec2_set_softdec(struct CODEC2 *c2, float *softdec);
float codec2_get_energy(struct CODEC2 *codec2_state, const unsigned char *bits);
// support for ML and VQ experiments
void codec2_open_mlfeat(struct CODEC2 *codec2_state, char *feat_filename, char *model_filename);
void codec2_load_codebook(struct CODEC2 *codec2_state, int num, char *filename);
float codec2_get_var(struct CODEC2 *codec2_state);
float *codec2_enable_user_ratek(struct CODEC2 *codec2_state, int *K);
// 700C post filter and equaliser
void codec2_700c_post_filter(struct CODEC2 *codec2_state, int en);
void codec2_700c_eq(struct CODEC2 *codec2_state, int en);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -104,18 +104,19 @@ uint16_t *make_waterfall(float fre, int *retlen)
void init_fft()
{
/*
char fn[300];
* storing to a file in the working directory may be a problem under Windows, so we do not use wisdom files
sprintf(fn, "capture_fft_%d", fft_rate); // wisdom file for each capture rate
sprintf(fn, "capture_fft_%d", fft_rate); // wisdom file for each capture rate
fftw_import_wisdom_from_filename(fn);
fftw_import_wisdom_from_filename(fn);*/
din = (double *)fftw_malloc(sizeof(double) * fft_rate);
cpout = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * fft_rate);
plan = fftw_plan_dft_r2c_1d(fft_rate, din, cpout, FFTW_MEASURE);
fftw_export_wisdom_to_filename(fn);
//fftw_export_wisdom_to_filename(fn);
}
void exit_fft()

View File

@ -254,14 +254,12 @@ uint8_t *unpack_data(uint8_t *rxd, int len)
{
memcpy(payload,pl, PAYLOADLEN+10);
framerdy = 1;
if(symnum != 688)
printf("Header found, rotation: %d at symbol no.: %d result: OK\n", rotations, symnum);
//if(symnum != 688) printf("Header found, rotation: %d at symbol no.: %d result: OK\n", rotations, symnum);
symnum = 0;
}
else
{
if((symnum % ((UDPBLOCKLEN * 8) / bitsPerSymbol)) == 0)
printf("Header found, rotation: %d at symbol no.: %d result: %d\n", rotations, symnum, getPayload_error);
//if((symnum % ((UDPBLOCKLEN * 8) / bitsPerSymbol)) == 0) printf("Header found, rotation: %d at symbol no.: %d result: %d\n", rotations, symnum, getPayload_error);
}
}
}

View File

@ -73,7 +73,7 @@ int keeprunning = 1;
// UDP I/O
int BC_sock_AppToModem = -1;
int DATA_sock_AppToModem = -1;
int DATA_sock_from_GR = -1;
//int DATA_sock_from_GR = -1;
int DATA_sock_FFT_from_GR = -1;
int DATA_sock_I_Q_from_GR = -1;
@ -81,17 +81,11 @@ int UdpBCport_AppToModem = 40131;
int UdpDataPort_AppToModem = 40132;
int UdpDataPort_ModemToApp = 40133;
int UdpDataPort_toGR = 40134;
int UdpDataPort_fromGR = 40135;
int UdpDataPort_fromGR_FFT = 40136;
int UdpDataPort_fromGR_I_Q = 40137;
// op mode depending values
// default mode if not set by the app
int speedmode = 2;
int bitsPerSymbol = 2; // QPSK=2, 8PSK=3
int constellationSize = 4; // QPSK=4, 8PSK=8
int psk8mode=0; // 0=APSK8, 1=PSK8
char localIP[] = { "127.0.0.1" };
char ownfilename[] = { "hsmodem" };
@ -106,9 +100,16 @@ int linespeed = 4410;
int captureDeviceNo = -1;
int playbackDeviceNo = -1;
int MicDeviceNo = -1;
int LSDeviceNo = -1;
int initialPBvol = -1;
int initialCAPvol = -1;
int announcement = 0;
int VoiceAudioMode = VOICEMODE_OFF;
int codec = 1; // 0=opus, 1=codec2
int init_audio_result = 0;
int init_voice_result = 0;
int main(int argc, char* argv[])
{
@ -169,17 +170,19 @@ int main(int argc, char* argv[])
}
}
#endif
init_packer();
initFEC();
init_fft();
int ar = init_audio(playbackDeviceNo, captureDeviceNo);
init_voiceproc();
/*int ar = init_audio(playbackDeviceNo, captureDeviceNo);
if (ar == -1)
{
keeprunning = 0;
exit(0);
}
}*/
// start udp RX to listen for broadcast search message from Application
UdpRxInit(&BC_sock_AppToModem, UdpBCport_AppToModem, &bc_rxdata, &keeprunning);
@ -188,7 +191,7 @@ int main(int argc, char* argv[])
UdpRxInit(&DATA_sock_AppToModem, UdpDataPort_AppToModem, &appdata_rxdata, &keeprunning);
// start udp RX to listen for data from GR Receiver
UdpRxInit(&DATA_sock_from_GR, UdpDataPort_fromGR, &GRdata_rxdata, &keeprunning);
//UdpRxInit(&DATA_sock_from_GR, UdpDataPort_fromGR, &GRdata_rxdata, &keeprunning);
printf("QO100modem initialised and running\n");
@ -201,9 +204,46 @@ int main(int argc, char* argv[])
}
//doArraySend();
if (VoiceAudioMode == VOICEMODE_INTERNALLOOP)
{
// loop voice mic to LS
float f;
if (cap_read_fifo_voice(&f))
{
if(softwareCAPvolume_voice >= 0)
f *= softwareCAPvolume_voice;
pb_write_fifo_voice(f);
}
}
if (demodulator() == 0)
sleep_ms(10);
if (VoiceAudioMode == VOICEMODE_CODECLOOP || VoiceAudioMode == VOICEMODE_DV_FULLDUPLEX)
{
// send mic to codec
float f;
if (cap_read_fifo_voice(&f))
{
if (softwareCAPvolume_voice >= 0)
f *= softwareCAPvolume_voice;
encode(f);
}
}
// demodulate incoming audio data stream
static int old_tm = 0;
int tm = getus();
if (tm >= (old_tm + 1000000))
{
// read Audio device list every 1s
readAudioDevices();
old_tm = tm;
}
int dret = demodulator();
#ifdef _LINUX_
if(dret == 0)
usleep(1);
#endif
}
printf("stopped: %d\n", keeprunning);
@ -225,32 +265,26 @@ typedef struct {
int rx;
int bpsym;
int linespeed;
int codecrate;
} SPEEDRATE;
// AudioRate, TX-Resampler, RX-Resampler/4, bit/symbol, Codec-Rate
SPEEDRATE sr[8] = {
// QPSK modes
{48000, 32, 8, 2, 3000}, // AudioRate, TX-Resampler, RX-Resampler/4, bit/symbol, see samprate.ods
{48000, 24, 6, 2, 4000},
{44100, 20, 5, 2, 4410},
{48000, 20, 5, 2, 4800},
{48000, 32, 8, 2, 3000, 2400},
{48000, 24, 6, 2, 4000, 3200},
{44100, 20, 5, 2, 4410, 3600},
{48000, 20, 5, 2, 4800, 4000},
// 8PSK modes
{44100, 24, 6, 3, 5500},
{48000, 24, 6, 3, 6000},
{44100, 20, 5, 3, 6600},
{48000, 20, 5, 3, 7200}
{44100, 24, 6, 3, 5500, 4400},
{48000, 24, 6, 3, 6000, 4800},
{44100, 20, 5, 3, 6600, 5200},
{48000, 20, 5, 3, 7200, 6000}
};
void startModem()
{
if (speedmode >= 8)
{
speedmode = speedmode - 4;
psk8mode = 1;
}
else
psk8mode = 0;
bitsPerSymbol = sr[speedmode].bpsym;
constellationSize = (1 << bitsPerSymbol); // QPSK=4, 8PSK=8
@ -258,16 +292,17 @@ void startModem()
txinterpolfactor = sr[speedmode].tx;
rxPreInterpolfactor = sr[speedmode].rx;
linespeed = sr[speedmode].linespeed;
opusbitrate = sr[speedmode].codecrate;
// int TX audio and modulator
close_dsp();
init_audio(playbackDeviceNo, captureDeviceNo);
init_audio_result = init_audio(playbackDeviceNo, captureDeviceNo);
setPBvolume(initialPBvol);
setCAPvolume(initialCAPvol);
init_dsp();
}
void setAudioDevices(int pb, int cap, int pbvol, int capvol, int announce)
void setAudioDevices(int pb, int cap, int pbvol, int capvol, int announce, int pbls, int pbmic)
{
//printf("%d %d\n", pb, cap);
@ -278,6 +313,8 @@ void setAudioDevices(int pb, int cap, int pbvol, int capvol, int announce)
captureDeviceNo = cap;
initialPBvol = pbvol;
initialCAPvol = capvol;
initialLSvol = pbls;
initialMICvol = pbmic;
}
announcement = announce;
@ -288,7 +325,7 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
{
if (len > 0 && pdata[0] == 0x3c)
{
setAudioDevices(pdata[1], pdata[2], pdata[3], pdata[4], pdata[5]);
setAudioDevices(pdata[1], pdata[2], pdata[3], pdata[4], pdata[5], pdata[6], pdata[7]);
char rxip[20];
strcpy(rxip, inet_ntoa(rxsock->sin_addr));
@ -335,6 +372,11 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
if (type == 16)
{
// Byte 1 contains the resampler ratio for TX and RX modem
if (pdata[1] >= 8)
{
printf("wrong speedmode %d, ignoring\n", pdata[1]);
return;
}
speedmode = pdata[1];
printf("set speedmode to %d\n", speedmode);
restart_modems = 1;
@ -394,6 +436,42 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
return;
}
if (type == 23)
{
// set playback volume (in % 0..100)
setVolume_voice(0, minfo);
return;
}
if (type == 24)
{
// set capture volume (in % 0..100)
setVolume_voice(1, minfo);
return;
}
if (type == 25)
{
//printf("%d %d %d %d %d\n", pdata[0], pdata[1], pdata[2], pdata[3], pdata[4]);
LSDeviceNo = pdata[1];
MicDeviceNo = pdata[2];
VoiceAudioMode = pdata[3];
codec = pdata[4];
// init voice audio
init_voice_result = init_audio_voice(LSDeviceNo, MicDeviceNo);
init_voiceproc();
return;
}
if (type == 26)
{
// GUI requests termination of this hsmodem
printf("shut down hsmodem\n");
closeAllandTerminate();
}
if (len != (PAYLOADLEN + 2))
{
printf("data from app: wrong length:%d (should be %d)\n", len - 2, PAYLOADLEN);
@ -451,12 +529,21 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
uint8_t* pl = unpack_data(pdata, len);
if (pl != NULL)
{
// complete frame received
// send payload to app
uint8_t txpl[PAYLOADLEN + 10 + 1];
memcpy(txpl + 1, pl, PAYLOADLEN + 10);
txpl[0] = 1; // type 1: payload data follows
sendUDP(appIP, UdpDataPort_ModemToApp, txpl, PAYLOADLEN + 10 + 1);
if (VoiceAudioMode != VOICEMODE_DV_FULLDUPLEX)
{
// complete frame received
// send payload to app
uint8_t txpl[PAYLOADLEN + 10 + 1];
memcpy(txpl + 1, pl, PAYLOADLEN + 10);
txpl[0] = 1; // type 1: payload data follows
sendUDP(appIP, UdpDataPort_ModemToApp, txpl, PAYLOADLEN + 10 + 1);
}
else
{
// send to Codec decoder
if (*(pl + 3) != 0) // minfo=0 ... just a filler, ignore
toCodecDecoder(pl + 10, PAYLOADLEN);
}
fnd = 0;
}
else
@ -464,7 +551,7 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
// no frame found
// if longer ws seconds nothing found, reset liquid RX modem
// comes here with symbol rate, i.e. 4000 S/s
int ws = 4;
int ws = 4;
int wt = sr[speedmode].audio / sr[speedmode].tx;
if (++fnd >= (wt * ws))
{

View File

@ -30,6 +30,7 @@
#include <Tlhelp32.h>
#include <winbase.h>
#include <Shlobj.h>
#include "opus.h"
#define _USE_MATH_DEFINES
#include <math.h>
@ -37,6 +38,8 @@
#pragma comment(lib, "basswasapi.lib")
#pragma comment(lib, "libliquid.lib")
#pragma comment(lib, "fftw_lib/libfftw3-3.lib")
#pragma comment(lib, "opus.lib")
#pragma comment(lib, "libcodec2.lib")
#endif
#ifdef _LINUX_
@ -52,6 +55,7 @@
#include <arpa/inet.h>
#include <pwd.h>
#include <math.h>
#include <opus/opus.h>
#endif
#include "bass.h"
@ -62,6 +66,8 @@
#include "fec.h"
#include "udp.h"
#include "symboltracker.h"
#include "bassenc_opus.h"
#include "codec2.h"
#define jpg_tempfilename "rxdata.jpg"
@ -73,6 +79,18 @@
#define MAXDEVSTRLEN 2000
#define CHANNELS 1 // no of channels used
// voice audio sampling rate
#define VOICE_SAMPRATE 48000 // do NOT change, OPUS works with 48k only
enum _VOICEMODES_ {
VOICEMODE_OFF,
VOICEMODE_LISTENAUDIOIN,
VOICEMODE_INTERNALLOOP,
VOICEMODE_CODECLOOP,
VOICEMODE_DV_FULLDUPLEX,
VOICEMODE_DV_RXONLY
};
void init_packer();
uint8_t* Pack(uint8_t* payload, int type, int status, int* plen);
uint8_t* unpack_data(uint8_t* rxd, int len);
@ -96,7 +114,7 @@ void TX_Scramble(uint8_t* data, int len);
uint8_t* RX_Scramble(uint8_t* data, int len);
uint16_t Crc16_messagecalc(int rxtx, uint8_t* data, int len);
void showbytestring(char* title, uint8_t* data, int anz);
void showbytestring(char* title, uint8_t* data, int totallen, int anz);
void measure_speed_syms(int len);
void measure_speed_bps(int len);
@ -106,6 +124,7 @@ int cfec_Reconstruct(uint8_t* darr, uint8_t* destination);
int init_audio(int pbdev, int capdev);
int pb_fifo_freespace(int nolock);
int pb_fifo_usedspace();
void pb_write_fifo_clear();
void pb_write_fifo(float sample);
int cap_read_fifo(float* data);
@ -113,11 +132,17 @@ uint8_t* getAudioDevicelist(int* len);
void setPBvolume(int v);
void setCAPvolume(int v);
void setVolume(int pbcap, int v);
void setVolume_voice(int pbcap, int v);
int init_wasapi(int pbdev, int capdev);
void sendAnnouncement();
void readAudioDevices();
void clear_audio_fifos();
void clear_voice_fifos();
void sleep_ms(int ms);
int getus();
void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock);
void toGR_sendData(uint8_t* data, int type, int status);
void modulator(uint8_t sym_in);
int pb_fifo_usedBlocks();
@ -131,6 +156,30 @@ void exit_fft();
void showbytestringf(char* title, float* data, int anz);
uint16_t* make_waterfall(float fre, int* retlen);
int init_audio_voice(int setpbdev, int setcapdev);
void pb_write_fifo_voice(float sample);
int cap_read_fifo_voice(float* data);
void toVoice(float sample);
void toCodecDecoder(uint8_t* pdata, int len);
void init_voiceproc();
void encode(float f);
int init_wasapi_voice(int pbdev, int capdev);
void init_codec2();
void encode_codec2(float f);
void toCodecDecoder_codec2(uint8_t* pdata, int len);
void close_wasapi();
void close_wasapi_voice();
void closeAllandTerminate();
void close_voiceproc();
void close_codec2();
void close_audio();
void close_audio_voice();
int cap_fifo_usedPercent();
void km_symtrack_cccf_create(int _ftype,
unsigned int _k,
unsigned int _m,
@ -147,17 +196,33 @@ extern int speed;
extern int keeprunning;
extern int caprate;
extern int BC_sock_AppToModem;
extern int DATA_sock_AppToModem;
extern int UdpDataPort_ModemToApp;
extern int txinterpolfactor;
extern int rxPreInterpolfactor;
extern char appIP[20];
extern float softwareCAPvolume;
extern float softwareCAPvolume_voice;
extern int announcement;
extern int ann_running;
extern int transmissions;
extern int linespeed;
extern uint8_t maxLevel;
extern int psk8mode;
extern int VoiceAudioMode;
extern int opusbitrate;
extern int init_audio_result;
extern int init_voice_result;
extern int initialLSvol;
extern int initialMICvol;
extern int codec;
// audio device description table
typedef struct {
int bassdev; // bass (basswasapi) dev no
char name[256]; // DEV name
char id[256];
} AUDIODEVS;
#ifdef _LINUX_
int isRunning(char* prgname);

View File

@ -162,6 +162,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>wsock32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/NODEFAULTLIB:libcmt.lib %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -220,20 +221,28 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="bass.h" />
<ClInclude Include="bassflac.h" />
<ClInclude Include="bassenc.h" />
<ClInclude Include="bassenc_opus.h" />
<ClInclude Include="basswasapi.h" />
<ClInclude Include="codec2.h" />
<ClInclude Include="fec.h" />
<ClInclude Include="fftw3.h" />
<ClInclude Include="fftw_lib\fftw3.h" />
<ClInclude Include="frameformat.h" />
<ClInclude Include="hsmodem.h" />
<ClInclude Include="liquid.h" />
<ClInclude Include="opus.h" />
<ClInclude Include="opus_defines.h" />
<ClInclude Include="opus_types.h" />
<ClInclude Include="symboltracker.h" />
<ClInclude Include="udp.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="audio.cpp" />
<ClCompile Include="audio_voice.cpp" />
<ClCompile Include="audio_voice_wasapi.cpp" />
<ClCompile Include="audio_wasapi.cpp" />
<ClCompile Include="codec2.cpp" />
<ClCompile Include="constellation.cpp" />
<ClCompile Include="crc16.cpp" />
<ClCompile Include="fec.cpp" />
@ -246,6 +255,7 @@
<ClCompile Include="speed.cpp" />
<ClCompile Include="symboltracker.cpp" />
<ClCompile Include="udp.cpp" />
<ClCompile Include="voiceprocessor.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -57,6 +57,18 @@
<ClCompile Include="symboltracker.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="audio_voice.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="voiceprocessor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="audio_voice_wasapi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="codec2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="hsmodem.h">
@ -86,10 +98,25 @@
<ClInclude Include="fec.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="bassflac.h">
<ClInclude Include="symboltracker.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="symboltracker.h">
<ClInclude Include="bassenc_opus.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="bassenc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="opus.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="opus_defines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="opus_types.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="codec2.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>

BIN
hsmodem/libcodec2.lib Executable file

Binary file not shown.

View File

@ -53,10 +53,7 @@ modulation_scheme getMod()
return LIQUID_MODEM_QPSK;
else
{
if(psk8mode == 0)
return LIQUID_MODEM_APSK8;
else
return LIQUID_MODEM_PSK8;
return LIQUID_MODEM_APSK8;
}
}
@ -281,10 +278,15 @@ void make_FFTdata(float f)
int bidx = 0;
txpl[bidx++] = 4; // type 4: FFT data follows
int us = pb_fifo_usedBlocks();
if (us > 255 || ann_running == 1) us = 255;
txpl[bidx++] = us; // usage of TX fifo
us = cap_fifo_usedPercent();
if (us > 255) us = 255;
txpl[bidx++] = us; // usage of TX fifo
for (int i = 0; i < fftlen; i++)
{
txpl[bidx++] = fft[i] >> 8;

View File

@ -69,9 +69,36 @@ void install_signal_handler()
}
#endif // _LINUX_
void showbytestring(char *title, uint8_t *data, int anz)
void closeAllandTerminate()
{
printf("%s. Len %d: ",title,anz);
// terminate all Threads
keeprunning = 0;
// close audio
#ifdef _LINUX_
close_audio();
close_audio_voice();
#endif
#ifdef _WIN32_
close_wasapi();
close_wasapi_voice();
#endif
// close fft
exit_fft();
// close codec2 and opus
close_codec2();
close_voiceproc();
// close liquid-SDR
close_dsp();
// close network sockets
close(BC_sock_AppToModem);
close(DATA_sock_AppToModem);
exit(0);
}
void showbytestring(char *title, uint8_t *data, int totallen, int anz)
{
printf("%s. Len %d: ",title, totallen);
for(int i=0; i<anz; i++)
printf("%02X ",data[i]);
printf("\n");

981
hsmodem/opus.h Executable file
View File

@ -0,0 +1,981 @@
/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
Written by Jean-Marc Valin and Koen Vos */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file opus.h
* @brief Opus reference implementation API
*/
#ifndef OPUS_H
#define OPUS_H
#include "opus_types.h"
#include "opus_defines.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @mainpage Opus
*
* The Opus codec is designed for interactive speech and audio transmission over the Internet.
* It is designed by the IETF Codec Working Group and incorporates technology from
* Skype's SILK codec and Xiph.Org's CELT codec.
*
* The Opus codec is designed to handle a wide range of interactive audio applications,
* including Voice over IP, videoconferencing, in-game chat, and even remote live music
* performances. It can scale from low bit-rate narrowband speech to very high quality
* stereo music. Its main features are:
* @li Sampling rates from 8 to 48 kHz
* @li Bit-rates from 6 kb/s to 510 kb/s
* @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR)
* @li Audio bandwidth from narrowband to full-band
* @li Support for speech and music
* @li Support for mono and stereo
* @li Support for multichannel (up to 255 channels)
* @li Frame sizes from 2.5 ms to 60 ms
* @li Good loss robustness and packet loss concealment (PLC)
* @li Floating point and fixed-point implementation
*
* Documentation sections:
* @li @ref opus_encoder
* @li @ref opus_decoder
* @li @ref opus_repacketizer
* @li @ref opus_multistream
* @li @ref opus_libinfo
* @li @ref opus_custom
*/
/** @defgroup opus_encoder Opus Encoder
* @{
*
* @brief This page describes the process and functions used to encode Opus.
*
* Since Opus is a stateful codec, the encoding process starts with creating an encoder
* state. This can be done with:
*
* @code
* int error;
* OpusEncoder *enc;
* enc = opus_encoder_create(Fs, channels, application, &error);
* @endcode
*
* From this point, @c enc can be used for encoding an audio stream. An encoder state
* @b must @b not be used for more than one stream at the same time. Similarly, the encoder
* state @b must @b not be re-initialized for each frame.
*
* While opus_encoder_create() allocates memory for the state, it's also possible
* to initialize pre-allocated memory:
*
* @code
* int size;
* int error;
* OpusEncoder *enc;
* size = opus_encoder_get_size(channels);
* enc = malloc(size);
* error = opus_encoder_init(enc, Fs, channels, application);
* @endcode
*
* where opus_encoder_get_size() returns the required size for the encoder state. Note that
* future versions of this code may change the size, so no assuptions should be made about it.
*
* The encoder state is always continuous in memory and only a shallow copy is sufficient
* to copy it (e.g. memcpy())
*
* It is possible to change some of the encoder's settings using the opus_encoder_ctl()
* interface. All these settings already default to the recommended value, so they should
* only be changed when necessary. The most common settings one may want to change are:
*
* @code
* opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));
* opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
* opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type));
* @endcode
*
* where
*
* @arg bitrate is in bits per second (b/s)
* @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest
* @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC
*
* See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream.
*
* To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data:
* @code
* len = opus_encode(enc, audio_frame, frame_size, packet, max_packet);
* @endcode
*
* where
* <ul>
* <li>audio_frame is the audio data in opus_int16 (or float for opus_encode_float())</li>
* <li>frame_size is the duration of the frame in samples (per channel)</li>
* <li>packet is the byte array to which the compressed data is written</li>
* <li>max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended).
* Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.</li>
* </ul>
*
* opus_encode() and opus_encode_float() return the number of bytes actually written to the packet.
* The return value <b>can be negative</b>, which indicates that an error has occurred. If the return value
* is 2 bytes or less, then the packet does not need to be transmitted (DTX).
*
* Once the encoder state if no longer needed, it can be destroyed with
*
* @code
* opus_encoder_destroy(enc);
* @endcode
*
* If the encoder was created with opus_encoder_init() rather than opus_encoder_create(),
* then no action is required aside from potentially freeing the memory that was manually
* allocated for it (calling free(enc) for the example above)
*
*/
/** Opus encoder state.
* This contains the complete state of an Opus encoder.
* It is position independent and can be freely copied.
* @see opus_encoder_create,opus_encoder_init
*/
typedef struct OpusEncoder OpusEncoder;
/** Gets the size of an <code>OpusEncoder</code> structure.
* @param[in] channels <tt>int</tt>: Number of channels.
* This must be 1 or 2.
* @returns The size in bytes.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);
/**
*/
/** Allocates and initializes an encoder state.
* There are three coding modes:
*
* @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice
* signals. It enhances the input signal by high-pass filtering and
* emphasizing formants and harmonics. Optionally it includes in-band
* forward error correction to protect against packet loss. Use this
* mode for typical VoIP applications. Because of the enhancement,
* even at high bitrates the output may sound different from the input.
*
* @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most
* non-voice signals like music. Use this mode for music and mixed
* (music/voice) content, broadcast, and applications requiring less
* than 15 ms of coding delay.
*
* @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that
* disables the speech-optimized mode in exchange for slightly reduced delay.
* This mode can only be set on an newly initialized or freshly reset encoder
* because it changes the codec delay.
*
* This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution).
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)
* This must be one of 8000, 12000, 16000,
* 24000, or 48000.
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
* @param [in] application <tt>int</tt>: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
* @param [out] error <tt>int*</tt>: @ref opus_errorcodes
* @note Regardless of the sampling rate and number channels selected, the Opus encoder
* can switch to a lower audio bandwidth or number of channels if the bitrate
* selected is too low. This also means that it is safe to always use 48 kHz stereo input
* and let the encoder optimize the encoding.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(
opus_int32 Fs,
int channels,
int application,
int *error
);
/** Initializes a previously allocated encoder state
* The memory pointed to by st must be at least the size returned by opus_encoder_get_size().
* This is intended for applications which use their own allocator instead of malloc.
* @see opus_encoder_create(),opus_encoder_get_size()
* To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
* @param [in] st <tt>OpusEncoder*</tt>: Encoder state
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)
* This must be one of 8000, 12000, 16000,
* 24000, or 48000.
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
* @param [in] application <tt>int</tt>: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)
* @retval #OPUS_OK Success or @ref opus_errorcodes
*/
OPUS_EXPORT int opus_encoder_init(
OpusEncoder *st,
opus_int32 Fs,
int channels,
int application
) OPUS_ARG_NONNULL(1);
/** Encodes an Opus frame.
* @param [in] st <tt>OpusEncoder*</tt>: Encoder state
* @param [in] pcm <tt>opus_int16*</tt>: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16)
* @param [in] frame_size <tt>int</tt>: Number of samples per channel in the
* input signal.
* This must be an Opus frame size for
* the encoder's sampling rate.
* For example, at 48 kHz the permitted
* values are 120, 240, 480, 960, 1920,
* and 2880.
* Passing in a duration of less than
* 10 ms (480 samples at 48 kHz) will
* prevent the encoder from using the LPC
* or hybrid modes.
* @param [out] data <tt>unsigned char*</tt>: Output payload.
* This must contain storage for at
* least \a max_data_bytes.
* @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
* memory for the output
* payload. This may be
* used to impose an upper limit on
* the instant bitrate, but should
* not be used as the only bitrate
* control. Use #OPUS_SET_BITRATE to
* control the bitrate.
* @returns The length of the encoded packet (in bytes) on success or a
* negative error code (see @ref opus_errorcodes) on failure.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode(
OpusEncoder *st,
const opus_int16 *pcm,
int frame_size,
unsigned char *data,
opus_int32 max_data_bytes
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
/** Encodes an Opus frame from floating point input.
* @param [in] st <tt>OpusEncoder*</tt>: Encoder state
* @param [in] pcm <tt>float*</tt>: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0.
* Samples with a range beyond +/-1.0 are supported but will
* be clipped by decoders using the integer API and should
* only be used if it is known that the far end supports
* extended dynamic range.
* length is frame_size*channels*sizeof(float)
* @param [in] frame_size <tt>int</tt>: Number of samples per channel in the
* input signal.
* This must be an Opus frame size for
* the encoder's sampling rate.
* For example, at 48 kHz the permitted
* values are 120, 240, 480, 960, 1920,
* and 2880.
* Passing in a duration of less than
* 10 ms (480 samples at 48 kHz) will
* prevent the encoder from using the LPC
* or hybrid modes.
* @param [out] data <tt>unsigned char*</tt>: Output payload.
* This must contain storage for at
* least \a max_data_bytes.
* @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
* memory for the output
* payload. This may be
* used to impose an upper limit on
* the instant bitrate, but should
* not be used as the only bitrate
* control. Use #OPUS_SET_BITRATE to
* control the bitrate.
* @returns The length of the encoded packet (in bytes) on success or a
* negative error code (see @ref opus_errorcodes) on failure.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float(
OpusEncoder *st,
const float *pcm,
int frame_size,
unsigned char *data,
opus_int32 max_data_bytes
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
/** Frees an <code>OpusEncoder</code> allocated by opus_encoder_create().
* @param[in] st <tt>OpusEncoder*</tt>: State to be freed.
*/
OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st);
/** Perform a CTL function on an Opus encoder.
*
* Generally the request and subsequent arguments are generated
* by a convenience macro.
* @param st <tt>OpusEncoder*</tt>: Encoder state.
* @param request This and all remaining parameters should be replaced by one
* of the convenience macros in @ref opus_genericctls or
* @ref opus_encoderctls.
* @see opus_genericctls
* @see opus_encoderctls
*/
OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
/**@}*/
/** @defgroup opus_decoder Opus Decoder
* @{
*
* @brief This page describes the process and functions used to decode Opus.
*
* The decoding process also starts with creating a decoder
* state. This can be done with:
* @code
* int error;
* OpusDecoder *dec;
* dec = opus_decoder_create(Fs, channels, &error);
* @endcode
* where
* @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000
* @li channels is the number of channels (1 or 2)
* @li error will hold the error code in case of failure (or #OPUS_OK on success)
* @li the return value is a newly created decoder state to be used for decoding
*
* While opus_decoder_create() allocates memory for the state, it's also possible
* to initialize pre-allocated memory:
* @code
* int size;
* int error;
* OpusDecoder *dec;
* size = opus_decoder_get_size(channels);
* dec = malloc(size);
* error = opus_decoder_init(dec, Fs, channels);
* @endcode
* where opus_decoder_get_size() returns the required size for the decoder state. Note that
* future versions of this code may change the size, so no assuptions should be made about it.
*
* The decoder state is always continuous in memory and only a shallow copy is sufficient
* to copy it (e.g. memcpy())
*
* To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data:
* @code
* frame_size = opus_decode(dec, packet, len, decoded, max_size, 0);
* @endcode
* where
*
* @li packet is the byte array containing the compressed data
* @li len is the exact number of bytes contained in the packet
* @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float())
* @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array
*
* opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet.
* If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio
* buffer is too small to hold the decoded audio.
*
* Opus is a stateful codec with overlapping blocks and as a result Opus
* packets are not coded independently of each other. Packets must be
* passed into the decoder serially and in the correct order for a correct
* decode. Lost packets can be replaced with loss concealment by calling
* the decoder with a null pointer and zero length for the missing packet.
*
* A single codec state may only be accessed from a single thread at
* a time and any required locking must be performed by the caller. Separate
* streams must be decoded with separate decoder states and can be decoded
* in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK
* defined.
*
*/
/** Opus decoder state.
* This contains the complete state of an Opus decoder.
* It is position independent and can be freely copied.
* @see opus_decoder_create,opus_decoder_init
*/
typedef struct OpusDecoder OpusDecoder;
/** Gets the size of an <code>OpusDecoder</code> structure.
* @param [in] channels <tt>int</tt>: Number of channels.
* This must be 1 or 2.
* @returns The size in bytes.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels);
/** Allocates and initializes a decoder state.
* @param [in] Fs <tt>opus_int32</tt>: Sample rate to decode at (Hz).
* This must be one of 8000, 12000, 16000,
* 24000, or 48000.
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode
* @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes
*
* Internally Opus stores data at 48000 Hz, so that should be the default
* value for Fs. However, the decoder can efficiently decode to buffers
* at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use
* data at the full sample rate, or knows the compressed data doesn't
* use the full frequency range, it can request decoding at a reduced
* rate. Likewise, the decoder is capable of filling in either mono or
* interleaved stereo pcm buffers, at the caller's request.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create(
opus_int32 Fs,
int channels,
int *error
);
/** Initializes a previously allocated decoder state.
* The state must be at least the size returned by opus_decoder_get_size().
* This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size
* To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
* @param [in] st <tt>OpusDecoder*</tt>: Decoder state.
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate to decode to (Hz).
* This must be one of 8000, 12000, 16000,
* 24000, or 48000.
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode
* @retval #OPUS_OK Success or @ref opus_errorcodes
*/
OPUS_EXPORT int opus_decoder_init(
OpusDecoder *st,
opus_int32 Fs,
int channels
) OPUS_ARG_NONNULL(1);
/** Decode an Opus packet.
* @param [in] st <tt>OpusDecoder*</tt>: Decoder state
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
* @param [in] len <tt>opus_int32</tt>: Number of bytes in payload*
* @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
* is frame_size*channels*sizeof(opus_int16)
* @param [in] frame_size Number of samples per channel of available space in \a pcm.
* If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
* not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
* then frame_size needs to be exactly the duration of audio that is missing, otherwise the
* decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
* FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
* @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
* decoded. If no such data is available, the frame is decoded as if it were lost.
* @returns Number of decoded samples or @ref opus_errorcodes
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode(
OpusDecoder *st,
const unsigned char *data,
opus_int32 len,
opus_int16 *pcm,
int frame_size,
int decode_fec
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
/** Decode an Opus packet with floating point output.
* @param [in] st <tt>OpusDecoder*</tt>: Decoder state
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
* @param [in] len <tt>opus_int32</tt>: Number of bytes in payload
* @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
* is frame_size*channels*sizeof(float)
* @param [in] frame_size Number of samples per channel of available space in \a pcm.
* If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
* not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
* then frame_size needs to be exactly the duration of audio that is missing, otherwise the
* decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
* FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
* @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
* decoded. If no such data is available the frame is decoded as if it were lost.
* @returns Number of decoded samples or @ref opus_errorcodes
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float(
OpusDecoder *st,
const unsigned char *data,
opus_int32 len,
float *pcm,
int frame_size,
int decode_fec
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
/** Perform a CTL function on an Opus decoder.
*
* Generally the request and subsequent arguments are generated
* by a convenience macro.
* @param st <tt>OpusDecoder*</tt>: Decoder state.
* @param request This and all remaining parameters should be replaced by one
* of the convenience macros in @ref opus_genericctls or
* @ref opus_decoderctls.
* @see opus_genericctls
* @see opus_decoderctls
*/
OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
/** Frees an <code>OpusDecoder</code> allocated by opus_decoder_create().
* @param[in] st <tt>OpusDecoder*</tt>: State to be freed.
*/
OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
/** Parse an opus packet into one or more frames.
* Opus_decode will perform this operation internally so most applications do
* not need to use this function.
* This function does not copy the frames, the returned pointers are pointers into
* the input packet.
* @param [in] data <tt>char*</tt>: Opus packet to be parsed
* @param [in] len <tt>opus_int32</tt>: size of data
* @param [out] out_toc <tt>char*</tt>: TOC pointer
* @param [out] frames <tt>char*[48]</tt> encapsulated frames
* @param [out] size <tt>opus_int16[48]</tt> sizes of the encapsulated frames
* @param [out] payload_offset <tt>int*</tt>: returns the position of the payload within the packet (in bytes)
* @returns number of frames
*/
OPUS_EXPORT int opus_packet_parse(
const unsigned char *data,
opus_int32 len,
unsigned char *out_toc,
const unsigned char *frames[48],
opus_int16 size[48],
int *payload_offset
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5);
/** Gets the bandwidth of an Opus packet.
* @param [in] data <tt>char*</tt>: Opus packet
* @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass)
* @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass)
* @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass)
* @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass)
* @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass)
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1);
/** Gets the number of samples per frame from an Opus packet.
* @param [in] data <tt>char*</tt>: Opus packet.
* This must contain at least one byte of
* data.
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
* This must be a multiple of 400, or
* inaccurate results will be returned.
* @returns Number of samples per frame.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1);
/** Gets the number of channels from an Opus packet.
* @param [in] data <tt>char*</tt>: Opus packet
* @returns Number of channels
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1);
/** Gets the number of frames in an Opus packet.
* @param [in] packet <tt>char*</tt>: Opus packet
* @param [in] len <tt>opus_int32</tt>: Length of packet
* @returns Number of frames
* @retval OPUS_BAD_ARG Insufficient data was passed to the function
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1);
/** Gets the number of samples of an Opus packet.
* @param [in] packet <tt>char*</tt>: Opus packet
* @param [in] len <tt>opus_int32</tt>: Length of packet
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
* This must be a multiple of 400, or
* inaccurate results will be returned.
* @returns Number of samples
* @retval OPUS_BAD_ARG Insufficient data was passed to the function
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
/** Gets the number of samples of an Opus packet.
* @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
* @param [in] packet <tt>char*</tt>: Opus packet
* @param [in] len <tt>opus_int32</tt>: Length of packet
* @returns Number of samples
* @retval OPUS_BAD_ARG Insufficient data was passed to the function
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
/** Applies soft-clipping to bring a float signal within the [-1,1] range. If
* the signal is already in that range, nothing is done. If there are values
* outside of [-1,1], then the signal is clipped as smoothly as possible to
* both fit in the range and avoid creating excessive distortion in the
* process.
* @param [in,out] pcm <tt>float*</tt>: Input PCM and modified PCM
* @param [in] frame_size <tt>int</tt> Number of samples per channel to process
* @param [in] channels <tt>int</tt>: Number of channels
* @param [in,out] softclip_mem <tt>float*</tt>: State memory for the soft clipping process (one float per channel, initialized to zero)
*/
OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem);
/**@}*/
/** @defgroup opus_repacketizer Repacketizer
* @{
*
* The repacketizer can be used to merge multiple Opus packets into a single
* packet or alternatively to split Opus packets that have previously been
* merged. Splitting valid Opus packets is always guaranteed to succeed,
* whereas merging valid packets only succeeds if all frames have the same
* mode, bandwidth, and frame size, and when the total duration of the merged
* packet is no more than 120 ms. The 120 ms limit comes from the
* specification and limits decoder memory requirements at a point where
* framing overhead becomes negligible.
*
* The repacketizer currently only operates on elementary Opus
* streams. It will not manipualte multistream packets successfully, except in
* the degenerate case where they consist of data from a single stream.
*
* The repacketizing process starts with creating a repacketizer state, either
* by calling opus_repacketizer_create() or by allocating the memory yourself,
* e.g.,
* @code
* OpusRepacketizer *rp;
* rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size());
* if (rp != NULL)
* opus_repacketizer_init(rp);
* @endcode
*
* Then the application should submit packets with opus_repacketizer_cat(),
* extract new packets with opus_repacketizer_out() or
* opus_repacketizer_out_range(), and then reset the state for the next set of
* input packets via opus_repacketizer_init().
*
* For example, to split a sequence of packets into individual frames:
* @code
* unsigned char *data;
* int len;
* while (get_next_packet(&data, &len))
* {
* unsigned char out[1276];
* opus_int32 out_len;
* int nb_frames;
* int err;
* int i;
* err = opus_repacketizer_cat(rp, data, len);
* if (err != OPUS_OK)
* {
* release_packet(data);
* return err;
* }
* nb_frames = opus_repacketizer_get_nb_frames(rp);
* for (i = 0; i < nb_frames; i++)
* {
* out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out));
* if (out_len < 0)
* {
* release_packet(data);
* return (int)out_len;
* }
* output_next_packet(out, out_len);
* }
* opus_repacketizer_init(rp);
* release_packet(data);
* }
* @endcode
*
* Alternatively, to combine a sequence of frames into packets that each
* contain up to <code>TARGET_DURATION_MS</code> milliseconds of data:
* @code
* // The maximum number of packets with duration TARGET_DURATION_MS occurs
* // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5)
* // packets.
* unsigned char *data[(TARGET_DURATION_MS*2/5)+1];
* opus_int32 len[(TARGET_DURATION_MS*2/5)+1];
* int nb_packets;
* unsigned char out[1277*(TARGET_DURATION_MS*2/2)];
* opus_int32 out_len;
* int prev_toc;
* nb_packets = 0;
* while (get_next_packet(data+nb_packets, len+nb_packets))
* {
* int nb_frames;
* int err;
* nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]);
* if (nb_frames < 1)
* {
* release_packets(data, nb_packets+1);
* return nb_frames;
* }
* nb_frames += opus_repacketizer_get_nb_frames(rp);
* // If adding the next packet would exceed our target, or it has an
* // incompatible TOC sequence, output the packets we already have before
* // submitting it.
* // N.B., The nb_packets > 0 check ensures we've submitted at least one
* // packet since the last call to opus_repacketizer_init(). Otherwise a
* // single packet longer than TARGET_DURATION_MS would cause us to try to
* // output an (invalid) empty packet. It also ensures that prev_toc has
* // been set to a valid value. Additionally, len[nb_packets] > 0 is
* // guaranteed by the call to opus_packet_get_nb_frames() above, so the
* // reference to data[nb_packets][0] should be valid.
* if (nb_packets > 0 && (
* ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) ||
* opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames >
* TARGET_DURATION_MS*48))
* {
* out_len = opus_repacketizer_out(rp, out, sizeof(out));
* if (out_len < 0)
* {
* release_packets(data, nb_packets+1);
* return (int)out_len;
* }
* output_next_packet(out, out_len);
* opus_repacketizer_init(rp);
* release_packets(data, nb_packets);
* data[0] = data[nb_packets];
* len[0] = len[nb_packets];
* nb_packets = 0;
* }
* err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]);
* if (err != OPUS_OK)
* {
* release_packets(data, nb_packets+1);
* return err;
* }
* prev_toc = data[nb_packets][0];
* nb_packets++;
* }
* // Output the final, partial packet.
* if (nb_packets > 0)
* {
* out_len = opus_repacketizer_out(rp, out, sizeof(out));
* release_packets(data, nb_packets);
* if (out_len < 0)
* return (int)out_len;
* output_next_packet(out, out_len);
* }
* @endcode
*
* An alternate way of merging packets is to simply call opus_repacketizer_cat()
* unconditionally until it fails. At that point, the merged packet can be
* obtained with opus_repacketizer_out() and the input packet for which
* opus_repacketizer_cat() needs to be re-added to a newly reinitialized
* repacketizer state.
*/
typedef struct OpusRepacketizer OpusRepacketizer;
/** Gets the size of an <code>OpusRepacketizer</code> structure.
* @returns The size in bytes.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void);
/** (Re)initializes a previously allocated repacketizer state.
* The state must be at least the size returned by opus_repacketizer_get_size().
* This can be used for applications which use their own allocator instead of
* malloc().
* It must also be called to reset the queue of packets waiting to be
* repacketized, which is necessary if the maximum packet duration of 120 ms
* is reached or if you wish to submit packets with a different Opus
* configuration (coding mode, audio bandwidth, frame size, or channel count).
* Failure to do so will prevent a new packet from being added with
* opus_repacketizer_cat().
* @see opus_repacketizer_create
* @see opus_repacketizer_get_size
* @see opus_repacketizer_cat
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to
* (re)initialize.
* @returns A pointer to the same repacketizer state that was passed in.
*/
OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
/** Allocates memory and initializes the new repacketizer with
* opus_repacketizer_init().
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void);
/** Frees an <code>OpusRepacketizer</code> allocated by
* opus_repacketizer_create().
* @param[in] rp <tt>OpusRepacketizer*</tt>: State to be freed.
*/
OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp);
/** Add a packet to the current repacketizer state.
* This packet must match the configuration of any packets already submitted
* for repacketization since the last call to opus_repacketizer_init().
* This means that it must have the same coding mode, audio bandwidth, frame
* size, and channel count.
* This can be checked in advance by examining the top 6 bits of the first
* byte of the packet, and ensuring they match the top 6 bits of the first
* byte of any previously submitted packet.
* The total duration of audio in the repacketizer state also must not exceed
* 120 ms, the maximum duration of a single packet, after adding this packet.
*
* The contents of the current repacketizer state can be extracted into new
* packets using opus_repacketizer_out() or opus_repacketizer_out_range().
*
* In order to add a packet with a different configuration or to add more
* audio beyond 120 ms, you must clear the repacketizer state by calling
* opus_repacketizer_init().
* If a packet is too large to add to the current repacketizer state, no part
* of it is added, even if it contains multiple frames, some of which might
* fit.
* If you wish to be able to add parts of such packets, you should first use
* another repacketizer to split the packet into pieces and add them
* individually.
* @see opus_repacketizer_out_range
* @see opus_repacketizer_out
* @see opus_repacketizer_init
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to which to
* add the packet.
* @param[in] data <tt>const unsigned char*</tt>: The packet data.
* The application must ensure
* this pointer remains valid
* until the next call to
* opus_repacketizer_init() or
* opus_repacketizer_destroy().
* @param len <tt>opus_int32</tt>: The number of bytes in the packet data.
* @returns An error code indicating whether or not the operation succeeded.
* @retval #OPUS_OK The packet's contents have been added to the repacketizer
* state.
* @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence,
* the packet's TOC sequence was not compatible
* with previously submitted packets (because
* the coding mode, audio bandwidth, frame size,
* or channel count did not match), or adding
* this packet would increase the total amount of
* audio stored in the repacketizer state to more
* than 120 ms.
*/
OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
/** Construct a new packet from data previously submitted to the repacketizer
* state via opus_repacketizer_cat().
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
* construct the new packet.
* @param begin <tt>int</tt>: The index of the first frame in the current
* repacketizer state to include in the output.
* @param end <tt>int</tt>: One past the index of the last frame in the
* current repacketizer state to include in the
* output.
* @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
* store the output packet.
* @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
* the output buffer. In order to guarantee
* success, this should be at least
* <code>1276</code> for a single frame,
* or for multiple frames,
* <code>1277*(end-begin)</code>.
* However, <code>1*(end-begin)</code> plus
* the size of all packet data submitted to
* the repacketizer since the last call to
* opus_repacketizer_init() or
* opus_repacketizer_create() is also
* sufficient, and possibly much smaller.
* @returns The total size of the output packet on success, or an error code
* on failure.
* @retval #OPUS_BAD_ARG <code>[begin,end)</code> was an invalid range of
* frames (begin < 0, begin >= end, or end >
* opus_repacketizer_get_nb_frames()).
* @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
* complete output packet.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
/** Return the total number of frames contained in packet data submitted to
* the repacketizer state so far via opus_repacketizer_cat() since the last
* call to opus_repacketizer_init() or opus_repacketizer_create().
* This defines the valid range of packets that can be extracted with
* opus_repacketizer_out_range() or opus_repacketizer_out().
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state containing the
* frames.
* @returns The total number of frames contained in the packet data submitted
* to the repacketizer state.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
/** Construct a new packet from data previously submitted to the repacketizer
* state via opus_repacketizer_cat().
* This is a convenience routine that returns all the data submitted so far
* in a single packet.
* It is equivalent to calling
* @code
* opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp),
* data, maxlen)
* @endcode
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
* construct the new packet.
* @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
* store the output packet.
* @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
* the output buffer. In order to guarantee
* success, this should be at least
* <code>1277*opus_repacketizer_get_nb_frames(rp)</code>.
* However,
* <code>1*opus_repacketizer_get_nb_frames(rp)</code>
* plus the size of all packet data
* submitted to the repacketizer since the
* last call to opus_repacketizer_init() or
* opus_repacketizer_create() is also
* sufficient, and possibly much smaller.
* @returns The total size of the output packet on success, or an error code
* on failure.
* @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
* complete output packet.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1);
/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence).
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
* packet to pad.
* @param len <tt>opus_int32</tt>: The size of the packet.
* This must be at least 1.
* @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
* This must be at least as large as len.
* @returns an error code
* @retval #OPUS_OK \a on success.
* @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
*/
OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len);
/** Remove all padding from a given Opus packet and rewrite the TOC sequence to
* minimize space usage.
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
* packet to strip.
* @param len <tt>opus_int32</tt>: The size of the packet.
* This must be at least 1.
* @returns The new size of the output packet on success, or an error code
* on failure.
* @retval #OPUS_BAD_ARG \a len was less than 1.
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len);
/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence).
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
* packet to pad.
* @param len <tt>opus_int32</tt>: The size of the packet.
* This must be at least 1.
* @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
* This must be at least 1.
* @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
* This must be at least as large as len.
* @returns an error code
* @retval #OPUS_OK \a on success.
* @retval #OPUS_BAD_ARG \a len was less than 1.
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
*/
OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams);
/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to
* minimize space usage.
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
* packet to strip.
* @param len <tt>opus_int32</tt>: The size of the packet.
* This must be at least 1.
* @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
* This must be at least 1.
* @returns The new size of the output packet on success, or an error code
* on failure.
* @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams);
/**@}*/
#ifdef __cplusplus
}
#endif
#endif /* OPUS_H */

BIN
hsmodem/opus.lib Executable file

Binary file not shown.

799
hsmodem/opus_defines.h Executable file
View File

@ -0,0 +1,799 @@
/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
Written by Jean-Marc Valin and Koen Vos */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file opus_defines.h
* @brief Opus reference implementation constants
*/
#ifndef OPUS_DEFINES_H
#define OPUS_DEFINES_H
#include "opus_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup opus_errorcodes Error codes
* @{
*/
/** No error @hideinitializer*/
#define OPUS_OK 0
/** One or more invalid/out of range arguments @hideinitializer*/
#define OPUS_BAD_ARG -1
/** Not enough bytes allocated in the buffer @hideinitializer*/
#define OPUS_BUFFER_TOO_SMALL -2
/** An internal error was detected @hideinitializer*/
#define OPUS_INTERNAL_ERROR -3
/** The compressed data passed is corrupted @hideinitializer*/
#define OPUS_INVALID_PACKET -4
/** Invalid/unsupported request number @hideinitializer*/
#define OPUS_UNIMPLEMENTED -5
/** An encoder or decoder structure is invalid or already freed @hideinitializer*/
#define OPUS_INVALID_STATE -6
/** Memory allocation has failed @hideinitializer*/
#define OPUS_ALLOC_FAIL -7
/**@}*/
/** @cond OPUS_INTERNAL_DOC */
/**Export control for opus functions */
#ifndef OPUS_EXPORT
# if defined(WIN32)
# if defined(OPUS_BUILD) && defined(DLL_EXPORT)
# define OPUS_EXPORT __declspec(dllexport)
# else
# define OPUS_EXPORT
# endif
# elif defined(__GNUC__) && defined(OPUS_BUILD)
# define OPUS_EXPORT __attribute__ ((visibility ("default")))
# else
# define OPUS_EXPORT
# endif
#endif
# if !defined(OPUS_GNUC_PREREQ)
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
# define OPUS_GNUC_PREREQ(_maj,_min) \
((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
# else
# define OPUS_GNUC_PREREQ(_maj,_min) 0
# endif
# endif
#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
# if OPUS_GNUC_PREREQ(3,0)
# define OPUS_RESTRICT __restrict__
# elif (defined(_MSC_VER) && _MSC_VER >= 1400)
# define OPUS_RESTRICT __restrict
# else
# define OPUS_RESTRICT
# endif
#else
# define OPUS_RESTRICT restrict
#endif
#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
# if OPUS_GNUC_PREREQ(2,7)
# define OPUS_INLINE __inline__
# elif (defined(_MSC_VER))
# define OPUS_INLINE __inline
# else
# define OPUS_INLINE
# endif
#else
# define OPUS_INLINE inline
#endif
/**Warning attributes for opus functions
* NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out
* some paranoid null checks. */
#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
#else
# define OPUS_WARN_UNUSED_RESULT
#endif
#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
# define OPUS_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x)))
#else
# define OPUS_ARG_NONNULL(_x)
#endif
/** These are the actual Encoder CTL ID numbers.
* They should not be used directly by applications.
* In general, SETs should be even and GETs should be odd.*/
#define OPUS_SET_APPLICATION_REQUEST 4000
#define OPUS_GET_APPLICATION_REQUEST 4001
#define OPUS_SET_BITRATE_REQUEST 4002
#define OPUS_GET_BITRATE_REQUEST 4003
#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004
#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005
#define OPUS_SET_VBR_REQUEST 4006
#define OPUS_GET_VBR_REQUEST 4007
#define OPUS_SET_BANDWIDTH_REQUEST 4008
#define OPUS_GET_BANDWIDTH_REQUEST 4009
#define OPUS_SET_COMPLEXITY_REQUEST 4010
#define OPUS_GET_COMPLEXITY_REQUEST 4011
#define OPUS_SET_INBAND_FEC_REQUEST 4012
#define OPUS_GET_INBAND_FEC_REQUEST 4013
#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014
#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015
#define OPUS_SET_DTX_REQUEST 4016
#define OPUS_GET_DTX_REQUEST 4017
#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020
#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021
#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022
#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023
#define OPUS_SET_SIGNAL_REQUEST 4024
#define OPUS_GET_SIGNAL_REQUEST 4025
#define OPUS_GET_LOOKAHEAD_REQUEST 4027
/* #define OPUS_RESET_STATE 4028 */
#define OPUS_GET_SAMPLE_RATE_REQUEST 4029
#define OPUS_GET_FINAL_RANGE_REQUEST 4031
#define OPUS_GET_PITCH_REQUEST 4033
#define OPUS_SET_GAIN_REQUEST 4034
#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */
#define OPUS_SET_LSB_DEPTH_REQUEST 4036
#define OPUS_GET_LSB_DEPTH_REQUEST 4037
#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039
#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040
#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041
#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042
#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043
/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046
#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047
#define OPUS_GET_IN_DTX_REQUEST 4049
/** Defines for the presence of extended APIs. */
#define OPUS_HAVE_OPUS_PROJECTION_H
/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))
#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))
/** @endcond */
/** @defgroup opus_ctlvalues Pre-defined values for CTL interface
* @see opus_genericctls, opus_encoderctls
* @{
*/
/* Values for the various encoder CTLs */
#define OPUS_AUTO -1000 /**<Auto/default setting @hideinitializer*/
#define OPUS_BITRATE_MAX -1 /**<Maximum bitrate @hideinitializer*/
/** Best for most VoIP/videoconference applications where listening quality and intelligibility matter most
* @hideinitializer */
#define OPUS_APPLICATION_VOIP 2048
/** Best for broadcast/high-fidelity application where the decoded audio should be as close as possible to the input
* @hideinitializer */
#define OPUS_APPLICATION_AUDIO 2049
/** Only use when lowest-achievable latency is what matters most. Voice-optimized modes cannot be used.
* @hideinitializer */
#define OPUS_APPLICATION_RESTRICTED_LOWDELAY 2051
#define OPUS_SIGNAL_VOICE 3001 /**< Signal being encoded is voice */
#define OPUS_SIGNAL_MUSIC 3002 /**< Signal being encoded is music */
#define OPUS_BANDWIDTH_NARROWBAND 1101 /**< 4 kHz bandpass @hideinitializer*/
#define OPUS_BANDWIDTH_MEDIUMBAND 1102 /**< 6 kHz bandpass @hideinitializer*/
#define OPUS_BANDWIDTH_WIDEBAND 1103 /**< 8 kHz bandpass @hideinitializer*/
#define OPUS_BANDWIDTH_SUPERWIDEBAND 1104 /**<12 kHz bandpass @hideinitializer*/
#define OPUS_BANDWIDTH_FULLBAND 1105 /**<20 kHz bandpass @hideinitializer*/
#define OPUS_FRAMESIZE_ARG 5000 /**< Select frame size from the argument (default) */
#define OPUS_FRAMESIZE_2_5_MS 5001 /**< Use 2.5 ms frames */
#define OPUS_FRAMESIZE_5_MS 5002 /**< Use 5 ms frames */
#define OPUS_FRAMESIZE_10_MS 5003 /**< Use 10 ms frames */
#define OPUS_FRAMESIZE_20_MS 5004 /**< Use 20 ms frames */
#define OPUS_FRAMESIZE_40_MS 5005 /**< Use 40 ms frames */
#define OPUS_FRAMESIZE_60_MS 5006 /**< Use 60 ms frames */
#define OPUS_FRAMESIZE_80_MS 5007 /**< Use 80 ms frames */
#define OPUS_FRAMESIZE_100_MS 5008 /**< Use 100 ms frames */
#define OPUS_FRAMESIZE_120_MS 5009 /**< Use 120 ms frames */
/**@}*/
/** @defgroup opus_encoderctls Encoder related CTLs
*
* These are convenience macros for use with the \c opus_encode_ctl
* interface. They are used to generate the appropriate series of
* arguments for that call, passing the correct type, size and so
* on as expected for each particular request.
*
* Some usage examples:
*
* @code
* int ret;
* ret = opus_encoder_ctl(enc_ctx, OPUS_SET_BANDWIDTH(OPUS_AUTO));
* if (ret != OPUS_OK) return ret;
*
* opus_int32 rate;
* opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&rate));
*
* opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);
* @endcode
*
* @see opus_genericctls, opus_encoder
* @{
*/
/** Configures the encoder's computational complexity.
* The supported range is 0-10 inclusive with 10 representing the highest complexity.
* @see OPUS_GET_COMPLEXITY
* @param[in] x <tt>opus_int32</tt>: Allowed values: 0-10, inclusive.
*
* @hideinitializer */
#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x)
/** Gets the encoder's complexity configuration.
* @see OPUS_SET_COMPLEXITY
* @param[out] x <tt>opus_int32 *</tt>: Returns a value in the range 0-10,
* inclusive.
* @hideinitializer */
#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x)
/** Configures the bitrate in the encoder.
* Rates from 500 to 512000 bits per second are meaningful, as well as the
* special values #OPUS_AUTO and #OPUS_BITRATE_MAX.
* The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much
* rate as it can, which is useful for controlling the rate by adjusting the
* output buffer size.
* @see OPUS_GET_BITRATE
* @param[in] x <tt>opus_int32</tt>: Bitrate in bits per second. The default
* is determined based on the number of
* channels and the input sampling rate.
* @hideinitializer */
#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x)
/** Gets the encoder's bitrate configuration.
* @see OPUS_SET_BITRATE
* @param[out] x <tt>opus_int32 *</tt>: Returns the bitrate in bits per second.
* The default is determined based on the
* number of channels and the input
* sampling rate.
* @hideinitializer */
#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x)
/** Enables or disables variable bitrate (VBR) in the encoder.
* The configured bitrate may not be met exactly because frames must
* be an integer number of bytes in length.
* @see OPUS_GET_VBR
* @see OPUS_SET_VBR_CONSTRAINT
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>0</dt><dd>Hard CBR. For LPC/hybrid modes at very low bit-rate, this can
* cause noticeable quality degradation.</dd>
* <dt>1</dt><dd>VBR (default). The exact type of VBR is controlled by
* #OPUS_SET_VBR_CONSTRAINT.</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x)
/** Determine if variable bitrate (VBR) is enabled in the encoder.
* @see OPUS_SET_VBR
* @see OPUS_GET_VBR_CONSTRAINT
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>0</dt><dd>Hard CBR.</dd>
* <dt>1</dt><dd>VBR (default). The exact type of VBR may be retrieved via
* #OPUS_GET_VBR_CONSTRAINT.</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x)
/** Enables or disables constrained VBR in the encoder.
* This setting is ignored when the encoder is in CBR mode.
* @warning Only the MDCT mode of Opus currently heeds the constraint.
* Speech mode ignores it completely, hybrid mode may fail to obey it
* if the LPC layer uses more bitrate than the constraint would have
* permitted.
* @see OPUS_GET_VBR_CONSTRAINT
* @see OPUS_SET_VBR
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>0</dt><dd>Unconstrained VBR.</dd>
* <dt>1</dt><dd>Constrained VBR (default). This creates a maximum of one
* frame of buffering delay assuming a transport with a
* serialization speed of the nominal bitrate.</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x)
/** Determine if constrained VBR is enabled in the encoder.
* @see OPUS_SET_VBR_CONSTRAINT
* @see OPUS_GET_VBR
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>0</dt><dd>Unconstrained VBR.</dd>
* <dt>1</dt><dd>Constrained VBR (default).</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x)
/** Configures mono/stereo forcing in the encoder.
* This can force the encoder to produce packets encoded as either mono or
* stereo, regardless of the format of the input audio. This is useful when
* the caller knows that the input signal is currently a mono source embedded
* in a stereo stream.
* @see OPUS_GET_FORCE_CHANNELS
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>#OPUS_AUTO</dt><dd>Not forced (default)</dd>
* <dt>1</dt> <dd>Forced mono</dd>
* <dt>2</dt> <dd>Forced stereo</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x)
/** Gets the encoder's forced channel configuration.
* @see OPUS_SET_FORCE_CHANNELS
* @param[out] x <tt>opus_int32 *</tt>:
* <dl>
* <dt>#OPUS_AUTO</dt><dd>Not forced (default)</dd>
* <dt>1</dt> <dd>Forced mono</dd>
* <dt>2</dt> <dd>Forced stereo</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x)
/** Configures the maximum bandpass that the encoder will select automatically.
* Applications should normally use this instead of #OPUS_SET_BANDWIDTH
* (leaving that set to the default, #OPUS_AUTO). This allows the
* application to set an upper bound based on the type of input it is
* providing, but still gives the encoder the freedom to reduce the bandpass
* when the bitrate becomes too low, for better overall quality.
* @see OPUS_GET_MAX_BANDWIDTH
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
* <dt>OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
* <dt>OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
* <dt>OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
* <dt>OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband (default)</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x)
/** Gets the encoder's configured maximum allowed bandpass.
* @see OPUS_SET_MAX_BANDWIDTH
* @param[out] x <tt>opus_int32 *</tt>: Allowed values:
* <dl>
* <dt>#OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband (default)</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
/** Sets the encoder's bandpass to a specific value.
* This prevents the encoder from automatically selecting the bandpass based
* on the available bitrate. If an application knows the bandpass of the input
* audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH
* instead, which still gives the encoder the freedom to reduce the bandpass
* when the bitrate becomes too low, for better overall quality.
* @see OPUS_GET_BANDWIDTH
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
* <dt>#OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x)
/** Configures the type of signal being encoded.
* This is a hint which helps the encoder's mode selection.
* @see OPUS_GET_SIGNAL
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
* <dt>#OPUS_SIGNAL_VOICE</dt><dd>Bias thresholds towards choosing LPC or Hybrid modes.</dd>
* <dt>#OPUS_SIGNAL_MUSIC</dt><dd>Bias thresholds towards choosing MDCT modes.</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x)
/** Gets the encoder's configured signal type.
* @see OPUS_SET_SIGNAL
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
* <dt>#OPUS_SIGNAL_VOICE</dt><dd>Bias thresholds towards choosing LPC or Hybrid modes.</dd>
* <dt>#OPUS_SIGNAL_MUSIC</dt><dd>Bias thresholds towards choosing MDCT modes.</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x)
/** Configures the encoder's intended application.
* The initial value is a mandatory argument to the encoder_create function.
* @see OPUS_GET_APPLICATION
* @param[in] x <tt>opus_int32</tt>: Returns one of the following values:
* <dl>
* <dt>#OPUS_APPLICATION_VOIP</dt>
* <dd>Process signal for improved speech intelligibility.</dd>
* <dt>#OPUS_APPLICATION_AUDIO</dt>
* <dd>Favor faithfulness to the original input.</dd>
* <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
* <dd>Configure the minimum possible coding delay by disabling certain modes
* of operation.</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x)
/** Gets the encoder's configured application.
* @see OPUS_SET_APPLICATION
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>#OPUS_APPLICATION_VOIP</dt>
* <dd>Process signal for improved speech intelligibility.</dd>
* <dt>#OPUS_APPLICATION_AUDIO</dt>
* <dd>Favor faithfulness to the original input.</dd>
* <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
* <dd>Configure the minimum possible coding delay by disabling certain modes
* of operation.</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x)
/** Gets the total samples of delay added by the entire codec.
* This can be queried by the encoder and then the provided number of samples can be
* skipped on from the start of the decoder's output to provide time aligned input
* and output. From the perspective of a decoding application the real data begins this many
* samples late.
*
* The decoder contribution to this delay is identical for all decoders, but the
* encoder portion of the delay may vary from implementation to implementation,
* version to version, or even depend on the encoder's initial configuration.
* Applications needing delay compensation should call this CTL rather than
* hard-coding a value.
* @param[out] x <tt>opus_int32 *</tt>: Number of lookahead samples
* @hideinitializer */
#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x)
/** Configures the encoder's use of inband forward error correction (FEC).
* @note This is only applicable to the LPC layer
* @see OPUS_GET_INBAND_FEC
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>0</dt><dd>Disable inband FEC (default).</dd>
* <dt>1</dt><dd>Enable inband FEC.</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
/** Gets encoder's configured use of inband forward error correction.
* @see OPUS_SET_INBAND_FEC
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>0</dt><dd>Inband FEC disabled (default).</dd>
* <dt>1</dt><dd>Inband FEC enabled.</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)
/** Configures the encoder's expected packet loss percentage.
* Higher values trigger progressively more loss resistant behavior in the encoder
* at the expense of quality at a given bitrate in the absence of packet loss, but
* greater quality under loss.
* @see OPUS_GET_PACKET_LOSS_PERC
* @param[in] x <tt>opus_int32</tt>: Loss percentage in the range 0-100, inclusive (default: 0).
* @hideinitializer */
#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x)
/** Gets the encoder's configured packet loss percentage.
* @see OPUS_SET_PACKET_LOSS_PERC
* @param[out] x <tt>opus_int32 *</tt>: Returns the configured loss percentage
* in the range 0-100, inclusive (default: 0).
* @hideinitializer */
#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x)
/** Configures the encoder's use of discontinuous transmission (DTX).
* @note This is only applicable to the LPC layer
* @see OPUS_GET_DTX
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>0</dt><dd>Disable DTX (default).</dd>
* <dt>1</dt><dd>Enabled DTX.</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x)
/** Gets encoder's configured use of discontinuous transmission.
* @see OPUS_SET_DTX
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>0</dt><dd>DTX disabled (default).</dd>
* <dt>1</dt><dd>DTX enabled.</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x)
/** Configures the depth of signal being encoded.
*
* This is a hint which helps the encoder identify silence and near-silence.
* It represents the number of significant bits of linear intensity below
* which the signal contains ignorable quantization or other noise.
*
* For example, OPUS_SET_LSB_DEPTH(14) would be an appropriate setting
* for G.711 u-law input. OPUS_SET_LSB_DEPTH(16) would be appropriate
* for 16-bit linear pcm input with opus_encode_float().
*
* When using opus_encode() instead of opus_encode_float(), or when libopus
* is compiled for fixed-point, the encoder uses the minimum of the value
* set here and the value 16.
*
* @see OPUS_GET_LSB_DEPTH
* @param[in] x <tt>opus_int32</tt>: Input precision in bits, between 8 and 24
* (default: 24).
* @hideinitializer */
#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x)
/** Gets the encoder's configured signal depth.
* @see OPUS_SET_LSB_DEPTH
* @param[out] x <tt>opus_int32 *</tt>: Input precision in bits, between 8 and
* 24 (default: 24).
* @hideinitializer */
#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x)
/** Configures the encoder's use of variable duration frames.
* When variable duration is enabled, the encoder is free to use a shorter frame
* size than the one requested in the opus_encode*() call.
* It is then the user's responsibility
* to verify how much audio was encoded by checking the ToC byte of the encoded
* packet. The part of the audio that was not encoded needs to be resent to the
* encoder for the next call. Do not use this option unless you <b>really</b>
* know what you are doing.
* @see OPUS_GET_EXPERT_FRAME_DURATION
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>
* <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 5 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_80_MS</dt><dd>Use 80 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_100_MS</dt><dd>Use 100 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_120_MS</dt><dd>Use 120 ms frames.</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x)
/** Gets the encoder's configured use of variable duration frames.
* @see OPUS_SET_EXPERT_FRAME_DURATION
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>
* <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 5 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_80_MS</dt><dd>Use 80 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_100_MS</dt><dd>Use 100 ms frames.</dd>
* <dt>OPUS_FRAMESIZE_120_MS</dt><dd>Use 120 ms frames.</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x)
/** If set to 1, disables almost all use of prediction, making frames almost
* completely independent. This reduces quality.
* @see OPUS_GET_PREDICTION_DISABLED
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>0</dt><dd>Enable prediction (default).</dd>
* <dt>1</dt><dd>Disable prediction.</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x)
/** Gets the encoder's configured prediction status.
* @see OPUS_SET_PREDICTION_DISABLED
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>0</dt><dd>Prediction enabled (default).</dd>
* <dt>1</dt><dd>Prediction disabled.</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)
/**@}*/
/** @defgroup opus_genericctls Generic CTLs
*
* These macros are used with the \c opus_decoder_ctl and
* \c opus_encoder_ctl calls to generate a particular
* request.
*
* When called on an \c OpusDecoder they apply to that
* particular decoder instance. When called on an
* \c OpusEncoder they apply to the corresponding setting
* on that encoder instance, if present.
*
* Some usage examples:
*
* @code
* int ret;
* opus_int32 pitch;
* ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch));
* if (ret == OPUS_OK) return ret;
*
* opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);
* opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE);
*
* opus_int32 enc_bw, dec_bw;
* opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw));
* opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw));
* if (enc_bw != dec_bw) {
* printf("packet bandwidth mismatch!\n");
* }
* @endcode
*
* @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls
* @{
*/
/** Resets the codec state to be equivalent to a freshly initialized state.
* This should be called when switching streams in order to prevent
* the back to back decoding from giving different results from
* one at a time decoding.
* @hideinitializer */
#define OPUS_RESET_STATE 4028
/** Gets the final state of the codec's entropy coder.
* This is used for testing purposes,
* The encoder and decoder state should be identical after coding a payload
* (assuming no data corruption or software bugs)
*
* @param[out] x <tt>opus_uint32 *</tt>: Entropy coder state
*
* @hideinitializer */
#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x)
/** Gets the encoder's configured bandpass or the decoder's last bandpass.
* @see OPUS_SET_BANDWIDTH
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
* <dt>#OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
* <dt>#OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
/** Gets the sampling rate the encoder or decoder was initialized with.
* This simply returns the <code>Fs</code> value passed to opus_encoder_init()
* or opus_decoder_init().
* @param[out] x <tt>opus_int32 *</tt>: Sampling rate of encoder or decoder.
* @hideinitializer
*/
#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
/** If set to 1, disables the use of phase inversion for intensity stereo,
* improving the quality of mono downmixes, but slightly reducing normal
* stereo quality. Disabling phase inversion in the decoder does not comply
* with RFC 6716, although it does not cause any interoperability issue and
* is expected to become part of the Opus standard once RFC 6716 is updated
* by draft-ietf-codec-opus-update.
* @see OPUS_GET_PHASE_INVERSION_DISABLED
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>0</dt><dd>Enable phase inversion (default).</dd>
* <dt>1</dt><dd>Disable phase inversion.</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_PHASE_INVERSION_DISABLED(x) OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int(x)
/** Gets the encoder's configured phase inversion status.
* @see OPUS_SET_PHASE_INVERSION_DISABLED
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>0</dt><dd>Stereo phase inversion enabled (default).</dd>
* <dt>1</dt><dd>Stereo phase inversion disabled.</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x)
/** Gets the DTX state of the encoder.
* Returns whether the last encoded frame was either a comfort noise update
* during DTX or not encoded because of DTX.
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
* <dl>
* <dt>0</dt><dd>The encoder is not in DTX.</dd>
* <dt>1</dt><dd>The encoder is in DTX.</dd>
* </dl>
* @hideinitializer */
#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x)
/**@}*/
/** @defgroup opus_decoderctls Decoder related CTLs
* @see opus_genericctls, opus_encoderctls, opus_decoder
* @{
*/
/** Configures decoder gain adjustment.
* Scales the decoded output by a factor specified in Q8 dB units.
* This has a maximum range of -32768 to 32767 inclusive, and returns
* OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment.
* This setting survives decoder reset.
*
* gain = pow(10, x/(20.0*256))
*
* @param[in] x <tt>opus_int32</tt>: Amount to scale PCM signal by in Q8 dB units.
* @hideinitializer */
#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x)
/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN
*
* @param[out] x <tt>opus_int32 *</tt>: Amount to scale PCM signal by in Q8 dB units.
* @hideinitializer */
#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x)
/** Gets the duration (in samples) of the last packet successfully decoded or concealed.
* @param[out] x <tt>opus_int32 *</tt>: Number of samples (at current sampling rate).
* @hideinitializer */
#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x)
/** Gets the pitch of the last decoded frame, if available.
* This can be used for any post-processing algorithm requiring the use of pitch,
* e.g. time stretching/shortening. If the last frame was not voiced, or if the
* pitch was not coded in the frame, then zero is returned.
*
* This CTL is only implemented for decoder instances.
*
* @param[out] x <tt>opus_int32 *</tt>: pitch period at 48 kHz (or 0 if not available)
*
* @hideinitializer */
#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x)
/**@}*/
/** @defgroup opus_libinfo Opus library information functions
* @{
*/
/** Converts an opus error code into a human readable string.
*
* @param[in] error <tt>int</tt>: Error number
* @returns Error string
*/
OPUS_EXPORT const char *opus_strerror(int error);
/** Gets the libopus version string.
*
* Applications may look for the substring "-fixed" in the version string to
* determine whether they have a fixed-point or floating-point build at
* runtime.
*
* @returns Version string
*/
OPUS_EXPORT const char *opus_get_version_string(void);
/**@}*/
#ifdef __cplusplus
}
#endif
#endif /* OPUS_DEFINES_H */

166
hsmodem/opus_types.h Executable file
View File

@ -0,0 +1,166 @@
/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */
/* Modified by Jean-Marc Valin */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* opus_types.h based on ogg_types.h from libogg */
/**
@file opus_types.h
@brief Opus reference implementation types
*/
#ifndef OPUS_TYPES_H
#define OPUS_TYPES_H
#define opus_int int /* used for counters etc; at least 16 bits */
#define opus_int64 long long
#define opus_int8 signed char
#define opus_uint unsigned int /* used for counters etc; at least 16 bits */
#define opus_uint64 unsigned long long
#define opus_uint8 unsigned char
/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */
#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H))
#include <stdint.h>
# undef opus_int64
# undef opus_int8
# undef opus_uint64
# undef opus_uint8
typedef int8_t opus_int8;
typedef uint8_t opus_uint8;
typedef int16_t opus_int16;
typedef uint16_t opus_uint16;
typedef int32_t opus_int32;
typedef uint32_t opus_uint32;
typedef int64_t opus_int64;
typedef uint64_t opus_uint64;
#elif defined(_WIN32)
# if defined(__CYGWIN__)
# include <_G_config.h>
typedef _G_int32_t opus_int32;
typedef _G_uint32_t opus_uint32;
typedef _G_int16 opus_int16;
typedef _G_uint16 opus_uint16;
# elif defined(__MINGW32__)
typedef short opus_int16;
typedef unsigned short opus_uint16;
typedef int opus_int32;
typedef unsigned int opus_uint32;
# elif defined(__MWERKS__)
typedef int opus_int32;
typedef unsigned int opus_uint32;
typedef short opus_int16;
typedef unsigned short opus_uint16;
# else
/* MSVC/Borland */
typedef __int32 opus_int32;
typedef unsigned __int32 opus_uint32;
typedef __int16 opus_int16;
typedef unsigned __int16 opus_uint16;
# endif
#elif defined(__MACOS__)
# include <sys/types.h>
typedef SInt16 opus_int16;
typedef UInt16 opus_uint16;
typedef SInt32 opus_int32;
typedef UInt32 opus_uint32;
#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
# include <sys/types.h>
typedef int16_t opus_int16;
typedef u_int16_t opus_uint16;
typedef int32_t opus_int32;
typedef u_int32_t opus_uint32;
#elif defined(__BEOS__)
/* Be */
# include <inttypes.h>
typedef int16 opus_int16;
typedef u_int16 opus_uint16;
typedef int32_t opus_int32;
typedef u_int32_t opus_uint32;
#elif defined (__EMX__)
/* OS/2 GCC */
typedef short opus_int16;
typedef unsigned short opus_uint16;
typedef int opus_int32;
typedef unsigned int opus_uint32;
#elif defined (DJGPP)
/* DJGPP */
typedef short opus_int16;
typedef unsigned short opus_uint16;
typedef int opus_int32;
typedef unsigned int opus_uint32;
#elif defined(R5900)
/* PS2 EE */
typedef int opus_int32;
typedef unsigned opus_uint32;
typedef short opus_int16;
typedef unsigned short opus_uint16;
#elif defined(__SYMBIAN32__)
/* Symbian GCC */
typedef signed short opus_int16;
typedef unsigned short opus_uint16;
typedef signed int opus_int32;
typedef unsigned int opus_uint32;
#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
typedef short opus_int16;
typedef unsigned short opus_uint16;
typedef long opus_int32;
typedef unsigned long opus_uint32;
#elif defined(CONFIG_TI_C6X)
typedef short opus_int16;
typedef unsigned short opus_uint16;
typedef int opus_int32;
typedef unsigned int opus_uint32;
#else
/* Give up, take a reasonable guess */
typedef short opus_int16;
typedef unsigned short opus_uint16;
typedef int opus_int32;
typedef unsigned int opus_uint32;
#endif
#endif /* OPUS_TYPES_H */

View File

@ -26,7 +26,7 @@
int speed = 0;
#define MAXSPDARR 5
#define MAXSPDARR 50
int spdarr[MAXSPDARR];
int spdarrbps[MAXSPDARR];
@ -82,12 +82,12 @@ static int f=1;
int meanvalbps(int v)
{
static int f = 1;
static int f = 5;
if (f)
{
f--;
for (int i = 0; i < MAXSPDARR; i++) spdarrbps[i] = -1;
f = 0;
}
for (int i = (MAXSPDARR - 1); i > 0; i--)

37
hsmodem/version.h Normal file
View File

@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------*\
FILE........: version.h
AUTHOR......: Tomas Härdin
DATE CREATED: 03 November 2017
Codec 2 VERSION #defines
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2017 Tomas Härdin
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. 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 Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
//this functions both as an include guard and your typical HAVE macro
#ifndef CODEC2_HAVE_VERSION
#define CODEC2_HAVE_VERSION
#define CODEC2_VERSION_MAJOR 0
#define CODEC2_VERSION_MINOR 9
#define CODEC2_VERSION_PATCH 2
#define CODEC2_VERSION "0.9.2"
#endif //CODEC2_HAVE_VERSION

252
hsmodem/voiceprocessor.cpp Executable file
View File

@ -0,0 +1,252 @@
/*
* 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.
*
* voiceprocessor.c ... function to handle voice transfer
*
*/
#include "hsmodem.h"
int opusbitrate = 0;
void sendCodecToModulator(uint8_t* pdata, int len);
OpusEncoder* opusenc = (OpusEncoder*)NULL;
OpusDecoder* opusdec = (OpusDecoder*)NULL;
void init_voiceproc()
{
if (codec == 1)
{
init_codec2();
return;
}
if (opusbitrate == 0)
{
printf("Codec bitrate not set\n");
return;
}
close_voiceproc();
if (VoiceAudioMode == VOICEMODE_CODECLOOP || VoiceAudioMode == VOICEMODE_DV_FULLDUPLEX || VoiceAudioMode == VOICEMODE_DV_RXONLY)
{
int err;
opusenc = opus_encoder_create(VOICE_SAMPRATE, 1, OPUS_APPLICATION_VOIP, &err);
if (opusenc == (OpusEncoder*)NULL || err != OPUS_OK)
{
printf("opus_encoder_create failed\n");
return;
}
opus_encoder_ctl(opusenc, OPUS_SET_BITRATE(opusbitrate));
printf("set opus rate: %d\n", opusbitrate);
opus_encoder_ctl(opusenc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
opus_encoder_ctl(opusenc, OPUS_SET_VBR(0)); // hard-CBR
opus_encoder_ctl(opusenc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
opusdec = opus_decoder_create(VOICE_SAMPRATE, 1 , &err);
if (opusdec == (OpusDecoder*)NULL || err != OPUS_OK)
{
printf("opus_encoder_create failed\n");
return;
}
}
}
void close_voiceproc()
{
if(opusenc != (OpusEncoder*)NULL)
opus_encoder_destroy(opusenc);
opusenc = (OpusEncoder*)NULL;
if (opusdec != (OpusDecoder*)NULL)
opus_decoder_destroy(opusdec);
opusdec = (OpusDecoder*)NULL;
}
#define ENC_FRAMESIZE 2880
void encode(float f)
{
if (codec == 1)
{
encode_codec2(f);
return;
}
if (opusenc == (OpusEncoder*)NULL) return;
static float farr[ENC_FRAMESIZE];
static int farridx = 0;
uint8_t opusdata[10000];
// collect samples until we have ENC_FRAMESIZE
farr[farridx] = f;
if (++farridx == ENC_FRAMESIZE)
{
opus_int32 ret = opus_encode_float(opusenc, farr, farridx, opusdata, opusbitrate);
if (ret < 0)
{
printf("opus_encode_float error: %d", ret);
}
// length of an OPUS packet:
// duration[ms] * OutSampRate[kbps] / 8
// line speed 7200: sample rate=6, PacketSize = (ENC_FRAMESIZE*1000/48000) * 6 / 8 = (ENC_FRAMESIZE/48)*6/8 = 45
//measure_speed_bps(ret*8);
//showbytestring("ENC:", opusdata, ret, ret);
// send Codec data to modulator
if (VoiceAudioMode == VOICEMODE_DV_FULLDUPLEX)
{
memmove(opusdata + 1, opusdata, ret);
opusdata[0] = 0xff; // start of opus packet marker
sendCodecToModulator(opusdata, ret+1);
}
// decode and send samples to loadspeaker
if (VoiceAudioMode == VOICEMODE_CODECLOOP)
{
static float fresult[ENC_FRAMESIZE];
int r = opus_decode_float(opusdec, opusdata, ret, fresult, ENC_FRAMESIZE, 0);
if (r < 0)
{
printf("opus_decode_float error: %d", r);
}
for (int i = 0; i < r; i++)
pb_write_fifo_voice(fresult[i]);
}
farridx = 0;
}
}
// void toGR_sendData(uint8_t* data, int type, int status)
// this function expects "data" with length: payloadlen
// so we have to collect samples until one payload is filled
// this may take too long, in this case send the frame immediately
// the first byte in the payload is the marker 0xff
// type=6 ... voice payload
// minfo=1 ... voice data available
// minfo=0 ... filler payload, just ignore
void sendCodecToModulator(uint8_t *pdata, int len)
{
static uint8_t payload[PAYLOADLEN];
static int vdidx = 0;
// fill the new voice data "pdata" into the buffer "voicedata"
for (int i = 0; i < len; i++)
{
if (vdidx >= PAYLOADLEN) printf("vdidx too high: %d", vdidx);
payload[vdidx++] = pdata[i];
// if the voicedata buffer is full, send it to the modem
if (vdidx == PAYLOADLEN)
{
vdidx = 0;
toGR_sendData(payload, 6, 1); // 6 ... voice data, 1 ... valid voice data
}
while (1)
{
// we have to check if the TX fifo has enough data. In case of an underrun the Q(8A)PSK signal will be distorted
int us = pb_fifo_usedspace();
if (us < 20000)
{
//printf("tx filler\n");
// not enough samples in the TX buffer
// send a dummy frame, a frame with 0 voice data
uint8_t dummy[PAYLOADLEN];
memset(dummy, 0, PAYLOADLEN);
toGR_sendData(dummy, 6, 0);
}
else
break;
}
}
}
// we get the received data stream with length: PAYLOADLEN
// find opus packets marked with 0xff and a length of opusPacketSize
// send send these chunks to the codec_decoder
#define CHUNKSIZE 200
void toCodecDecoder(uint8_t *pdata, int len)
{
if (codec == 1)
{
toCodecDecoder_codec2(pdata, len);
return;
}
static uint8_t chunk[CHUNKSIZE];
int opusPacketSize = ((ENC_FRAMESIZE / 48) * (opusbitrate/100)) / 80;
if (opusPacketSize > 45)
{
printf("wrong opusPacketSize: %d\n", opusPacketSize);
return;
}
// 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 - 1; i++)
chunk[i] = chunk[i + 1];
chunk[CHUNKSIZE - 1] = pdata[vd];
// an OPUS packet has max length of 45 Byte.
// in the chunk size of 200 fit minimum 4 chunks
// so lets test if 4 chunks are there, by looking for the marker
// at distance opusPacketSize
int mfound = 1;
for (int m = 0; m < 4; m++)
{
if (chunk[(opusPacketSize+1) * m] != 0xff)
{
mfound = 0;
break;
}
}
if (mfound)
{
//showbytestring("OPUS:", chunk + 1, opusPacketSize, opusPacketSize);
static float fresult[ENC_FRAMESIZE];
int r = opus_decode_float(opusdec, chunk + 1, opusPacketSize, fresult, ENC_FRAMESIZE, 0);
if (r < 0)
{
printf("opus_decode_float error: %d\n", r);
}
else
{
//measure_speed_bps(r);
for (int j = 0; j < r; j++)
pb_write_fifo_voice(fresult[j]);
}
}
}
}

View File

@ -176,8 +176,9 @@ namespace oscardata
{
// send as the last frame
Array.Copy(txdata, txpos, txarr, 0, restlen); // unused byte will be 0
txudp(txarr, txtype, statics.LastFrame);
txudp(txarr, txtype, statics.LastFrame);
// send the last frame a couple of times
for(int i=0; i<10; i++)
txudp(txarr, txtype, statics.LastFrame);
setSending(false); // transmission complete
}
else

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@ using System.Text;
using System.IO;
using System.Drawing.Drawing2D;
using System.Diagnostics;
using System.Threading;
namespace oscardata
{
@ -42,6 +43,8 @@ namespace oscardata
String old_tsip = "";
bool modemrunning = false;
receivefile recfile = new receivefile();
int last_initAudioStatus;
int last_initVoiceStatus;
public Form1()
{
@ -60,6 +63,8 @@ namespace oscardata
else
statics.ostype = 1; // Linux
statics.CreateAllDirs();
// set temp paths
statics.zip_TXtempfilename = statics.addTmpPath(statics.zip_TXtempfilename);
statics.zip_RXtempfilename = statics.addTmpPath(statics.zip_RXtempfilename);
@ -192,19 +197,42 @@ namespace oscardata
{
statics.GotAudioDevices = 2;
// populate combo boxes
cb_audioPB.BeginUpdate();
cb_audioPB.Items.Clear();
cb_loudspeaker.BeginUpdate();
cb_loudspeaker.Items.Clear();
foreach (String s in statics.AudioPBdevs)
{
if(s.Length > 1)
if (s.Length > 1)
{
cb_audioPB.Items.Add(s);
cb_loudspeaker.Items.Add(s);
}
}
cb_loudspeaker.EndUpdate();
cb_audioPB.EndUpdate();
// check if displayed text is available in the item list
findDevice(cb_loudspeaker);
findDevice(cb_audioPB);
cb_audioCAP.BeginUpdate();
cb_audioCAP.Items.Clear();
cb_mic.BeginUpdate();
cb_mic.Items.Clear();
foreach (String s in statics.AudioCAPdevs)
{
if (s.Length > 1)
{
cb_audioCAP.Items.Add(s);
cb_mic.Items.Add(s);
}
}
cb_mic.EndUpdate();
cb_audioCAP.EndUpdate();
findDevice(cb_mic);
findDevice(cb_audioCAP);
}
if (setPBvolume >= 0)
{
Byte[] txdata = new byte[2];
@ -222,15 +250,124 @@ namespace oscardata
Udp.UdpSendCtrl(txdata);
setCAPvolume = -1;
}
if (setLSvolume >= 0)
{
Byte[] txdata = new byte[2];
txdata[0] = (Byte)statics.SetLSvolume;
txdata[1] = (Byte)setLSvolume;
Udp.UdpSendCtrl(txdata);
setLSvolume = -1;
}
if (setMICvolume != -1)
{
Byte[] txdata = new byte[2];
txdata[0] = (Byte)statics.SetMICvolume;
txdata[1] = (Byte)setMICvolume;
Udp.UdpSendCtrl(txdata);
setMICvolume = -1;
}
if (last_initAudioStatus != statics.initAudioStatus)
{
if ((statics.initAudioStatus & 1) == 1)
pb_audioPBstatus.BackgroundImage = Properties.Resources.fail;
else
pb_audioPBstatus.BackgroundImage = Properties.Resources.ok;
if ((statics.initAudioStatus & 2) == 2)
pb_audioCAPstatus.BackgroundImage = Properties.Resources.fail;
else
pb_audioCAPstatus.BackgroundImage = Properties.Resources.ok;
last_initAudioStatus = statics.initAudioStatus;
}
if (last_initVoiceStatus != statics.initVoiceStatus)
{
if ((statics.initVoiceStatus & 1) == 1)
pb_voicePBstatus.BackgroundImage = Properties.Resources.fail;
else
pb_voicePBstatus.BackgroundImage = Properties.Resources.ok;
if ((statics.initVoiceStatus & 2) == 2)
pb_voiceCAPstatus.BackgroundImage = Properties.Resources.fail;
else
pb_voiceCAPstatus.BackgroundImage = Properties.Resources.ok;
last_initVoiceStatus = statics.initVoiceStatus;
}
}
// correct entries in the Audio Device Comboboxes if Devices have changed
void findDevice(ComboBox cb)
{
int pos = -1;
if (cb.Text.Length >= 4)
{
// Device Name starts at Index 3 in the string
String dn = cb.Text.Substring(3);
int anz = cb.Items.Count;
for (int i = 0; i < anz; i++)
{
String name = cb.Items[i].ToString();
name = name.Substring(3);
if (dn == name)
{
pos = i;
break;
}
}
}
if (pos == -1)
{
// not available, reset to first item which usually is Default
if (cb.Items.Count == 0)
cb.Text = "no sound devices available";
else
cb.Text = cb.Items[0].ToString();
}
else
cb.Text = cb.Items[pos].ToString();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
save_Setup();
if (cb_autostart.Checked)
{
statics.killall("hsmodem");
statics.killall("hsmodem.exe");
// tell hsmodem to terminate itself
Byte[] txdata = new byte[1];
txdata[0] = (Byte)statics.terminate;
Udp.UdpSendCtrl(txdata);
Thread.Sleep(250);
if (statics.ostype == 0)
{
int to = 0;
while(statics.isProcRunning("hsmodem.exe"))
{
Thread.Sleep(250);
// tell hsmodem to terminate itself
Udp.UdpSendCtrl(txdata);
if (++to >= 10) break; // give up after 2,5s
}
if (to >= 10)
statics.killall("hsmodem.exe");
}
else
{
Thread.Sleep(250);
statics.killall("hsmodem");
}
}
// exit the threads
statics.running = false;
@ -264,13 +401,6 @@ namespace oscardata
rxbytecounter += statics.UdpBlocklen;
trackBar_maxlevel.Value = maxlevel;
int v1 = 255;
int v2 = 220;
if (maxlevel < 20 || maxlevel > 70) trackBar_maxlevel.BackColor = Color.FromArgb(v1,v2,v2);
else if (maxlevel < 30 || maxlevel > 60) trackBar_maxlevel.BackColor = Color.FromArgb(v1, v1, v2);
else trackBar_maxlevel.BackColor = Color.FromArgb(v2, v1, v2);
Byte[] rxdata = new byte[rxd.Length - 10];
Array.Copy(rxd, 10, rxdata, 0, rxd.Length - 10);
@ -334,6 +464,10 @@ namespace oscardata
printText(rtb_RXfile, "transmission speed: " + ((int)(recfile.filesize * 8 / recfile.runtime.TotalSeconds)).ToString() + " bit/s" + "\r\n\r\n");
printText(rtb_RXfile, "file size : " + recfile.filesize + " byte\r\n\r\n");
printText(rtb_RXfile, "file name : " + recfile.filename + "\r\n\r\n");
if(recfile.filename.Length <= 1)
{
printText(rtb_RXfile, "file status : not complete, retransmit\r\n\r\n");
}
}
}
@ -378,6 +512,11 @@ namespace oscardata
if (statics.PBfifousage < progressBar_fifo.Minimum) progressBar_fifo.Value = progressBar_fifo.Minimum;
else if (statics.PBfifousage >= progressBar_fifo.Maximum) progressBar_fifo.Value = progressBar_fifo.Maximum-1;
else progressBar_fifo.Value = statics.PBfifousage;
progressBar_capfifo.Invalidate();
if (statics.CAPfifousage < progressBar_capfifo.Minimum) progressBar_capfifo.Value = progressBar_capfifo.Minimum;
else if (statics.CAPfifousage >= progressBar_capfifo.Maximum) progressBar_capfifo.Value = progressBar_capfifo.Maximum - 1;
else progressBar_capfifo.Value = statics.CAPfifousage;
}
private void panel_constel_Paint(object sender, PaintEventArgs e)
@ -877,14 +1016,18 @@ namespace oscardata
label_txfile.Location = new Point(rtb_TXfile.Location.X, ly);
label_rxfile.Location = new Point(rtb_RXfile.Location.X, ly);
trackBar_maxlevel.Location = new Point(panel_txspectrum.Location.X + panel_txspectrum.Size.Width + 5, panel_txspectrum.Location.Y);
trackBar_maxlevel.Size = new Size(20, panel_txspectrum.Size.Height);
label_speed.Location = new Point(trackBar_maxlevel.Location.X + trackBar_maxlevel.Size.Width + 15,panel_txspectrum.Location.Y+10);
label_speed.Location = new Point(panel_txspectrum.Location.X + panel_txspectrum.Size.Width + 15,panel_txspectrum.Location.Y+10);
cb_speed.Location = new Point(label_speed.Location.X + label_speed.Size.Width + 10, label_speed.Location.Y-5);
label_fifo.Location = new Point(label_speed.Location.X, label_speed.Location.Y + 35);
progressBar_fifo.Location = new Point(cb_speed.Location.X, cb_speed.Location.Y + 35);
int y = 26;
label_fifo.Location = new Point(label_speed.Location.X, label_speed.Location.Y + y);
progressBar_fifo.Location = new Point(cb_speed.Location.X, cb_speed.Location.Y + y+5);
progressBar_fifo.Size = new Size(progressBar_fifo.Width, 18);
y = 20;
label_capfifo.Location = new Point(label_fifo.Location.X, label_fifo.Location.Y + y);
progressBar_capfifo.Location = new Point(progressBar_fifo.Location.X, progressBar_fifo.Location.Y + y);
progressBar_capfifo.Size = new Size(progressBar_capfifo.Width, 18);
}
public String GetMyBroadcastIP()
@ -923,6 +1066,24 @@ namespace oscardata
return x;
}
Byte getLSaudioDevice()
{
String s = cb_loudspeaker.Text;
Byte x = (Byte)cb_loudspeaker.Items.IndexOf(s);
Console.WriteLine("LS:" + s + " " + x);
//if (s.ToUpper() == "DEFAULT") x = 255;
return x;
}
Byte getMICaudioDevice()
{
String s = cb_mic.Text;
Byte x = (Byte)cb_mic.Items.IndexOf(s);
Console.WriteLine("MIC:" + s + " " + x);
//if (s.ToUpper() == "DEFAULT") x = 255;
return x;
}
/*
* search for the modem IP:
* send a search message via UDP to port UdpBCport
@ -933,13 +1094,15 @@ namespace oscardata
private void search_modem()
{
Byte[] txb = new byte[6];
Byte[] txb = new byte[8];
txb[0] = 0x3c; // ID of this message
txb[1] = getPBaudioDevice();
txb[2] = getCAPaudioDevice();
txb[3] = (Byte)tb_PBvol.Value;
txb[4] = (Byte)tb_CAPvol.Value;
txb[5] = (Byte)cb_announcement.Items.IndexOf(cb_announcement.Text);
txb[6] = (Byte)tb_loadspeaker.Value;
txb[7] = (Byte)tb_mic.Value;
Udp.UdpBCsend(txb, GetMyBroadcastIP(), statics.UdpBCport_AppToModem);
@ -1128,6 +1291,17 @@ namespace oscardata
s = ReadString(sr);
try { cb_stampinfo.Checked = (s == "1"); } catch { }
try { tb_info.Text = ReadString(sr); } catch { }
try { cb_loudspeaker.Text = ReadString(sr); } catch { }
try { cb_mic.Text = ReadString(sr); } catch { }
try { tb_loadspeaker.Value = ReadInt(sr); } catch { }
try { tb_mic.Value = ReadInt(sr); } catch { }
try
{
s = ReadString(sr);
rb_opus.Checked = (s == "1");
rb_codec2.Checked = (s != "1");
}
catch { }
}
}
catch
@ -1158,6 +1332,11 @@ namespace oscardata
sw.WriteLine(cb_announcement.Text);
sw.WriteLine(cb_stampinfo.Checked ? "1" : "0");
sw.WriteLine(tb_info.Text);
sw.WriteLine(cb_loudspeaker.Text);
sw.WriteLine(cb_mic.Text);
sw.WriteLine(tb_loadspeaker.Value.ToString());
sw.WriteLine(tb_mic.Value.ToString());
sw.WriteLine(rb_opus.Checked ? "1" : "0");
}
}
catch { }
@ -1208,5 +1387,137 @@ namespace oscardata
{
setCAPvolume = tb_CAPvol.Value;
}
private void bt_blockinfo_Click(object sender, EventArgs e)
{
String s;
int[] d = new int[2];
recfile.oldblockinfo(d);
int failed = d[0] - d[1];
s = "Received Blocks\n" +
"---------------\n" +
"total : " + d[0] + "\n" +
"good : " + d[1] + "\n" +
"failed: " + failed + "\n";
if(failed > 1)
{
s += "\nfile incomplete, ask for retransmission";
}
Form2_showtext sf = new Form2_showtext("Block Info",s);
sf.ShowDialog();
}
void setVoiceAudio()
{
Byte[] txdata = new byte[5];
txdata[0] = (Byte)statics.SetVoiceMode;
txdata[1] = (Byte)getLSaudioDevice();
txdata[2] = (Byte)getMICaudioDevice();
Byte opmode = 0;
// values see: hsmodem.h _VOICEMODES_
if (cb_switchtoLS.Checked) opmode = 1;
if (cb_voiceloop.Checked) opmode = 2;
if (cb_codecloop.Checked) opmode = 3;
if (cb_digitalVoice.Checked) opmode = 4;
if (cb_digitalVoiceRXonly.Checked) opmode = 5;
if(opmode == 0) pb_voice.BackgroundImage = null;
txdata[3] = opmode;
Byte codec;
if (rb_opus.Checked) codec = 0;
else codec = 1;
txdata[4] = codec;
Udp.UdpSendCtrl(txdata);
if(opmode > 0)
{
rb_opus.Enabled = false;
rb_codec2.Enabled = false;
}
else
{
rb_opus.Enabled = true;
rb_codec2.Enabled = true;
}
}
private void cb_switchtoLS_CheckedChanged(object sender, EventArgs e)
{
if(cb_switchtoLS.Checked)
{
cb_voiceloop.Checked = false;
cb_codecloop.Checked = false;
cb_digitalVoice.Checked = false;
cb_digitalVoiceRXonly.Checked = false;
pb_voice.BackgroundImage = Properties.Resources.cdc_digital;
}
setVoiceAudio();
}
private void cb_voiceloop_CheckedChanged(object sender, EventArgs e)
{
if (cb_voiceloop.Checked)
{
cb_switchtoLS.Checked = false;
cb_codecloop.Checked = false;
cb_digitalVoice.Checked = false;
cb_digitalVoiceRXonly.Checked = false;
pb_voice.BackgroundImage = Properties.Resources.cdc_intloop;
}
setVoiceAudio();
}
private void cb_codecloop_CheckedChanged(object sender, EventArgs e)
{
if (cb_codecloop.Checked)
{
cb_switchtoLS.Checked = false;
cb_voiceloop.Checked = false;
cb_digitalVoice.Checked = false;
cb_digitalVoiceRXonly.Checked = false;
pb_voice.BackgroundImage = Properties.Resources.cdc_codecloop;
}
setVoiceAudio();
}
private void cb_digitalVoice_CheckedChanged(object sender, EventArgs e)
{
if (cb_digitalVoice.Checked)
{
cb_switchtoLS.Checked = false;
cb_voiceloop.Checked = false;
cb_codecloop.Checked = false;
cb_digitalVoiceRXonly.Checked = false;
pb_voice.BackgroundImage = Properties.Resources.cdc_dv;
}
setVoiceAudio();
}
private void cb_digitalVoiceRXonly_CheckedChanged(object sender, EventArgs e)
{
if (cb_digitalVoiceRXonly.Checked)
{
cb_switchtoLS.Checked = false;
cb_voiceloop.Checked = false;
cb_codecloop.Checked = false;
cb_digitalVoice.Checked = false;
pb_voice.BackgroundImage = Properties.Resources.cdc_dvrx;
}
setVoiceAudio();
}
int setLSvolume = -1;
int setMICvolume = -1;
private void tb_loadspeaker_Scroll(object sender, EventArgs e)
{
setLSvolume = tb_loadspeaker.Value;
}
private void tb_mic_Scroll(object sender, EventArgs e)
{
setMICvolume = tb_mic.Value;
}
}
}

View File

@ -129,6 +129,158 @@
<metadata name="timer_qpsk.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>371, 17</value>
</metadata>
<metadata name="imageList1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>644, 17</value>
</metadata>
<data name="imageList1.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABw
FwAAAk1TRnQBSQFMAgEBDQEAAbABAAGwAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
AwABQAMAAUADAAEBAQABCAYAARAYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
AWYDAAGZAwABzAIAATMDAAIzAgABMwFmAgABMwGZAgABMwHMAgABMwH/AgABZgMAAWYBMwIAAmYCAAFm
AZkCAAFmAcwCAAFmAf8CAAGZAwABmQEzAgABmQFmAgACmQIAAZkBzAIAAZkB/wIAAcwDAAHMATMCAAHM
AWYCAAHMAZkCAALMAgABzAH/AgAB/wFmAgAB/wGZAgAB/wHMAQABMwH/AgAB/wEAATMBAAEzAQABZgEA
ATMBAAGZAQABMwEAAcwBAAEzAQAB/wEAAf8BMwIAAzMBAAIzAWYBAAIzAZkBAAIzAcwBAAIzAf8BAAEz
AWYCAAEzAWYBMwEAATMCZgEAATMBZgGZAQABMwFmAcwBAAEzAWYB/wEAATMBmQIAATMBmQEzAQABMwGZ
AWYBAAEzApkBAAEzAZkBzAEAATMBmQH/AQABMwHMAgABMwHMATMBAAEzAcwBZgEAATMBzAGZAQABMwLM
AQABMwHMAf8BAAEzAf8BMwEAATMB/wFmAQABMwH/AZkBAAEzAf8BzAEAATMC/wEAAWYDAAFmAQABMwEA
AWYBAAFmAQABZgEAAZkBAAFmAQABzAEAAWYBAAH/AQABZgEzAgABZgIzAQABZgEzAWYBAAFmATMBmQEA
AWYBMwHMAQABZgEzAf8BAAJmAgACZgEzAQADZgEAAmYBmQEAAmYBzAEAAWYBmQIAAWYBmQEzAQABZgGZ
AWYBAAFmApkBAAFmAZkBzAEAAWYBmQH/AQABZgHMAgABZgHMATMBAAFmAcwBmQEAAWYCzAEAAWYBzAH/
AQABZgH/AgABZgH/ATMBAAFmAf8BmQEAAWYB/wHMAQABzAEAAf8BAAH/AQABzAEAApkCAAGZATMBmQEA
AZkBAAGZAQABmQEAAcwBAAGZAwABmQIzAQABmQEAAWYBAAGZATMBzAEAAZkBAAH/AQABmQFmAgABmQFm
ATMBAAGZATMBZgEAAZkBZgGZAQABmQFmAcwBAAGZATMB/wEAApkBMwEAApkBZgEAA5kBAAKZAcwBAAKZ
Af8BAAGZAcwCAAGZAcwBMwEAAWYBzAFmAQABmQHMAZkBAAGZAswBAAGZAcwB/wEAAZkB/wIAAZkB/wEz
AQABmQHMAWYBAAGZAf8BmQEAAZkB/wHMAQABmQL/AQABzAMAAZkBAAEzAQABzAEAAWYBAAHMAQABmQEA
AcwBAAHMAQABmQEzAgABzAIzAQABzAEzAWYBAAHMATMBmQEAAcwBMwHMAQABzAEzAf8BAAHMAWYCAAHM
AWYBMwEAAZkCZgEAAcwBZgGZAQABzAFmAcwBAAGZAWYB/wEAAcwBmQIAAcwBmQEzAQABzAGZAWYBAAHM
ApkBAAHMAZkBzAEAAcwBmQH/AQACzAIAAswBMwEAAswBZgEAAswBmQEAA8wBAALMAf8BAAHMAf8CAAHM
Af8BMwEAAZkB/wFmAQABzAH/AZkBAAHMAf8BzAEAAcwC/wEAAcwBAAEzAQAB/wEAAWYBAAH/AQABmQEA
AcwBMwIAAf8CMwEAAf8BMwFmAQAB/wEzAZkBAAH/ATMBzAEAAf8BMwH/AQAB/wFmAgAB/wFmATMBAAHM
AmYBAAH/AWYBmQEAAf8BZgHMAQABzAFmAf8BAAH/AZkCAAH/AZkBMwEAAf8BmQFmAQAB/wKZAQAB/wGZ
AcwBAAH/AZkB/wEAAf8BzAIAAf8BzAEzAQAB/wHMAWYBAAH/AcwBmQEAAf8CzAEAAf8BzAH/AQAC/wEz
AQABzAH/AWYBAAL/AZkBAAL/AcwBAAJmAf8BAAFmAf8BZgEAAWYC/wEAAf8CZgEAAf8BZgH/AQAC/wFm
AQABIQEAAaUBAANfAQADdwEAA4YBAAOWAQADywEAA7IBAAPXAQAD3QEAA+MBAAPqAQAD8QEAA/gBAAHw
AfsB/wEAAaQCoAEAA4ADAAH/AgAB/wMAAv8BAAH/AwAB/wEAAf8BAAL/AgAD/wQAARoBmQEbAf8CAAH/
AfQBGgGZAf81AAF0ATIBNwFLAfEB9AF0ATEBOAEyAfM1AAF5AzgCNwM4ATEB8zUAAZkEOAH7AzgBMQH0
NQABmQg4ATEB9jUAAZkEegJZAjgBMQH0MwAB/wGZAVgIegFZAXkB/zIAARoBWQt6AVIB/zAAAfQBeQ16
ARowAAHzAVIMegF5AZkxAAH2ARsBGgGZBnoBmQEaARsB9AH/NQABGwF6ApoBegF5Af85AAH/AXkCoAF6
AfY7AAH2AXoBoAEaPQABGwGaAf93AAH/DPIB9AH/BwABBwHsAeoBbQHqAewBvBMABP8B9AHzAQcB7wHw
AfQF/wEAAZMDRQZGBEUB9AkAAW0BEwHsBgAC/wn2Af8FAAH0AfAB9wEUARECEAYAAf8BbwIfAUYGJQFG
ASQBHwFFAfIDAAH0BfMBbQFDAZIFAAH/AZkBUwkyAXUB/wEAAf8BBwHwAfEB9AH/AfMCBwHyAwAB/wIA
Af8BbwEfAW8B9AF0ASUCJgIlARsBkwEfAUUB8gMAAe0BEQFEAQEBRAIRAQ8BkgUAAf8CUwGaAVMBwwFZ
AcMBWQQyAfYBAAH/AfIB8AERAfQHAAHxAUMB8wEAAf8BbwEfAZMC8wF1AiwBTQHxAfMB8AFFASQB8gQA
Af8BRQEfAW4B/wHrAQ4B7QUAAf8BMgFTARoBWQH/AVkB/wFZBDIB9gEAAfQB7AETAQ8B8gcAAe8BEQEV
AfEB/wFvAR8BJAGTAfIB8QF1ASwBvAHxAbwBJAEfASQB8gUAAW8BIAGTAQABbQEAAe0FAAH/AzIBmgHD
AVkB/wE4BDIB9gEAAfQBDgHqARAB8gcAAe8BQwEVAZIB/wFvAh8BJAGTAfEB8AK8AQcBRgMfAfIFAAFv
ASABkwEAAW0BAAHtBQAB/wEyAVMBGgGaAVMBmgF6BTIB9gEAAfQB6gHrAUMB8gcAAe8BEwHqAQcB/wFv
AQEBHwEkAUYBHAHxAfABBwElAh8BAQEfAfIFAAFvASABkwEAAesBEAHtBQAB/wEsAjIBWQH2ARoBUwUy
AfYCAAEHAe0BFAHyBwAB7wFtAewB8AH/AW8BRQFGAUwBbwPxAfABkwFvAUYCRQHyBAAB/wFuASABkwEA
AesBDwGSAwAB8wEAAf8BUwF6AcMBGgGaAXoBWQJ6A1MB/wIAAfIBvAESAfMHAAEHAesB8AHzAf8EbwHx
AfIBvAEHAfEB8gGTA28B8gQAAfMBCwEfAZMBAAHrAREBkgMAARMBAAH/AVMDdQR6BHUB/wIAAfQBvAH/
CQAB/wHvAf8BAAJvAZMC8wG8AZMBbwEHAfIB8wGTAm8B8wQAAfQBDwEBAZMBAAHrAUMBkgEAAf8BvAER
AQAB/wFTCnoBdQH/AgAB/wGSAfQJAAHyAe8B/wEAAm8BvAHzAfAEbwHvAvMBkwFvAfMEAAH/AREBEAFD
AW0BQwIVAW0BFAERARQBAAH/AVMKegF1Af8DAAH/AfIJAAHyAwADkwEHBpMB7wOTAfMB9AFvAgAB/wIS
AW0D7QFEAu0B7AGSAQAB/wF1CpoBegH/BAABvAHvAf8FAAH0AewB8QMADpMB8wH/AUUB/wIAARwB7QHv
AgAB8QFFBQAB/wEbAXoJdQEaAf8EAAH/AkMBvAL/AfQBBwEQAW0B/wMAAfMMkwEaAv8CbgLvAW4B9wHs
Ae8BkwJuBgAM/wYAAf8B7wETAw4BFAEHAf8TAAH/C28bAAH/AfMB/wYABP8C9AHvAewBkgHyAfQF/wMA
C/8CAAH/AfAB7wHyAf8HAAH/AfMBGgH/EwAB9AESAewE7wHsAfAFAAH/AfQK8gHzAf8BAAH/AQcB/wHv
AfIB/wUAAf8B8gFSATgBGgQAAfQBCAwAAfAC7ALwAv8B9AGSAfAB7QQAAf8B8gHxAQgCvAHwAQgEGwLz
Av8BBwG8AewB7QHyAf8DAAH/AfABUgI4AZkEAAHyAU8BlwH0CQAB/wHsAW0D/wL0Av8BBwHzAQcDAAH0
AfMBcgEoAS4BLwF4AS8ENQEbAfIB/wEAAfQBBwEUAQ8B7QH0Af8BAAH/AfIBMQE4AVkBdAH/BAAB8gIt
AU8B/wgAAeoBbQH0AbwD9AHzAfQBBwH0AZIBBwMAAfQB8wFyAigCmAIvAzUBGwHyAf8BAAH/AfQB7wET
ARQB9wH0Af8B8wFSAlkBmQH/BQAB8gIzAS0BTwG8Af8FAAH/Ae0BvAT0AfMB8gT0AfEBBwIAAfQB8wFy
AigB/wEIBS8BCAHyAf8DAAH/AQcBEgFDAe8BvAExATgBWQGZAf8GAAHyAjMCLQECAZgB/wQAAfAB7AH0
AfMC9AEHAfQBGgP0AfAB7QHsAgAB9AHzAXICKAH/AfQBUAEuAXgBUAEvAbwB8gH/BAAB/wEHAhIB7QFZ
ATIB8wH/BwAB8gIzAS0CAgEnAXIB9AMAAQcB7AL0AvMB9AEfAbwE9AHtAe8BDgEAAfQB8wFyAigB9AL/
AbwB/wFQASgBvAHyAf8FAAH/Ae8B7AHwAfcBvAH/CAAB8gMtAgIBJwEhAUkB9AIAAbwBkgLzAfAC8wEH
Ae0E8wHtAe8B/wEAAfQB8wFyAigBUAH0A/8BUAEoAbwB8gH/BQAB/wIHAewB6wEHAfMC/wYAAfEGTwFJ
AZgB/wIAAf8BBwHxAfMB8gHzAZMC8wEHAvMB8QHwAQcCAAH0AfMBcgMoAZgD/wFQASgBvAHyAf8EAAH/
AQcB8QHyAQcB7wHsAesB7AHvAfQB/wQAAfEGTwEIBQABBwHrAfMB7wHzARoD8wHwAfEB7AHzAf8CAAH0
AfMBcgIoAVAECAFKASgBvAHyAf8DAAH0AQcBvAHyAv8B8AHsAe0B7wLtAfQEAAHxAU8EcgHxAf8FAAHz
AfEB7AHyAfAD8wHyAbwB7AHxAe8DAAH0AfMBcgkoAbwB8gH/AgAB/wEHAfIB8wMAAfIBvAEHAbwC7wHx
BAAB8QFyAZcBcgFJAfQIAAEHAfMB6wHvAfcBBwHvAe0BbQHwAe0B9wHtAf8BAAH0AfMBHAlyAfEB8gL/
AfMB7wG8AfMB/wMAAfQBBwHyAQcB9AH/AfQEAAHxAnIB7wH/CgAC8wG8Ae0C7AEHAfMBBwHyAbwB9AEH
AQAB/wHwCvMB8gH0AQAB/wIHAfMFAAH/Ae8B9AHvAfMB/wUAAfEBTwEIAf8NAAHzAbwBBwG8AfICAAHy
AfQBAAG8AQAC/wr0Av8BAAH/AfEB8gH/BQAB/wHyAfAB8wEHAfQFAAH/AfMXAALxHAAB/wHzAf8cAAH/
AfADmAH0IAAF/wH0Cv8B9A3yAZEB7xAAEP8QAAHxAvQC/wHvA/8B8gHxAfQBCAG7AfABkQQAAQEBHgQA
Af8BRQEBAwAB8wHwBfIC8QbyAfABAAG8ArQLtQH/AfIC9AL/Ae8D/wHyAfEBcgFxAZEBSQFyAwABAQH5
AUcBCwIAAf8BHgH5ARcBAQIAAfIB8wP/AfMBuwK0AQkB9AT/AfABAAH3AUMBFQJKAUQBQwERA0MBFQFD
ARMB9AHyAvQC/wHvA/8B8gHxAUkC/wEHAXECAAGTAW8C+QFHAQsB/wELA/kBRQIAAfIB8wL/AfQBtAGz
AgkCtAHxA/8B8AEAAfcBEQFDAkoBFQMQAhEBQwERAWYB9AHyBAcB7AG8AvACvAFJAfMB9AHxAXIDAAJv
AiABRgEOAyABAQH/AgAB8gHzAv8CiwG0AgkBtAGLAa4D/wHwAQAB9wEQAUMCSgFEAREDEAMRARUB9AHy
BLwBkgHwAvEB8AG8AUkB7wHwAewB7wQAAW8BTAUgAQEB/wMAAfIB8wH/AQcBhgGtAbQBCQG6AbMBrQGG
AQcC/wHwAQAB9wIUAkoBFAERARABDwQOARUB9AHyAfQBBwEIAf8BBwH/AfIB/wHzAfEB8AFJAQ0B7QH/
BQABbwFMAyABHwH/BAAB8gHzAf8BtQGGArQCswGtAosBrgL/AfEBAAHvAusBbQHqARIBFAEVAREBEAIP
ARABFQH0AfIC8wEHAfQBBwH/AbwB/wHzAfED/wHyAf8EAAH/AR8DRgFvAUYBHwQAAfIB8wH/AbUBhgG7
AQkBtAGtAosBzwGuAv8B8QEAAQcBkwF0AXkCegJTAkwDKwFLAfQB8gHzAQcBvAH0AQcB/wHwAf8B8wHy
A/8B8wQAAf8BHwNGAXQCRgFvAR8DAAHyAfMB/wK1AgkBtAKLAYYBiwG1Av8B8QEAAQcBlAGaAqABegF1
AlMETQFvAfQB8gG8AwcB9wG8BPAB8wH0Af8B8wMAAf8BHwNvAQEBbgF0Am8BFgEfAgAB8gHzAf8B8wG1
AQcBCQG0Ac8CiwGuAfQC/wHxAQABBwKUA5oDdQLjAhcBbwH0BfMBBwP0AfMB8gP/AfMDAAEaAUwCFgEf
Af8BAAFvAxYBHwIAAfIB8wL/AfABtQEJAa4BtAGuAc8BvAP/AfEBAAEHBrcDlAOxAY4B9ALzAggB8wG8
A/QB8wHyA/8B8wQAARoBTAEfAf8DAAFvARYBHwMAAvID8wG8ArUBrgG1AbwE8wHxAQABBwHPDLUB9ALz
AfIBBwHzAfAE8wHyA/QB8wUAARoB/wUAAZMEAAHyCfAC7wO1AfABAAG7A60DswK0BdUB9ALzAvAB8wHw
BfMD9AHzEQAB9Am8AQcBvAMHAfIBAAHyBQkE3QQZAv8G8gfzAf8xAAFCAU0BPgcAAT4DAAEoAwABQAMA
AUADAAEBAQABAQYAAQIWAAP/AQAB4QGDBgAB4AEDBgAB4AEDBgAB4AEDBgAB4AEDBgAB4AEDBgABgAEB
BgABgBcAAYAHAAH4AQ8GAAH4AR8GAAH8AT8GAAH+AT8GAAL/BgABgAEAAf4BAwL/AYABAAGAAQAB/wGP
AcABAwHgAT8CAAHgAQ8BgAEBAQABOwIAAeABDwGAAQEBBwHxAgAB8AEPAYABAQEHAfACAAH4AY8BgAEB
AQcB8AIAAfgBjwGAAQEBBwHwAgAB+AGPAYABAQGHAfACAAHwAY4BgAEBAYcB8AIAAfABjgGAAQEBjwH4
AYABAAHwAYgBgAEBAY8B+AGAAQAB8AEAAYABAQHPAfsBgAEAATABAAGAAQEC4wGAAQABGAHPAYABAQHg
AQMBgAIAAQ8BwAEDAfABBwL/AQABDwL/Af4BPwIAAeABAwEHAfAC/wHgAQ8BgAEBAQMB4AHzAf8BwAEH
AYABAAEBAcAB8AH/AYABAwGAAQACgAHwAX8BgAEDAYABAAGAAQEB8AEfAQABAQGAAQAB4AEDAfABDwEA
AQEBgAEAAfABBwHwAQcCAAGAAQAB+AEPAfABAwIAAYABAAH4AQMB8AEDAQABAQGAAQAB8AEAAfABDwGA
AQEBgAEAAeABAAHwAQ8BgAEDAYABAAHDAYAB8AE/AcABAAGAAQABAwGAAfABfwHgAQABgAEBAQ8BgQHw
Af8B+AEyAYABAQEPAYEB8wL/AfkD/wHjA/8BwAT/BAAC/wIAAv8CAAHzAccCAAGAAwAB4QGDAgABgAMA
AcABAwIAAYADAAHgAQMCAAGAAwAB8AEHAgABgAMAAfgBDwIAAYADAAHwAQ8CAAGAAgABAQHgAQcCAAGA
AgABAQHAAQMCAAGAAgABAQHAAYMCAAGAAgABAQHhAccCAAGAAgABAQHzAe8CAAGAAgABAQL/AgABgAIA
AQEG/ws=
</value>
</data>
<data name="richTextBox1.Text" xml:space="preserve">
<value>QO-100 Multimedia High Speed Modem for Linux and Windows
(c) by DJ0ABR, Kurt Moraw, Germany https://dj0abr.de/
for Amsat-DL: https://amsat-dl.org/
Open Source: https://github.com/dj0abr/SSB_HighSpeed_Modem
3rd Party, Credits and Licensing:
BASS audio library:
www.un4seen.com: BASS is free for non-commercial use
DSP Library liquid-DSP:
https://liquidsdr.org/
MIT License
OPUS Codec:
https://opus-codec.org/
BSD-licensed
FFTW: http://www.fftw.org/
GNU General Public License
FreeDV: https://github.com/drowe67/codec2
GNU Lesser General Public License v2.1
Image from ICON Archive: https://www.iconarchive.com/
Artist: Oxygen Team
Iconset: Oxygen Icons (883 icons)
License: GNU Lesser General Public License
Artist: Sallee Design (Available for custom work)
Iconset: Music Icons (29 icons)
License: CC Attribution 4.0
Testing &amp; Manual:
DD1US: https://www.dd1us.de/
VIP user: DP0GVN: https://www.awi.de/expedition/stationen/neumayer-station-iii.html
</value>
</data>
<metadata name="timer_searchmodem.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>482, 17</value>
</metadata>

75
oscardata/oscardata/Form2_showtext.Designer.cs generated Executable file
View File

@ -0,0 +1,75 @@
namespace oscardata
{
partial class Form2_showtext
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.rtb = new System.Windows.Forms.RichTextBox();
this.bt_OK = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// rtb
//
this.rtb.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.rtb.Location = new System.Drawing.Point(13, 13);
this.rtb.Name = "rtb";
this.rtb.Size = new System.Drawing.Size(310, 315);
this.rtb.TabIndex = 0;
this.rtb.Text = "";
//
// bt_OK
//
this.bt_OK.Location = new System.Drawing.Point(247, 335);
this.bt_OK.Name = "bt_OK";
this.bt_OK.Size = new System.Drawing.Size(75, 23);
this.bt_OK.TabIndex = 1;
this.bt_OK.Text = "OK";
this.bt_OK.UseVisualStyleBackColor = true;
this.bt_OK.Click += new System.EventHandler(this.bt_OK_Click);
//
// Form2_showtext
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(335, 367);
this.Controls.Add(this.bt_OK);
this.Controls.Add(this.rtb);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form2_showtext";
this.ShowIcon = false;
this.Text = "Form2_showtext";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.RichTextBox rtb;
private System.Windows.Forms.Button bt_OK;
}
}

View File

@ -0,0 +1,65 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace oscardata
{
public partial class Form2_showtext : Form
{
public Form2_showtext(String title,String s)
{
InitializeComponent();
this.Text = title;
PrintText(rtb,s);
}
void PrintText(RichTextBox rtb, String s)
{
AppendTextOnce(rtb, new Font("Courier New", (float)8), Color.Blue, Color.White, s);
}
void AppendTextOnce(RichTextBox rtb, Font selfont, Color color, Color bcolor, string text)
{
try
{
if (text.Contains("\n"))
{
char[] ca = new char[] { '\n', '\r' };
text = text.Trim(ca);
text += "\n";
}
// max. xxx Zeilen, wenn mehr dann lösche älteste
if (rtb.Lines.Length > 200)
{
rtb.SelectionStart = 0;
rtb.SelectionLength = rtb.Text.IndexOf("\n", 0) + 1;
rtb.SelectedText = "";
}
int start = rtb.TextLength;
rtb.AppendText(text);
int end = rtb.TextLength;
// Textbox may transform chars, so (end-start) != text.Length
rtb.Select(start, end - start);
rtb.SelectionColor = color;
rtb.SelectionFont = selfont;
rtb.SelectionBackColor = bcolor;
rtb.Select(end, 0);
rtb.ScrollToCaret();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void bt_OK_Click(object sender, EventArgs e)
{
this.Close();
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -63,9 +63,9 @@ namespace oscardata.Properties {
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap constelBG {
internal static System.Drawing.Bitmap binary {
get {
object obj = ResourceManager.GetObject("constelBG", resourceCulture);
object obj = ResourceManager.GetObject("binary", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
@ -73,9 +73,159 @@ namespace oscardata.Properties {
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap defaultpic {
internal static System.Drawing.Bitmap cancel {
get {
object obj = ResourceManager.GetObject("defaultpic", resourceCulture);
object obj = ResourceManager.GetObject("cancel", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap cdc_codecloop {
get {
object obj = ResourceManager.GetObject("cdc_codecloop", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap cdc_dig {
get {
object obj = ResourceManager.GetObject("cdc_dig", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap cdc_digital {
get {
object obj = ResourceManager.GetObject("cdc_digital", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap cdc_dv {
get {
object obj = ResourceManager.GetObject("cdc_dv", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap cdc_dvrx {
get {
object obj = ResourceManager.GetObject("cdc_dvrx", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap cdc_intloop {
get {
object obj = ResourceManager.GetObject("cdc_intloop", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap fail {
get {
object obj = ResourceManager.GetObject("fail", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap html {
get {
object obj = ResourceManager.GetObject("html", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap image {
get {
object obj = ResourceManager.GetObject("image", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap image1 {
get {
object obj = ResourceManager.GetObject("image1", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap image3 {
get {
object obj = ResourceManager.GetObject("image3", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap meter {
get {
object obj = ResourceManager.GetObject("meter", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap meter_big {
get {
object obj = ResourceManager.GetObject("meter_big", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap ok {
get {
object obj = ResourceManager.GetObject("ok", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap openfolder {
get {
object obj = ResourceManager.GetObject("openfolder", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
@ -89,5 +239,105 @@ namespace oscardata.Properties {
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Satellite_icon1 {
get {
object obj = ResourceManager.GetObject("Satellite_icon1", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap setup {
get {
object obj = ResourceManager.GetObject("setup", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap setup_big {
get {
object obj = ResourceManager.GetObject("setup_big", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap start {
get {
object obj = ResourceManager.GetObject("start", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap stop {
get {
object obj = ResourceManager.GetObject("stop", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap text {
get {
object obj = ResourceManager.GetObject("text", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap text_big {
get {
object obj = ResourceManager.GetObject("text_big", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap transmit {
get {
object obj = ResourceManager.GetObject("transmit", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap voice {
get {
object obj = ResourceManager.GetObject("voice", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap voice_big {
get {
object obj = ResourceManager.GetObject("voice_big", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@ -118,13 +118,88 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="defaultpic" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>defaultpic.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Satellite_icon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Satellite-icon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="constelBG" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>constelBG.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<data name="image" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>image.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="image1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>image1.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="binary" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>binary.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="cancel" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>cancel.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="html" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>html.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="image3" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>image.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="meter" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>meter.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="meter_big" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>meter_big.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="openfolder" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>openfolder.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Satellite_icon1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Satellite-icon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="setup" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>setup.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="setup_big" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>setup_big.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="start" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>start.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="stop" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>stop.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="text" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>text.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="text_big" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>text_big.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="transmit" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>transmit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="voice" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>voice.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="voice_big" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>voice_big.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="fail" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>fail.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ok" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>ok.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="cdc_codecloop" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>cdc_codecloop.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="cdc_dig" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>cdc_dig.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="cdc_digital" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>cdc_digital.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="cdc_dv" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>cdc_dv.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="cdc_dvrx" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>cdc_dvrx.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="cdc_intloop" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>cdc_intloop.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 784 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup>
</configuration>

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup>
</configuration>

Binary file not shown.

View File

@ -22,6 +22,8 @@ namespace oscardata
public static Byte AsciiFile = 3;
public static Byte HTMLFile = 4;
public static Byte BinaryFile = 5;
public static Byte Audio = 6;
// the upper values are for internal use
public static Byte ResamplingRate = 16;
public static Byte AutosendFile = 17;
@ -30,6 +32,10 @@ namespace oscardata
public static Byte ResetModem = 20;
public static Byte SetPBvolume = 21;
public static Byte SetCAPvolume = 22;
public static Byte SetLSvolume = 23;
public static Byte SetMICvolume = 24;
public static Byte SetVoiceMode = 25;
public static Byte terminate = 26;
// frame sequence, modem needs that for i.e. sending a preamble
public static Byte FirstFrame = 0;
@ -65,6 +71,9 @@ namespace oscardata
public static String[] AudioPBdevs;
public static String[] AudioCAPdevs;
public static int PBfifousage = 0;
public static int CAPfifousage = 0;
public static int initAudioStatus;
public static int initVoiceStatus;
public static String[] getOwnIPs()
@ -198,6 +207,38 @@ namespace oscardata
return home + filename;
}
public static void CreateAllDirs()
{
String home = Application.UserAppDataPath;
String deli = "/";
if (statics.ostype == 0)
deli = "\\";
// create home directory
try
{
Directory.CreateDirectory(home);
}
catch { }
// create application path
home += deli + DataStorage;
try
{
Directory.CreateDirectory(home);
}
catch { }
// create image path
home += deli + RXimageStorage;
try
{
Directory.CreateDirectory(home);
}
catch { }
}
// Returns the file's size.
public static long GetFileSize(string file_name)
{
@ -305,6 +346,23 @@ namespace oscardata
return true;
}
// checks if a process is running
static public bool isProcRunning(String s)
{
bool running = false;
if (ostype == 0)
{
foreach (var process in Process.GetProcessesByName(s))
{
running = true;
break;
}
}
return running;
}
static public void killall(String s)
{
if (ostype == 0)

View File

@ -107,26 +107,5 @@ namespace oscardata
return destImage;
}
// gets a receive payload, reconstruct the image
// type: 2=start, 3=cont
public void receive_image(Byte[] rxdata, int minfo)
{
BinaryWriter writer = null;
if (minfo == statics.FirstFrame)
{
// image starts, create destination file
writer = new BinaryWriter(File.Open(statics.jpg_tempfilename, FileMode.Create));
writer.Write(rxdata);
}
else
{
// continue with image
writer = new BinaryWriter(File.Open(statics.jpg_tempfilename, FileMode.Append));
writer.Write(rxdata);
}
writer.Close();
}
}
}

View File

@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]

Binary file not shown.

View File

@ -0,0 +1 @@
9e2591805e48c9de90be794d8c80dc9ff27fb5a3

View File

@ -0,0 +1,11 @@
E:\funk\hsmodem\oscardata\oscardata\bin\Debug\oscardata.exe.config
E:\funk\hsmodem\oscardata\oscardata\bin\Debug\oscardata.exe
E:\funk\hsmodem\oscardata\oscardata\bin\Debug\oscardata.pdb
E:\funk\hsmodem\oscardata\oscardata\obj\Debug\oscardata.Form1.resources
E:\funk\hsmodem\oscardata\oscardata\obj\Debug\oscardata.Properties.Resources.resources
E:\funk\hsmodem\oscardata\oscardata\obj\Debug\oscardata.csproj.GenerateResource.cache
E:\funk\hsmodem\oscardata\oscardata\obj\Debug\oscardata.csproj.CoreCompileInputs.cache
E:\funk\hsmodem\oscardata\oscardata\obj\Debug\oscardata.exe
E:\funk\hsmodem\oscardata\oscardata\obj\Debug\oscardata.pdb
E:\funk\hsmodem\oscardata\oscardata\obj\Debug\oscardata.csprojAssemblyReference.cache
E:\funk\hsmodem\oscardata\oscardata\obj\Debug\oscardata.Form2_showtext.resources

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]

Some files were not shown because too many files have changed in this diff Show More