This commit is contained in:
kurt 2021-01-15 22:15:58 +01:00
parent 429ec008a9
commit 46faf838bc
194 changed files with 15030 additions and 472 deletions

0
WinRelease/audio/1200.pcm Normal file → Executable file
View File

0
WinRelease/audio/2400.pcm Normal file → Executable file
View File

0
WinRelease/audio/3000.pcm Normal file → Executable file
View File

0
WinRelease/audio/4000.pcm Normal file → Executable file
View File

0
WinRelease/audio/4410.pcm Normal file → Executable file
View File

0
WinRelease/audio/4800.pcm Normal file → Executable file
View File

0
WinRelease/audio/5500.pcm Normal file → Executable file
View File

0
WinRelease/audio/6000.pcm Normal file → Executable file
View File

0
WinRelease/audio/6600.pcm Normal file → Executable file
View File

0
WinRelease/audio/7200.pcm Normal file → Executable file
View File

0
WinRelease/audio/amsat.pcm Normal file → Executable file
View File

0
WinRelease/audio/bpsk.pcm Normal file → Executable file
View File

0
WinRelease/audio/kbps.pcm Normal file → Executable file
View File

0
WinRelease/audio/psk8.pcm Normal file → Executable file
View File

0
WinRelease/audio/qpsk.pcm Normal file → Executable file
View File

Binary file not shown.

BIN
WinRelease/hsmodem.iobj Executable file

Binary file not shown.

BIN
WinRelease/hsmodem.ipdb Executable file

Binary file not shown.

BIN
WinRelease/hsmodem.pdb Executable file

Binary file not shown.

Binary file not shown.

BIN
WinRelease/portaudio_x86.dll Executable file

Binary file not shown.

0
hsmodem.sln Executable file → Normal file
View File

0
hsmodem.wse Executable file → Normal file
View File

View File

@ -9,7 +9,18 @@
CXXFLAGS = -Wall -O3 -std=c++0x -Wno-write-strings -Wno-narrowing
LDFLAGS = -lpthread -lrt -lsndfile -lasound -lm -lopus -lfftw3 -lfftw3_threads -lliquid -lcodec2 -lsoundio
OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o scrambler.o speed.o fec.o udp.o fft.o liquid_if.o symboltracker.o voiceprocessor.o codec2.o soundio.o fifo.o announcement.o fifo_voice.o voiceio.o tuning.o rtty.o
OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o\
scrambler.o speed.o fec.o udp.o fft.o liquid_if.o symboltracker.o\
voiceprocessor.o codec2.o fifo.o announcement.o tuning.o rtty.o volume.o\
libkmaudio/libkmaudio_fifo.o\
libkmaudio/libkmaudio_getDevices.o\
libkmaudio/libkmaudio_getDevices_Linux.o\
libkmaudio/libkmaudio_init.o\
libkmaudio/libkmaudio_init_linux.o\
libkmaudio/libkmaudio_interface.o\
libkmaudio/libkmaudio_capture_linux.o\
libkmaudio/libkmaudio_playback_linux.o\
libkmaudio/libkmaudio_resampler.o
default: $(OBJ)
mkdir -p ../hsmodemLinux

0
hsmodem/SharedLibs/aarch64/libliquid.so Normal file → Executable file
View File

0
hsmodem/SharedLibs/aarch64/libsoundio.so Normal file → Executable file
View File

0
hsmodem/SharedLibs/aarch64/libsoundio.so.2 Normal file → Executable file
View File

0
hsmodem/SharedLibs/aarch64/libsoundio.so.2.0.0 Normal file → Executable file
View File

Binary file not shown.

View File

@ -92,7 +92,8 @@ void playAudioPCM(char* fn, int destination)
{
int to = 4000;
int res;
while ((res = io_ls_fifo_usedspace()) > 10000)
//while ((res = io_ls_fifo_usedspace()) > 10000)
while ((res = io_fifo_usedspace(voice_pbidx)) > 10000)
{
if (--to == 0)
{
@ -102,7 +103,8 @@ void playAudioPCM(char* fn, int destination)
}
sleep_ms(1);
}
io_ls_write_fifo(f / 32768);
float f1 = f / 32768;
kmaudio_playsamples(voice_pbidx, &f1, 1, lsvol);
}
if (caprate == 44100)
@ -123,7 +125,8 @@ void playAudioPCM(char* fn, int destination)
if ((destination & 1) == 1)
{
int to = 4000;
while (io_pb_fifo_usedspace() > 10000)
//while (io_pb_fifo_usedspace() > 10000)
while (io_fifo_usedspace(io_pbidx) > 10000)
{
if (--to == 0)
{
@ -133,7 +136,7 @@ void playAudioPCM(char* fn, int destination)
}
sleep_ms(1);
}
io_pb_write_fifo(f);
kmaudio_playsamples(io_pbidx, &f, 1, pbvol);
}
}
@ -191,7 +194,9 @@ void playIntro()
snprintf(fn, 499, "%s/oscardata/intro/intro.pcm", homepath);
fn[499] = 0;
io_clear_voice_fifos();
//io_clear_voice_fifos();
io_fifo_clear(voice_pbidx);
io_fifo_clear(voice_capidx);
create_a();
playAudioPCM(fn, 3);
close_a();

0
hsmodem/audio/1200.pcm Normal file → Executable file
View File

0
hsmodem/audio/2400.pcm Normal file → Executable file
View File

0
hsmodem/audio/3000.pcm Normal file → Executable file
View File

0
hsmodem/audio/4000.pcm Normal file → Executable file
View File

0
hsmodem/audio/4410.pcm Normal file → Executable file
View File

0
hsmodem/audio/4800.pcm Normal file → Executable file
View File

0
hsmodem/audio/5500.pcm Normal file → Executable file
View File

0
hsmodem/audio/6000.pcm Normal file → Executable file
View File

0
hsmodem/audio/6600.pcm Normal file → Executable file
View File

0
hsmodem/audio/7200.pcm Normal file → Executable file
View File

0
hsmodem/audio/amsat.pcm Normal file → Executable file
View File

0
hsmodem/audio/bpsk.pcm Normal file → Executable file
View File

0
hsmodem/audio/kbps.pcm Normal file → Executable file
View File

0
hsmodem/audio/psk8.pcm Normal file → Executable file
View File

0
hsmodem/audio/qpsk.pcm Normal file → Executable file
View File

0
hsmodem/audio/sound0.pcm Normal file → Executable file
View File

0
hsmodem/audio/sound1.pcm Normal file → Executable file
View File

0
hsmodem/audio/wav2pcm.py Normal file → Executable file
View File

View File

@ -136,7 +136,7 @@ void encode_codec2(float f)
firinterp_crcf_execute(interp8_48, inp, outp);
for (int x = 0; x < decfactor; x++)
io_ls_write_fifo(outp[x].real);
kmaudio_playsamples(voice_pbidx, &outp[x].real, 1, lsvol);
}
}
}
@ -191,7 +191,8 @@ void toCodecDecoder_codec2(uint8_t* pdata, int len)
firinterp_crcf_execute(interp8_48, inp, outp);
for (int x = 0; x < decfactor; x++)
io_ls_write_fifo(outp[x].real);
//io_ls_write_fifo(outp[x].real);
kmaudio_playsamples(voice_pbidx, &outp[x].real, 1, lsvol);
}
}
}

0
hsmodem/endian.h Normal file → Executable file
View File

0
hsmodem/fec.h Normal file → Executable file
View File

0
hsmodem/fec/schifra_crc.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_ecc_traits.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_erasure_channel.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_error_processes.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_fileio.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_galois_field.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_galois_field_element.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_galois_field_polynomial.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_galois_utilities.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_reed_solomon_bitio.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_reed_solomon_block.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_reed_solomon_codec_validator.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_reed_solomon_encoder.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_reed_solomon_file_decoder.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_reed_solomon_file_encoder.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_reed_solomon_file_interleaver.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_reed_solomon_general_codec.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_reed_solomon_interleaving.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_reed_solomon_product_code.hpp Normal file → Executable file
View File

0
hsmodem/fec/schifra_reed_solomon_speed_evaluator.hpp Normal file → Executable file
View File

View File

0
hsmodem/fec/schifra_utilities.hpp Normal file → Executable file
View File

View File

@ -30,7 +30,7 @@
#include <fftw3.h>
#endif
uint16_t* mean(uint16_t* f);
uint16_t* mean(uint16_t* f, int smoothX, int smoothY);
#define FFT_AUDIOSAMPLERATE 800
@ -234,20 +234,20 @@ uint16_t *make_waterfall(float fre, int *retlen)
if(fftrdy == 1)
{
*retlen = fftcount;
return mean(fftout);
if(speedmode == 10)
return mean(fftout, 2, 2);
return mean(fftout,2,4);
}
return NULL;
}
// smooth fft output
const int smoothX = 2; // must be an even number !
const int smoothY = 10;
int yidx = 0;
uint16_t* mean(uint16_t* f)
uint16_t* mean(uint16_t* f, int smoothX, int smoothY)
{
if (smoothY > 20) smoothY = 20;
static uint16_t fa[FFT_AUDIOSAMPLERATE / 2 + 1];
if (tuning)
@ -270,12 +270,12 @@ uint16_t* mean(uint16_t* f)
// smooth Y values
static uint16_t yarr[smoothY][FFT_AUDIOSAMPLERATE / 2 + 1];
static uint16_t yarr[20][FFT_AUDIOSAMPLERATE / 2 + 1];
for (int i = 0; i < fftcount; i++)
yarr[yidx][i] = fa[i];
if (++yidx >= smoothY) yidx = 0;
memset(fa, 0, FFT_AUDIOSAMPLERATE / 2 + 1);
memset(fa, 0, sizeof(uint16_t) * (FFT_AUDIOSAMPLERATE / 2 + 1));
for (int i = 0; i < fftcount; i++)
{
for (int j = 0; j < smoothY; j++)
@ -288,6 +288,7 @@ uint16_t* mean(uint16_t* f)
void _init_fft()
{
printf("init FFT\n");
fftcount = FFT_AUDIOSAMPLERATE / 2 + 1; // number of output samples
// the FFT outputs 400 values from 0 to 4kHz with a resolution of 10 Hz
@ -301,9 +302,8 @@ void _init_fft()
// decimate 44.1k or 48k down to 8000Hz
// the FFT rate is 800, but we feed it with 8000 Samplerate
// this results in a new fft every 100ms with a resolution of 10 Hz
float ratio = 10.0f * (float)FFT_AUDIOSAMPLERATE / (float)physRXcaprate;
float ratio = 10.0f * (float)FFT_AUDIOSAMPLERATE / (float)caprate;
fftdecim = msresamp_crcf_create(ratio, 40.0f);
}
void _exit_fft()

0
hsmodem/fftw_lib/fftw3.h Normal file → Executable file
View File

View File

@ -27,8 +27,9 @@
#include "hsmodem.h"
void rtty_init_pipes();
/*
#ifdef _WIN32_
CRITICAL_SECTION io_cap_crit_sec;
CRITICAL_SECTION io_pb_crit_sec;
@ -198,9 +199,6 @@ int io_pb_fifo_usedspace()
IO_PB_UNLOCK();
return elemInFifo;
/*
int anz = io_pb_fifo_freespace(0);
return AUDIO_PLAYBACK_BUFLEN - anz;*/
}
// read num elements
@ -237,7 +235,7 @@ void io_clear_audio_fifos()
io_pb_write_fifo_clear();
io_cap_write_fifo_clear();
}
*/
// ================== RTTY FIFO ===================
void clear_rtty_fifos();
@ -271,12 +269,17 @@ void RTTY_RX_UNLOCK() { pthread_mutex_unlock(&rtty_rx_crit_sec); }
void rtty_init_pipes()
{
#ifdef _WIN32_
if (&rtty_tx_crit_sec != NULL) DeleteCriticalSection(&rtty_tx_crit_sec);
InitializeCriticalSection(&rtty_tx_crit_sec);
static int f = 1;
if (&rtty_rx_crit_sec != NULL) DeleteCriticalSection(&rtty_rx_crit_sec);
InitializeCriticalSection(&rtty_rx_crit_sec);
if (f)
{
f = 0;
if (&rtty_tx_crit_sec != NULL) DeleteCriticalSection(&rtty_tx_crit_sec);
InitializeCriticalSection(&rtty_tx_crit_sec);
if (&rtty_rx_crit_sec != NULL) DeleteCriticalSection(&rtty_rx_crit_sec);
InitializeCriticalSection(&rtty_rx_crit_sec);
}
#endif
clear_rtty_fifos();

0
hsmodem/frameformat.h Normal file → Executable file
View File

View File

@ -24,7 +24,7 @@
*/
/*
* this is a console program
* this is a console program
* it can be compiled under Linux: make
* and under Windows: Visual-Studio
*
@ -65,11 +65,11 @@ char ownfilename[] = { "hsmodem" };
char appIP[20] = { 0 };
int fixappIP = 0;
int restart_modems = 0;
int init_voice = 0;
int trigger_resetmodem = 0;
char homepath[1000] = { 0 };
int caprate = 44100;
int physRXcaprate = 44100;
int txinterpolfactor = 20;
int rxPreInterpolfactor = 5;
int linespeed = 4410;
@ -79,20 +79,20 @@ char playbackDeviceName[101] = { 0 };
char micDeviceName[101] = { 0 };
char lsDeviceName[101] = { 0 };
float softwareCAPvolume = 1;
float softwarePBvolume = 1;
float softwareMICvolume = 1;
float softwareLSvolume = 1;
int announcement = 0;
int VoiceAudioMode = VOICEMODE_OFF;
int codec = 1; // 0=opus, 1=codec2
int tuning = 0;
int marker = 1;
int init_audio_result = 0;
int init_voice_result = 0;
// number of audio device in libkmaudio
int io_capidx = 0;
int io_pbidx = 0;
int voice_capidx = 0;
int voice_pbidx = 0;
int safemode = 0;
int sendIntro = 0;
@ -182,7 +182,7 @@ int main(int argc, char* argv[])
struct stat st = { 0 };
char nd[1000];
char nd[1100];
sprintf(nd, "%s/oscardata", homepath);
if (stat(nd, &st) == -1)
{
@ -194,6 +194,9 @@ int main(int argc, char* argv[])
#endif
printf("user home path:<%s>\n", homepath);
init_tune();
kmaudio_init();
kmaudio_getDeviceList();
init_packer();
initFEC();
@ -207,6 +210,8 @@ int main(int argc, char* argv[])
while (keeprunning)
{
int wait = 1;
if (restart_modems == 1)
{
printf("restart modem requested\n");
@ -214,25 +219,36 @@ int main(int argc, char* argv[])
restart_modems = 0;
}
if (init_voice == 1)
{
initVoice();
init_voice = 0;
}
//doArraySend();
if (VoiceAudioMode == VOICEMODE_INTERNALLOOP)
{
// loop voice mic to LS
float f;
while (io_mic_read_fifo(&f))
{
io_ls_write_fifo(f);
}
float f[1100]; // 1.1 x need rate to have reserve for resampler
int anz = kmaudio_readsamples(voice_capidx, f, 1000, micvol, 0);
if (anz > 0)
kmaudio_playsamples(voice_pbidx, f, anz,lsvol);
}
if (VoiceAudioMode == VOICEMODE_RECORD)
{
// loop voice mic to LS, and record into PCM file
float f;
while (io_mic_read_fifo(&f))
float f[1100];
while (1)
{
io_saveStream(f);
io_ls_write_fifo(f);
int anz = kmaudio_readsamples(voice_capidx, f, 1000, micvol,0);
if (anz > 0)
{
io_saveStream(f, anz);
kmaudio_playsamples(voice_pbidx, f, anz,lsvol);
}
else
break;
}
}
@ -246,7 +262,8 @@ int main(int argc, char* argv[])
{
// send mic to codec
float f;
while (io_mic_read_fifo(&f))
while(kmaudio_readsamples(voice_capidx, &f, 1, micvol,0))
//while (io_mic_read_fifo(&f))
{
encode(f);
}
@ -255,36 +272,34 @@ int main(int argc, char* argv[])
if (tuning != 0)
{
do_tuning(tuning);
wait = 0;
}
if (speedmode == 10)
{
// nothing to do here
//testall();
//fmtest();
sleep_ms(10); // nothing to do here
}
else
{
// demodulate incoming audio data stream
static uint64_t old_tm = 0;
#ifdef _LINUX_
/*static uint64_t old_tm = 0;
uint64_t tm = getms();
if (tm >= (old_tm + 1000))
{
// read Audio device list every 1s
io_readAudioDevices();
// runtime dectection currently works under linux only
kmaudio_getDeviceList();
old_tm = tm;
}
int dret = demodulator();
if (dret == 0)
{
// no new data in fifo
#ifdef _LINUX_
// not important how long to sleep, 10ms is fine
sleep_ms(10);
}*/
#endif
}
// demodulate incoming audio data stream
int dret = demodulator();
if (dret) wait = 0;
}
if (wait) sleep_ms(10);
}
printf("stopped: %d\n", keeprunning);
@ -335,7 +350,6 @@ void startModem()
printf("startModem\n");
close_dsp();
close_rtty();
io_close_audio();
speedmode = set_speedmode;
bitsPerSymbol = sr[speedmode].bpsym;
@ -348,7 +362,20 @@ void startModem()
opusbitrate = sr[speedmode].codecrate;
// int TX audio and modulator
init_audio_result = io_init_sound(playbackDeviceName, captureDeviceName);
io_capidx = kmaudio_startCapture(captureDeviceName, caprate);
if (io_capidx == -1)
{
printf("CAP: cannot open device: %s\n", captureDeviceName);
return;
}
io_pbidx = kmaudio_startPlayback(playbackDeviceName, caprate);
if (io_pbidx == -1)
{
printf("PB: cannot open device: %s\n", playbackDeviceName);
return;
}
_init_fft();
if (speedmode < 10)
{
@ -359,6 +386,26 @@ void startModem()
rtty_txoff = 1;
init_rtty();
}
init_tune();
}
void initVoice()
{
// init voice audio
if (VoiceAudioMode == VOICEMODE_OFF)
{
float f = 0.0f;
io_saveStream(&f, 1); // close recording
close_voiceproc();
}
else
{
voice_capidx = kmaudio_startCapture(micDeviceName, VOICE_SAMPRATE);
voice_pbidx = kmaudio_startPlayback(lsDeviceName, VOICE_SAMPRATE);
init_voiceproc();
}
}
// called from UDP callback ! DO NOT call any system functions
@ -527,35 +574,37 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
// reset liquid RX modem
tuning = 0;
resetModem();
io_clear_audio_fifos();
//io_clear_audio_fifos();
io_fifo_clear(voice_pbidx);
io_fifo_clear(voice_capidx);
return;
}
if (type == 21)
{
// set playback volume (in % 0..100)
io_setVolume(0,minfo);
io_setPBvolume(minfo);
return;
}
if (type == 22)
{
// set capture volume (in % 0..100)
io_setVolume(1,minfo);
io_setCAPvolume(minfo);
return;
}
if (type == 23)
{
// set playback volume (in % 0..100)
setVolume_voice(0, minfo);
io_setLSvolume(minfo);
return;
}
if (type == 24)
{
// set capture volume (in % 0..100)
setVolume_voice(1, minfo);
io_setMICvolume(minfo);
return;
}
@ -579,18 +628,7 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
//printf("LS:<%s> MIC:<%s> Mode:%d codec:%d\n", lsDeviceName, micDeviceName, VoiceAudioMode, codec);
// init voice audio
if (VoiceAudioMode == VOICEMODE_OFF)
{
io_saveStream(0.0f); // close recording
close_voiceproc();
io_close_voice();
}
else
{
init_voice_result = io_init_voice(lsDeviceName, micDeviceName);
init_voiceproc();
}
init_voice = 1;
return;
}
@ -681,7 +719,7 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
printf("data from app: wrong length:%d (should be %d)\n", len - 2, PAYLOADLEN);
return;
}
//if (getSending() == 1) return; // already sending (Array sending)
if (minfo == 0 || minfo == 3)
@ -696,6 +734,8 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
// one frame has 258 bytes, so we need for 6s: 6* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
toGR_sendData(pdata + 2, type, minfo,0);
int numframespreamble = 6 * ((caprate / txinterpolfactor) * bitsPerSymbol / 8) / 258 + 1;
if (type == 1)// BER Test
numframespreamble = 1;
for (int i = 0; i < numframespreamble; i++)
toGR_sendData(pdata + 2, type, minfo,1);
}
@ -743,8 +783,7 @@ void toGR_sendData(uint8_t* data, int type, int status, int repeat)
//showbytestring((char *)"BERtx: ", txdata, len);
if (txdata != NULL)
sendToModulator(txdata, len);
if (txdata != NULL) sendToModulator(txdata, len);
}
// called by liquid demodulator for received data

View File

@ -63,8 +63,9 @@
#include "udp.h"
#include "symboltracker.h"
#include "codec2.h"
#include "soundio.h"
#include "libkmaudio/soundio.h"
#include "baudot.h"
#include "libkmaudio/libkmaudio.h"
#define jpg_tempfilename "rxdata.jpg"
@ -125,7 +126,7 @@ void measure_speed_bps(int len);
void initFEC();
void GetFEC(uint8_t* txblock, int len, uint8_t* destArray);
int cfec_Reconstruct(uint8_t* darr, uint8_t* destination);
/*
void io_pb_write_fifo_clear();
int io_init_sound(char* pbname, char* capname);
int io_pb_fifo_freespace(int nolock);
@ -140,11 +141,28 @@ int io_pb_fifo_usedspace();
int io_cap_fifo_usedPercent();
int io_pb_read_fifo_num(float* data, int num);
void io_clear_audio_fifos();
int io_pb_fifo_usedBlocks();
void io_voice_init_pipes();
int io_mic_read_fifo(float* data);
void io_ls_write_fifo(float sample);
char* getDevID(char* devname, int io);
int io_init_voice(char* lsname, char* micname);
int min_int(int a, int b);
void io_close_voice();
int io_ls_read_fifo_num(float* data, int num);
void io_mic_write_fifo(float sample);
void write_sample_s16ne(char* ptr, double sample);
int io_ls_fifo_usedspace();
void write_sample_float32ne(char* ptr, double sample);
void io_clear_voice_fifos();
*/
void io_setPBvolume(int v);
void io_setCAPvolume(int v);
void io_setVolume(int pbcap, int v);
void io_setLSvolume(int v);
void io_setMICvolume(int v);
void setVolume_voice(int pbcap, int v);
void sendAnnouncement();
void sleep_ms(int ms);
@ -153,7 +171,7 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock);
void toGR_sendData(uint8_t* data, int type, int status, int repeat);
void modulator(uint8_t sym_in);
int io_pb_fifo_usedBlocks();
void init_dsp();
int demodulator();
void sendToModulator(uint8_t* d, int len);
@ -177,20 +195,6 @@ void closeAllandTerminate();
void close_voiceproc();
void close_codec2();
void io_voice_init_pipes();
int io_mic_read_fifo(float* data);
void io_ls_write_fifo(float sample);
void io_setLSvolume(int v);
void io_setMICvolume(int v);
char* getDevID(char* devname, int io);
int io_init_voice(char* lsname, char* micname);
int min_int(int a, int b);
void io_close_voice();
int io_ls_read_fifo_num(float* data, int num);
void io_mic_write_fifo(float sample);
void write_sample_s16ne(char* ptr, double sample);
int io_ls_fifo_usedspace();
void write_sample_float32ne(char* ptr, double sample);
SYMTRACK* km_symtrack_cccf_create( int _ftype,
unsigned int _k,
@ -202,9 +206,8 @@ void km_symtrack_cccf_set_bandwidth(SYMTRACK* , float _bw);
void km_symtrack_execute(SYMTRACK* ,liquid_float_complex _x, liquid_float_complex* _y, unsigned int* _ny, unsigned int* psym_out);
void km_symtrack_cccf_destroy(SYMTRACK*);
void io_saveStream(float f);
void io_saveStream(float *fa, int anz);
void playIntro();
void io_clear_voice_fifos();
float do_tuning(int send);
void init_tune();
float singleFrequency();
@ -215,7 +218,6 @@ void rtty_sendChar(int c);
void init_rtty();
int do_rtty();
void make_FFTdata(float f);
void getMax(float fv);
void close_rtty();
void close_a();
void rtty_modifyRXfreq(int);
@ -226,6 +228,8 @@ void rtty_rx_write_fifo(char c);
int rtty_rx_read_fifo(char* pc);
void clear_rtty_txfifo();
void fmtest();
void rtty_init_pipes();
void initVoice();
extern int speedmode;
@ -240,8 +244,6 @@ extern int UdpDataPort_ModemToApp;
extern int txinterpolfactor;
extern int rxPreInterpolfactor;
extern char appIP[20];
extern float softwareCAPvolume;
extern float softwarePBvolume;
extern int announcement;
extern int ann_running;
extern int transmissions;
@ -250,7 +252,6 @@ extern uint8_t maxLevel;
extern uint8_t maxTXLevel;
extern int VoiceAudioMode;
extern int opusbitrate;
extern int init_audio_result;
extern int init_voice_result;
extern int initialLSvol;
extern int initialMICvol;
@ -258,9 +259,6 @@ extern int codec;
extern int trigger_resetmodem;
extern int rxlevel_deteced;
extern int rx_in_sync;
extern float softwareMICvolume;
extern float softwareLSvolume;
extern int physRXcaprate;
extern int restart_modems;
extern int safemode;
extern char homepath[];
@ -272,6 +270,14 @@ extern int rtty_txoff;
extern int rtty_txidx;
extern int rtty_frequency;
extern int rtty_autosync;
extern int io_capidx;
extern int io_pbidx;
extern int voice_capidx;
extern int voice_pbidx;
extern float pbvol;
extern float capvol;
extern float lsvol;
extern float micvol;
#ifdef _LINUX_

View File

@ -225,17 +225,18 @@
<ItemGroup>
<ClInclude Include="baudot.h" />
<ClInclude Include="codec2.h" />
<ClInclude Include="endian.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="libkmaudio\endian.h" />
<ClInclude Include="libkmaudio\libkmaudio.h" />
<ClInclude Include="libkmaudio\soundio.h" />
<ClInclude Include="liquid.h" />
<ClInclude Include="opus.h" />
<ClInclude Include="opus_defines.h" />
<ClInclude Include="opus_types.h" />
<ClInclude Include="soundio.h" />
<ClInclude Include="symboltracker.h" />
<ClInclude Include="udp.h" />
</ItemGroup>
@ -247,20 +248,29 @@
<ClCompile Include="fec.cpp" />
<ClCompile Include="fft.cpp" />
<ClCompile Include="fifo.cpp" />
<ClCompile Include="fifo_voice.cpp" />
<ClCompile Include="frame_packer.cpp" />
<ClCompile Include="hsmodem.cpp" />
<ClCompile Include="libkmaudio\libkmaudio_capture.cpp" />
<ClCompile Include="libkmaudio\libkmaudio_capture_linux.cpp" />
<ClCompile Include="libkmaudio\libkmaudio_fifo.cpp" />
<ClCompile Include="libkmaudio\libkmaudio_getDevices.cpp" />
<ClCompile Include="libkmaudio\libkmaudio_getDevices_Linux.cpp" />
<ClCompile Include="libkmaudio\libkmaudio_init.cpp" />
<ClCompile Include="libkmaudio\libkmaudio_init_linux.cpp" />
<ClCompile Include="libkmaudio\libkmaudio_interface.cpp" />
<ClCompile Include="libkmaudio\libkmaudio_playback.cpp" />
<ClCompile Include="libkmaudio\libkmaudio_playback_linux.cpp" />
<ClCompile Include="libkmaudio\libkmaudio_resampler.cpp" />
<ClCompile Include="liquid_if.cpp" />
<ClCompile Include="main_helper.cpp" />
<ClCompile Include="rtty.cpp" />
<ClCompile Include="scrambler.cpp" />
<ClCompile Include="soundio.cpp" />
<ClCompile Include="speed.cpp" />
<ClCompile Include="symboltracker.cpp" />
<ClCompile Include="tuning.cpp" />
<ClCompile Include="udp.cpp" />
<ClCompile Include="voiceio.cpp" />
<ClCompile Include="voiceprocessor.cpp" />
<ClCompile Include="volume.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -57,27 +57,54 @@
<ClCompile Include="codec2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soundio.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="fifo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="announcement.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="fifo_voice.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="voiceio.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tuning.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rtty.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libkmaudio\libkmaudio_capture.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libkmaudio\libkmaudio_capture_linux.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libkmaudio\libkmaudio_fifo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libkmaudio\libkmaudio_getDevices.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libkmaudio\libkmaudio_getDevices_Linux.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libkmaudio\libkmaudio_init.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libkmaudio\libkmaudio_init_linux.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libkmaudio\libkmaudio_interface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libkmaudio\libkmaudio_playback.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libkmaudio\libkmaudio_playback_linux.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libkmaudio\libkmaudio_resampler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="volume.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="hsmodem.h">
@ -116,14 +143,17 @@
<ClInclude Include="codec2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soundio.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="endian.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="baudot.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="libkmaudio\libkmaudio.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="libkmaudio\soundio.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="libkmaudio\endian.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

97
hsmodem/libkmaudio/endian.h Executable file
View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of libsoundio, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef SOUNDIO_ENDIAN_H
#define SOUNDIO_ENDIAN_H
#if defined(__BIG_ENDIAN__)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__ARMEB__)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__THUMBEB__)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__AARCH64EB__)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(_MIPSEB)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__MIPSEB)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__MIPSEB__)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(_BIG_ENDIAN)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__sparc)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__sparc__)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(_POWER)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__powerpc__)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__ppc__)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__hpux)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__hppa)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(_POWER)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__s390__)
#define SOUNDIO_OS_BIG_ENDIAN
#elif defined(__LITTLE_ENDIAN__)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__ARMEL__)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__THUMBEL__)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__AARCH64EL__)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(_MIPSEL)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__MIPSEL)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__MIPSEL__)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(_LITTLE_ENDIAN)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__i386__)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__alpha__)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__ia64)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__ia64__)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(_M_IX86)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(_M_IA64)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(_M_ALPHA)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__amd64)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__amd64__)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(_M_AMD64)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__x86_64)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__x86_64__)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(_M_X64)
#define SOUNDIO_OS_LITTLE_ENDIAN
#elif defined(__bfin__)
#define SOUNDIO_OS_LITTLE_ENDIAN
#else
#error unable to detect endianness
#endif
#endif

170
hsmodem/libkmaudio/libkmaudio.cpp Executable file
View File

@ -0,0 +1,170 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
* Usage Example: see main() in this file
*
* 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.
*
* libkmaudio.cpp ... main() for test purposes only
* usually this library is linked to another program, in this case
* comment-out #define LIBTEST
*
*/
#include "libkmaudio.h"
int kmaudio_getDeviceList_test();
int keeprunning = 1;
/*
* main()
* for testing purposes only
* for library generation comment out: LIBTEST
*/
#define LIBTEST
#ifdef LIBTEST
int main()
{
// initialize sound system
// must be called once after program start
// if called during program run, this will reset the sound system, so better don't do it
kmaudio_init();
// read list of devices
// call as often as needed
// if a user pluggs-in an USB device on the fly then the running stream may
// be redirected by the OS. In this case closing/opening the stream
// may be required.
kmaudio_getDeviceList();
// start capture and/or playback streams
// Parameter: the device name and the sample rate (44100 or 48000 are supported)
// these function return the fifo-index, which is used to access the data in the
// coresponding fifo
int capidx = kmaudio_startCapture((char *)"Line 2 (Virtual Audio Cable)", 48000);
int pbidx = kmaudio_startPlayback((char *)"Line 2 (Virtual Audio Cable)", 48000);
// int ucapidx = kmaudio_startCapture((char*)"Mikrofon (2- USB Advanced Audio Device)", 48000);
// int upbidx = kmaudio_startPlayback((char*)"Lautsprecher (2- USB Advanced Audio Device)", 48000);
//int capidx = kmaudio_startCapture((char*)"USB Audio CODEC: - (hw:2,0)", 48000);
// int capidx = kmaudio_startCapture((char*)"Mikrofon (1080P Webcam)", 48000);
// int pbidx = kmaudio_startPlayback((char*)"Lautsprecher (2- High Definition Audio Device)", 48000);
//int pbidx = kmaudio_startPlayback((char*)"USB Audio CODEC: - (hw:2,0)", 48000);
//int capidx = kmaudio_startCapture((char*)"PCM2902 Audio Codec Analog Stereo", 48000);
//int pbidx = kmaudio_startPlayback((char*)"PCM2902 Audio Codec Analog Stereo", 48000);
//int ucapidx = kmaudio_startCapture((char*)"USB Advanced Audio Device Analog Stereo", 48000);
//int upbidx = kmaudio_startPlayback((char*)"USB Advanced Audio Device Analog Stereo", 48000);
if (1)
{
int16_t f[1100]; // 1.1 x need rate to have reserve for resampler
int16_t fv = -32768;
/*for (int i = 0; i < 48000; i++)
{
kmaudio_playsamples(pbidx, &fv, 1, 1);
if (++fv >= 32768) fv = -32768;
}*/
while (1)
{
int av = io_fifo_elems_avail(pbidx);
if (av < 10000)
{
//printf("av: %d\n", av);
for (int i = 0; i < 10000; i++)
{
kmaudio_playsamples(pbidx, &fv, 1, 1);
if (++fv >= 32768) fv = -32768;
//if (fv >= -1010 && fv <= -1000) fv = 1000; // avoid 0, for dropout testing
}
av = io_fifo_elems_avail(pbidx);
//printf("ava: %d\n", av);
}
int anz = kmaudio_readsamples(capidx, f, 20, 1, 0);
if (anz > 0)
{
/*char s[200];
s[0] = 0;
for(int i=0; i<anz; i++)
sprintf(s+strlen(s),"%d ", f[i]);
printf("%s\n",s);*/
static int16_t lf=-32768;
for (int i = 0; i < anz; i++)
{
if (f[i] != lf)
{
printf("error: %d %d\n",f[i], lf);
lf = f[i];
}
lf++;
}
}
}
/*
while (1)
{
// make a loop: record from Mic and play to Speaker
int done = 0;
// read samples from the capture fifo
int anz = kmaudio_readsamples(capidx, f, 1000, 1.0f, 0);
if (anz > 0)
{
// if samples are available, send them to playback fifo
//printf("write %d samples from %d to %d\n", anz, capidx, pbidx);
kmaudio_playsamples(pbidx, f, anz,1.0f);
done = 1;
}
int uanz = kmaudio_readsamples(ucapidx, f, 1000, 1.0f, 0);
if (uanz > 0)
{
// if samples are available, send them to playback fifo
//printf("write %d samples from %d to %d\n", anz, capidx, pbidx);
kmaudio_playsamples(upbidx, f, uanz, 1.0f);
done = 1;
}
if (done == 0)
{
// if no samples are available make a short break
// this is important to prevent excessive CPU usage
sleep_ms(10);
}
}*/
}
else
printf("device not available. Ending program\n");
// free resources. This will never happen in this example
// but should be done in the final program
kmaudio_close();
return 0;
}
#endif // LIBTEST

252
hsmodem/libkmaudio/libkmaudio.h Executable file
View File

@ -0,0 +1,252 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* 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.
*/
#pragma once
#ifdef WIN32
// ignore senseless warnings invented by M$ to confuse developers
#pragma warning( disable : 4091 )
#pragma warning( disable : 4003 )
#endif
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <wchar.h>
#ifdef WIN32
#include "Winsock2.h"
#include "io.h"
#include <Windows.h>
#include <iostream>
#include <process.h>
#include <Tlhelp32.h>
#include <winbase.h>
#include <Shlobj.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include "portaudio.h"
#include "pa_win_wasapi.h"
#pragma comment(lib, "portaudio_x86.lib")
#pragma comment(lib, "libliquid.lib")
#else
#include <sys/socket.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <sys/file.h>
#include <pthread.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <pwd.h>
#include <math.h>
#include "soundio.h"
#endif
#include "liquid.h"
/*
* Sample usage:
* init sound system
* 1. kmaudio_init();
* 2. kmaudio_getDeviceList();
*
* start a capture and a playback stream
* 3. kmaudio_startCapture() using a device name returned by io_getAudioDevicelist()
* 4. kmaudio_startPlayback() using a device name returned by io_getAudioDevicelist()
*
* now everything runs in the background, no more need for the user program
* to handle sound specific data
* now we can read/write sound samples as needed by our application
* as an example: get sound from microphone and send to speaker
* process in a loop:
* 5. kmaudio_readsamples()
* 6. kmaudio_playsamples()
*
* for a working example see main(), you will need to
* replace the device names with the names in your computer
*/
/*
* initialize the audio library, create required processes
* call only once when your application starts
* returns: 0 = OK, -1 = error
*/
int kmaudio_init();
/*
* closes and frees all resources
* call only when the application exits
*/
void kmaudio_close();
/*
* read a list of all available audio devices into devlist
* the list can then be read by calling io_getAudioDevicelist()
* call any time to find new plugged in/out devices
* returns: 0=OK, -1 if error
*/
int kmaudio_getDeviceList();
/*
* starts a capturing stream from devname with samprate
* returns: id of the capture stream or -1 = error
*/
int kmaudio_startCapture(char* devname, int samprate);
/*
* starts a playback stream to devname with samprate
* returns: id of the playback stream or -1 = error
*/
int kmaudio_startPlayback(char* devname, int samprate);
/*
* plays len samples from psamp to device id
* returns: 0=ok, -1=error
* id ... device id returned by kmaudio_startPlayback
* psamp ... float array of length len with the audio data (mono)
* len ... number of float values in psamp
* volume ... 0.0f..2.0f will be multiplied with the output sample
*/
int kmaudio_playsamples(int id, float* psamp, int len, float volume);
/*
* reads len samples from device id into psamp
* returns: 0=ok, -1=error
* id ... device id returned by kmaudio_startCapture
* psamp ... float array of length len getting the audio data (mono)
* len ... number of float values to write into psamp
* volume ... 0.0f..2.0f will be multiplied with the input sample
* wait ... 1=wait for data, 0=return if not enough data available (in this case psamp will return 0,0,0...)
*/
int kmaudio_readsamples(int id, float* psamp, int len, float volume, int wait);
/*
* reads the names of detected sound devices
* *len...length of the returned string
* returns: pointer to device string
* Format of the device string:
* first byte = 3 ... ID of this string, followed by pure text:
* Active status of the following device "0" or "1"
* Name of playback devices, followed by ~
* separator ^
* Active status of the following device "0" or "1"
* Name of capture devices, followed by ~
* these names are used for calls to kmaudio_startCapture and kmaudio_startPlayback
* to select the device
*/
uint8_t* io_getAudioDevicelist(int* len);
/*
* returns the max level (within 1 second) of this stream in % (0..100)
* if the level >= 100 the signal will get clipped and distorted
*/
uint8_t kmaudio_maxlevel(int id);
int io_fifo_freespace(int pipenum);
int io_fifo_usedspace(int pipenum);
void io_fifo_clear(int pipenum);
int io_fifo_usedpercent(int pipenum);
// -------- functions for internal use only --------
#define MAXDEVICES 200
#define MAXDEVNAMELENGTH 150
typedef struct _DEVLIST_ {
int index = 0; // index to this list
int active = 0; // 1=device valid, 0=possibly disconencted
char name[MAXDEVNAMELENGTH] = { 0 };// real name
int in_out = 0; // 0=capture device, 1=playback device, 2=both
int supports_44100 = 0; // 1 if supported
int supports_48000 = 0; // 1 if supported
int requested_samprate = 0; // sample rate requested by caller
int real_samprate = 0; // real sample rate of the device
int working = 0; // 0=not running, 1=initialized and working
#ifdef WIN32 // Windows using portaudio
int devnum = -1; // port audio device number
PaStreamParameters inputParameters;
PaStreamParameters outputParameters;
PaStream* capStream = NULL;
PaStream* pbStream = NULL;
#else // Linux using libsoundio
struct SoundIoDevice* io_pb_device = NULL;
struct SoundIoDevice* io_cap_device = NULL;
struct SoundIoInStream* instream = NULL;
struct SoundIoOutStream* outstream = NULL;
int stereo_mono = 2; // 1=mono, 2=stereo
char id[1000] = { 0 };
#endif
} DEVLIST;
int searchDevice(char* devname, int io);
void measure_speed_bps(int len);
void sleep_ms(int ms);
void io_write_fifo(int pipenum, float sample);
void io_write_fifo_short(int pipenum, int16_t sample);
void io_fifo_clear(int pipenum);
void init_pipes();
int io_read_fifo_num(int pipenum, float* data, int num);
int io_read_fifo(int pipenum, float* data);
int getRealSamprate(int idx);
int io_fifo_elems_avail(int pipenum);
void sleep_ms(int ms);
void io_buildAudioDevString();
void resampler_create(int devidx);
float* resample(int id, float* psamp, int len, int* pnewlen);
uint64_t getms();
void init_maxarray();
void kmaudio_detectDropouts(int id);
int io_read_fifo_num_short(int pipenum, int16_t* data, int num);
extern DEVLIST devlist[MAXDEVICES];
extern int devanz;
extern int keeprunning;
#ifndef WIN32 // Linux
int kmaudio_init_linux();
void kmaudio_close_linux();
char* getDevID(char* devname, int io, int* pidx);
extern struct SoundIo* soundio;
#endif // ndef WIN32

View File

@ -0,0 +1,152 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
*
* 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.
*
* libkmaudio_capture.cpp ...
* starts a portaudio capture stream and a callback routine. Writes the
* received audio samples into the fifo (Windows only)
*/
#include "libkmaudio.h"
#define FRAMES_PER_BUFFER 512
int recordCallback(const void* inputBuffer, void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData);
int kmaudio_startCapture(char* devname, int samprate)
{
printf("Start request for CAP stream:%s\n", devname);
if (devname == NULL || strlen(devname) < 3) // no devices defined yet
{
printf("no capture devices specified\n");
return -1;
}
int idx = searchDevice(devname, 0);
if (idx == -1)
{
printf("Device:<%s> not found\n", devname);
return -1;
}
devlist[idx].working = 0;
if (devlist[idx].capStream != NULL)
{
printf("Closing old CAP stream:%s [%d]\n", devname, idx);
Pa_CloseStream(devlist[idx].capStream);
devlist[idx].capStream = NULL;
}
printf("Starting CAP stream:%s [%d]\n", devname, idx);
io_fifo_clear(idx);
devlist[idx].requested_samprate = samprate;
if(getRealSamprate(idx) == -1)
{
printf("Samplerate %d not supported by device:<%s>\n", samprate, devname);
return -1;
}
if (devlist[idx].requested_samprate != devlist[idx].real_samprate)
resampler_create(idx);
struct PaWasapiStreamInfo wasapiInfo;
memset(&wasapiInfo, 0, sizeof(PaWasapiStreamInfo));
wasapiInfo.size = sizeof(PaWasapiStreamInfo);
wasapiInfo.hostApiType = paWASAPI;
wasapiInfo.version = 1;
wasapiInfo.flags = (paWinWasapiExclusive | paWinWasapiThreadPriority);
wasapiInfo.threadPriority = eThreadPriorityProAudio;
devlist[idx].inputParameters.hostApiSpecificStreamInfo = (&wasapiInfo);
int e = Pa_IsFormatSupported(&devlist[idx].inputParameters, NULL, (double)devlist[idx].real_samprate);
printf("err:%d device:%d PAdev:%d samprate: %f\n", e,idx, devlist[idx].devnum,(double)devlist[idx].real_samprate);
devlist[idx].index = idx;
int err = Pa_OpenStream(
&devlist[idx].capStream,
&devlist[idx].inputParameters,
NULL,
(double)devlist[idx].real_samprate,
FRAMES_PER_BUFFER,
paClipOff,
recordCallback,
&(devlist[idx].index));
if (err != paNoError)
{
printf("cannot open capture stream for device:<%s> %d\n", devname,err);
return -1;
}
err = Pa_StartStream(devlist[idx].capStream);
if (err != paNoError)
{
printf("cannot start capture stream for device:<%s>\n", devname);
return -1;
}
printf("Capture started sucessfully\n");
devlist[idx].working = 1;
return idx;
}
int recordCallback( const void* inputBuffer,
void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData)
{
const int16_t* rptr = (const int16_t*)inputBuffer;
int devidx = *((int *)userData);
int chans = devlist[devidx].inputParameters.channelCount;
//printf("%ld captured %d frames. Flag: %X\n", (long)rptr,framesPerBuffer, statusFlags);
//measure_speed_bps(framesPerBuffer);
//printf("%d %d\n", chans, rptr[0]);
for (unsigned int i = 0; i < framesPerBuffer; i++)
io_write_fifo_short(devidx, rptr[i * chans]);
// Prevent unused variable warnings
(void)outputBuffer;
(void)timeInfo;
(void)statusFlags;
if(keeprunning == 1)
return paContinue;
return paComplete;
}

View File

@ -0,0 +1,212 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
*
* 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.
*
* libkmaudio_capture.cpp ...
* starts a libsoundio capture stream and a callback routine. Writes the
* received audio samples into the fifo (Linux only)
*/
#ifndef WIN32
#include "libkmaudio.h"
char* getDevID(char* devname, int io, int *pidx)
{
for (int i = 0; i < devanz; i++)
{
//printf("%s: %d %d\n", devlist[i].name, io, devlist[i].in_out);
if (!strcmp(devname, devlist[i].name) && io == devlist[i].in_out)
{
*pidx = i;
return devlist[i].id;
}
}
return NULL;
}
int min_int(int a, int b)
{
return (a < b) ? a : b;
}
void read_callback(struct SoundIoInStream* instream, int frame_count_min, int frame_count_max)
{
int err;
if (instream == NULL || soundio == NULL) return;
//printf("cap: %d %d\n", frame_count_min, frame_count_max);
//int chans = instream->layout.channel_count;
//printf("cap:%d\n", instream->sample_rate);
int idx = *((int *)(instream->userdata));
struct SoundIoChannelArea* areas;
// samples are in areas.ptr
int frames_left = frame_count_max; // take all
while (keeprunning)
{
int frame_count = frames_left;
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
{
fprintf(stderr, "begin read error: %s", soundio_strerror(err));
return;
}
if (!frame_count)
break;
//printf("write %d samples to fifo %d. Channels:%d\n", frame_count, idx, instream->layout.channel_count);
for (int frame = 0; frame < frame_count; frame += 1)
{
for (int ch = 0; ch < instream->layout.channel_count; ch += 1)
{
float frxdata;
memcpy(&frxdata, areas[ch].ptr, instream->bytes_per_sample);
areas[ch].ptr += areas[ch].step;
if (ch == 0)
{
io_write_fifo(idx, frxdata);
}
}
}
//measure_speed_bps(frame_count);
if ((err = soundio_instream_end_read(instream)))
{
printf("end read error: %s", soundio_strerror(err));
return;
}
frames_left -= frame_count;
if (frames_left <= 0)
break;
}
}
void overflow_callback(struct SoundIoInStream* instream)
{
static int count = 0;
printf("overflow %d\n", ++count);
}
int kmaudio_startCapture(char* devname, int samprate)
{
printf("Start request for CAP stream:%s\n", devname);
if (devname == NULL || strlen(devname) < 3) // no devices defined yet
{
printf("no capture devices specified\n");
return -1;
}
int idx = 0; // index into devlist
char* capdevid = getDevID(devname, 0, &idx);
if (capdevid == NULL) return -1;
// if an old stream is open, close it
if (devlist[idx].instream != NULL)
{
printf("Closing old CAP stream:%s [%d]\n", devname, idx);
soundio_instream_destroy(devlist[idx].instream);
devlist[idx].instream = NULL;
}
printf("Starting CAP stream:%s [%d]\n", devname, idx);
io_fifo_clear(idx);
devlist[idx].working = 0;
// define the capture device
soundio_flush_events(soundio);
for (int i = 0; i < soundio_input_device_count(soundio); i++)
{
devlist[idx].io_cap_device = NULL;
struct SoundIoDevice* device = soundio_get_input_device(soundio, i);
if (strcmp(device->id, capdevid) == 0)
{
devlist[idx].io_cap_device = device;
break;
}
soundio_device_unref(device);
}
if (!devlist[idx].io_cap_device)
{
printf("Invalid device id: %s\n", capdevid);
return -1;
}
if (devlist[idx].io_cap_device->probe_error)
{
printf("Unable to probe device: %s\n", soundio_strerror(devlist[idx].io_cap_device->probe_error));
return -1;
}
// create capture callback
devlist[idx].instream = soundio_instream_create(devlist[idx].io_cap_device);
if (!devlist[idx].instream) {
printf("capture: out of memory\n");
return -1;
}
devlist[idx].requested_samprate = samprate;
if (getRealSamprate(idx) == -1)
{
printf("Samplerate %d not supported by device:<%s>\n", samprate, devname);
return -1;
}
if (devlist[idx].requested_samprate != devlist[idx].real_samprate)
resampler_create(idx);
devlist[idx].instream->format = SoundIoFormatFloat32NE;
devlist[idx].instream->sample_rate = devlist[idx].real_samprate;
devlist[idx].instream->software_latency = 0.1f;
devlist[idx].instream->read_callback = read_callback;
devlist[idx].instream->overflow_callback = overflow_callback;
devlist[idx].instream->userdata = &(devlist[idx].index);
int err = 0;
if ((err = soundio_instream_open(devlist[idx].instream))) {
printf("unable to open input stream: %d: %s", err, soundio_strerror(err));
return -1;
}
if ((err = soundio_instream_start(devlist[idx].instream))) {
printf("unable to start input device: %s", soundio_strerror(err));
return -1;
}
printf("selected CAPTURE device:\nname:%s\nid :%s\n", devlist[idx].name, capdevid);
printf("physical capture rate:%d, requested capture rate:%d\n", devlist[idx].real_samprate, devlist[idx].requested_samprate);
printf("format: %s\n\n", soundio_format_string(devlist[idx].instream->format));
devlist[idx].working = 1;
return idx;
}
#endif // #ifndef WIN32

View File

@ -0,0 +1,236 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
*
* 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.
*
* libkmaudio_fifo.cpp ... thread safe FIFOs, used to interface the
* audio callback routines to the other program
*
*/
#include "libkmaudio.h"
#define NUM_OF_PIPES 20
#ifdef WIN32
CRITICAL_SECTION crit_sec[NUM_OF_PIPES];
#define LOCK(pn) EnterCriticalSection(&(crit_sec[pn]))
void UNLOCK(int pn)
{
if (&(crit_sec[pn]) != NULL)
LeaveCriticalSection(&(crit_sec[pn]));
}
#else
pthread_mutex_t crit_sec[NUM_OF_PIPES];
#define LOCK(pn) pthread_mutex_lock(&(crit_sec[pn]))
#define UNLOCK(pn) pthread_mutex_unlock(&(crit_sec[pn]))
#endif
#define AUDIO_FIFOFLEN 480000 // 10s at 48k samprate (minimum is number of preambles)
int io_wridx[NUM_OF_PIPES];
int io_rdidx[NUM_OF_PIPES];
int16_t io_buffer[NUM_OF_PIPES][AUDIO_FIFOFLEN];
void init_pipes()
{
// init pipes only once
static int f = 1;
if (f)
{
f = 0;
for (int i = 0; i < NUM_OF_PIPES; i++)
{
#ifdef WIN32
if (&(crit_sec[i]) != NULL) DeleteCriticalSection(&(crit_sec[i]));
InitializeCriticalSection(&(crit_sec[i]));
#else
if (&(crit_sec[i]) != NULL) pthread_mutex_destroy(&(crit_sec[i]));
pthread_mutex_init(&(crit_sec[i]), NULL);
#endif
}
}
for (int i = 0; i < NUM_OF_PIPES; i++)
io_fifo_clear(i);
}
// write one sample into the fifo
// ignore data if the fifo is full
void io_write_fifo(int pipenum, float sample)
{
LOCK(pipenum);
if (((io_wridx[pipenum] + 1) % AUDIO_FIFOFLEN) == io_rdidx[pipenum])
{
//printf("cannot float WRITE fifo %d full\n",pipenum);
UNLOCK(pipenum);
return;
}
io_buffer[pipenum][io_wridx[pipenum]] = (int16_t)(sample * 32768.0f);
if (++io_wridx[pipenum] >= AUDIO_FIFOFLEN) io_wridx[pipenum] = 0;
UNLOCK(pipenum);
}
void io_write_fifo_short(int pipenum, int16_t sample)
{
LOCK(pipenum);
if (((io_wridx[pipenum] + 1) % AUDIO_FIFOFLEN) == io_rdidx[pipenum])
{
//printf("cannot short WRITE fifo %d full\n", pipenum);
UNLOCK(pipenum);
return;
}
io_buffer[pipenum][io_wridx[pipenum]] = sample;
if (++io_wridx[pipenum] >= AUDIO_FIFOFLEN) io_wridx[pipenum] = 0;
UNLOCK(pipenum);
}
int io_read_fifo(int pipenum, float* data)
{
LOCK(pipenum);
if (io_rdidx[pipenum] == io_wridx[pipenum])
{
// Fifo empty, no data available
UNLOCK(pipenum);
return 0;
}
int16_t id = io_buffer[pipenum][io_rdidx[pipenum]];
if (++io_rdidx[pipenum] >= AUDIO_FIFOFLEN) io_rdidx[pipenum] = 0;
UNLOCK(pipenum);
*data = (float)id / 32768;
return 1;
}
// read num elements
// if num elems not avail, return all what fifo has stored
int io_read_fifo_num(int pipenum, float* data, int num)
{
LOCK(pipenum);
int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN;
elemInFifo -= 1;
/*if (num > elemInFifo)
{
// Fifo not enough data available
//printf("only %d elements available\n", elemInFifo);
UNLOCK(pipenum);
return 0;
}*/
if (num > elemInFifo) num = elemInFifo;
int16_t id;
for (int i = 0; i < num; i++)
{
id = io_buffer[pipenum][io_rdidx[pipenum]];
*data++ = (float)id / 32768;
if (++io_rdidx[pipenum] >= AUDIO_FIFOFLEN) io_rdidx[pipenum] = 0;
}
UNLOCK(pipenum);
return num;
}
int io_read_fifo_num_short(int pipenum, int16_t* data, int num)
{
LOCK(pipenum);
int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN;
elemInFifo -= 1;
/*if (num > elemInFifo)
{
// Fifo not enough data available
//printf("only %d elements available\n", elemInFifo);
UNLOCK(pipenum);
return 0;
}*/
if (num > elemInFifo) num = elemInFifo;
for (int i = 0; i < num; i++)
{
*data++ = io_buffer[pipenum][io_rdidx[pipenum]];
if (++io_rdidx[pipenum] >= AUDIO_FIFOFLEN) io_rdidx[pipenum] = 0;
}
UNLOCK(pipenum);
return num;
}
void io_fifo_clear(int pipenum)
{
io_wridx[pipenum] = io_rdidx[pipenum] = 0;
}
int io_fifo_freespace(int pipenum)
{
int freebuf = 0;
LOCK(pipenum);
int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN;
freebuf = AUDIO_FIFOFLEN - elemInFifo -1;
UNLOCK(pipenum);
return freebuf;
}
int io_fifo_elems_avail(int pipenum)
{
int elems = 0;
LOCK(pipenum);
elems = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN;
UNLOCK(pipenum);
elems -= 10;
return elems;
}
int io_fifo_usedspace(int pipenum)
{
return AUDIO_FIFOFLEN - io_fifo_freespace(pipenum);
}
int io_fifo_usedpercent(int pipenum)
{
int used = AUDIO_FIFOFLEN - io_fifo_freespace(pipenum);
int percent = (used * 100) / AUDIO_FIFOFLEN;
//printf("idx:%d used:%d size:%d percent:%d\n", pipenum, used, AUDIO_FIFOFLEN, percent);
return percent;
}

View File

@ -0,0 +1,293 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
*
* 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.
*
* libkmaudio_getDevices.cpp
* read audio device list via portaudio (which is only used for Windows)
* prepare a device name string which can be read by another program
* in order to present the devices to use user for selection
*
*/
#include "libkmaudio.h"
void io_buildAudioDevString();
// number of detected devices, updated after a call to kmaudio_getDeviceList()
int devanz = 0;
// devlist contains all information for all detected devices
// the list is filled by a call to kmaudio_getDeviceList()
DEVLIST devlist[MAXDEVICES];
double latency = 0.2; // WASAPI latency in seconds
#ifdef WIN32
/*static double standardSampleRates[] = {
8000.0, 9600.0, 11025.0, 12000.0, 16000.0,
22050.0, 24000.0, 32000.0, 44100.0, 48000.0,
88200.0, 96000.0, 192000.0, -1 };*/
static double standardSampleRates[] = {44100.0, 48000.0, -1};
int getDevlistIndex(const char* name, int ichans, int ochans)
{
for (int i = 0; i < devanz; i++)
{
// check if already exists
if (!strcmp(devlist[i].name, name) &&
devlist[i].inputParameters.channelCount == ichans &&
devlist[i].outputParameters.channelCount == ochans)
return i;
}
int newidx = devanz;
devanz++;
//printf("New Dev:%s Idx:%d\n", name, newidx);
return newidx;
}
int kmaudio_getDeviceList()
{
int numDevices = Pa_GetDeviceCount();
if (numDevices < 0)
{
printf("ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices);
return -1;
}
//printf("%d Devices found\n", numDevices);
for (int i = 0; i < devanz; i++)
devlist[i].active = 0;
int didx;
for (int i = 0; i < numDevices; i++)
{
const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(i);
const PaHostApiInfo *ai = Pa_GetHostApiInfo(deviceInfo->hostApi);
// Windows: use WASAPI devices only
if (strstr(ai->name, "WASAPI") != NULL)
{
didx = getDevlistIndex(deviceInfo->name, deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels);
devlist[didx].devnum = i;
snprintf(devlist[didx].name, MAXDEVNAMELENGTH - 1, "%s", deviceInfo->name);
//printf("------%s-------\n", deviceInfo->name);
devlist[didx].inputParameters.device = i;
devlist[didx].inputParameters.channelCount = deviceInfo->maxInputChannels;
devlist[didx].inputParameters.sampleFormat = paInt16;
devlist[didx].inputParameters.suggestedLatency = latency;
devlist[didx].inputParameters.hostApiSpecificStreamInfo = NULL;
devlist[didx].outputParameters.device = i;
devlist[didx].outputParameters.channelCount = deviceInfo->maxOutputChannels;
devlist[didx].outputParameters.sampleFormat = paInt16;
devlist[didx].outputParameters.suggestedLatency = latency;
devlist[didx].outputParameters.hostApiSpecificStreamInfo = NULL;
if (devlist[didx].inputParameters.channelCount > 0 && devlist[devanz].outputParameters.channelCount > 0)
devlist[didx].in_out = 2;
else if (devlist[didx].inputParameters.channelCount > 0)
devlist[didx].in_out = 0;
else if (devlist[didx].outputParameters.channelCount > 0)
devlist[didx].in_out = 1;
devlist[didx].index = didx;
devlist[didx].active = 1;
for (int j = 0; standardSampleRates[j] > 0; j++)
{
PaError err = 0;
//if (devlist[didx].inputParameters.channelCount > 0 && devlist[didx].outputParameters.channelCount > 0)
// err = Pa_IsFormatSupported(&devlist[didx].inputParameters, &devlist[didx].outputParameters, standardSampleRates[j]);
if (devlist[didx].inputParameters.channelCount > 0)
err = Pa_IsFormatSupported(&devlist[didx].inputParameters, NULL, standardSampleRates[j]);
if (devlist[didx].outputParameters.channelCount > 0)
err = Pa_IsFormatSupported(NULL, &devlist[didx].outputParameters, standardSampleRates[j]);
// portaudio cannot detect if a device was removed, instead it delivers errors
if (err == paInvalidDevice)
devlist[didx].active = 0;
else if (err == paFormatIsSupported)
{
if (j == 0) devlist[didx].supports_44100 = 1;
if (j == 1) devlist[didx].supports_48000 = 1;
}
}
}
}
io_buildAudioDevString();
// close stream if a device does not exist any more
for (int i = 0; i < devanz; i++)
{
if (devlist[i].active == 0)
{
if (devlist[i].capStream != NULL)
{
printf("capture device %s disconnected, stop stream\n", devlist[i].name);
Pa_CloseStream(devlist[i].capStream);
devlist[i].capStream = NULL;
devlist[i].working = 0;
}
if (devlist[i].pbStream != NULL)
{
printf("playback device %s disconnected, stop stream\n", devlist[i].name);
Pa_CloseStream(devlist[i].pbStream);
devlist[i].pbStream = NULL;
devlist[i].working = 0;
}
}
}
static int csum = 0;
int sum = 0;
uint8_t* p = (uint8_t*)&(devlist[0].index);
for (int i = 0; i < (int)sizeof(devlist); i++)
sum += *p++;
if (csum != sum)
{
csum = sum;
printf("Windows Devices found:\n");
for (int i = 0; i < devanz; i++)
{
printf("Portaudio ID: %d\n", devlist[i].index);
printf("Name: %s\n", devlist[i].name);
printf("Cap/PB: %d\n", devlist[i].in_out);
printf("Channels: i:%d o:%d\n", devlist[i].inputParameters.channelCount, devlist[i].outputParameters.channelCount);
printf("SR 44100: %d\n", devlist[i].supports_44100);
printf("SR 48000: %d\n", devlist[i].supports_48000);
printf("is active: %s\n", devlist[i].active ? "yes" : "no");
}
}
return 0;
}
#endif //WIN32
// find a device in devlist
// returns: list index or -1 if error
int searchDevice(char* devname, int io)
{
for (int i = 0; i < devanz; i++)
{
if (strcmp(devname, devlist[i].name) == 0 && (devlist[i].in_out == io || devlist[i].in_out == 2))
return i;
}
return -1;
}
// choose physical, real sample rate for a device
// returns: 0=ok, -1=error: no sample rate supported
int getRealSamprate(int idx)
{
if (devlist[idx].requested_samprate == 44100)
{
if (devlist[idx].supports_44100) devlist[idx].real_samprate = 44100;
else if (devlist[idx].supports_48000) devlist[idx].real_samprate = 48000;
else return -1;
}
else if (devlist[idx].requested_samprate == 48000)
{
if (devlist[idx].supports_48000) devlist[idx].real_samprate = 48000;
else if (devlist[idx].supports_44100) devlist[idx].real_samprate = 44100;
else return -1;
}
return 0;
}
// build string of audio device name, to be sent to application as response to Broadcast search
// starting with PB devices, sperarator ^, capture devices
// separator between devices: ~
// the first character is 0 or 1 and does not belong to the device name
// it shows if this device was sucessfully started and is currently running (="1")
#define MAXDEVSTRLEN (MAXDEVICES * (MAXDEVNAMELENGTH + 2) + 10)
uint8_t io_devstring[MAXDEVSTRLEN];
void io_buildAudioDevString()
{
memset(io_devstring, 0, sizeof(io_devstring));
io_devstring[0] = ' '; // placeholder for ID for this UDP message
// playback devices
for (int i = 0; i < devanz; i++)
{
if (devlist[i].active == 0) continue;
if (strlen((char *)io_devstring) > MAXDEVSTRLEN)
{
printf("io_devstring too small:%d / %d. Serious error, abort program\n", MAXDEVSTRLEN, (int)strlen((char*)io_devstring));
exit(0);
}
if (devlist[i].in_out == 1)
{
strcat((char*)io_devstring, devlist[i].working?"1":"0");
strcat((char*)io_devstring, devlist[i].name);
strcat((char*)io_devstring, "~"); // audio device separator
}
}
strcat((char*)(io_devstring + 1), "^"); // PB, CAP separator
// capture devices
for (int i = 0; i < devanz; i++)
{
if (devlist[i].active == 0) continue;
if (strlen((char*)io_devstring) > MAXDEVSTRLEN)
{
printf("io_devstring too small:%d / %d. Serious error, abort program\n", MAXDEVSTRLEN, (int)strlen((char*)io_devstring));
exit(0);
}
if (devlist[i].in_out == 0)
{
strcat((char*)io_devstring, devlist[i].working ? "1" : "0");
strcat((char*)io_devstring, devlist[i].name);
strcat((char*)io_devstring, "~"); // audio device separator
}
}
//printf("<%s>\n", (char *)io_devstring);
io_devstring[0] = 3; // ID for this message
}
uint8_t* io_getAudioDevicelist(int* len)
{
*len = strlen((char*)(io_devstring + 1)) + 1;
return io_devstring;
}

View File

@ -0,0 +1,217 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
*
* 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.
*
* libkmaudio_getDevices_linux.cpp
* like libkmaudio_getDevices.cpp, but uses libsoundio under Linux
* to get the device list. Portaudio does not work under Linux because
* it does not support pulseaudio. Therefore the linux functions
* use libsoundio
*
*/
#ifndef WIN32 // Linux
#include "libkmaudio.h"
int scan_devices();
int kmaudio_getDeviceList()
{
if (soundio == NULL)
{
printf("kmaudio_getDeviceList: soundio not initialized\n");
return -1;
}
soundio_flush_events(soundio); // to get actual data
if (scan_devices() == -1) // read devices
{
printf("cannot read audio devices\n");
return -1;
}
io_buildAudioDevString();
// close stream if a device does not exist any more
for (int i = 0; i < devanz; i++)
{
if (devlist[i].active == 0)
{
if (devlist[i].instream != NULL)
{
printf("capture device %s disconnected, stop stream\n", devlist[i].name);
soundio_instream_destroy(devlist[i].instream);
devlist[i].instream = NULL;
devlist[i].working = 0;
}
if(devlist[i].outstream != NULL)
{
printf("playback device %s disconnected, stop stream\n", devlist[i].name);
soundio_outstream_destroy(devlist[i].outstream);
devlist[i].outstream = NULL;
devlist[i].working = 0;
}
}
}
static int csum = 0;
int sum = 0;
uint8_t* p = (uint8_t*)&(devlist[0].index);
for (int i = 0; i < (int)sizeof(devlist); i++)
sum += *p++;
if (csum != sum)
{
csum = sum;
printf("====== Linux Devices found: ======\n");
for (int i = 0; i < devanz; i++)
{
printf("Index: %d\n", devlist[i].index);
printf("Name: %s\n", devlist[i].name);
printf("ID: %s\n", devlist[i].id);
printf("Cap/PB: %d\n", devlist[i].in_out);
printf("Channels: %d\n", devlist[i].stereo_mono);
printf("SR 44100: %d\n", devlist[i].supports_44100);
printf("SR 48000: %d\n", devlist[i].supports_48000);
printf("is active: %s\n", devlist[i].active ? "yes" : "no");
printf("--------------------------------------\n");
}
}
return 0;
}
static void get_channel_layout(const struct SoundIoChannelLayout* layout)
{
if (layout->name)
{
if (strstr(layout->name, "ereo"))
devlist[devanz].stereo_mono = 2;
if (strstr(layout->name, "ono"))
devlist[devanz].stereo_mono = 1;
}
}
int getDeviceParameters(int idx, struct SoundIoDevice* device)
{
strncpy(devlist[idx].id, device->id, sizeof(devlist[0].id) - 1);
devlist[idx].id[sizeof(devlist[0].id) - 1] = 0;
strncpy(devlist[idx].name, device->name, sizeof(devlist[0].name) - 1);
devlist[idx].name[sizeof(devlist[0].name) - 1] = 0;
for (int i = 0; i < device->layout_count; i++)
get_channel_layout(&device->layouts[i]);
int min = 999999, max = 0;
for (int i = 0; i < device->sample_rate_count; i++)
{
struct SoundIoSampleRateRange* range = &device->sample_rates[i];
if (range->min < min)
min = range->min;
if (range->max > max)
max = range->max;
}
if (min <= 44100) devlist[idx].supports_44100 = 1;
if (max >= 48000) devlist[idx].supports_48000 = 1;
if (devlist[idx].supports_44100 == 0 && devlist[idx].supports_48000 == 0) return 0;
return 1;
}
int getDevlistIndex(char* name, char* id)
{
for (int i = 0; i < devanz; i++)
{
// check if already exists
if (!strcmp(devlist[i].id, id) && !strcmp(devlist[i].name, name))
return i;
}
int newidx = devanz;
devanz++;
//printf("New Dev:%s Idx:%d\n", name, newidx);
return newidx;
}
int scan_devices()
{
for (int i = 0; i < devanz; i++)
devlist[i].active = 0;
int didx;
for (int i = 0; i < soundio_input_device_count(soundio); i++)
{
struct SoundIoDevice* device = soundio_get_input_device(soundio, i);
if (device == NULL) continue;
if (strstr(device->name, "onitor")) continue;
if (device->probe_error) continue;
didx = getDevlistIndex(device->name, device->id);
if (getDeviceParameters(didx, device) == 1)
{
//printf("%d %d ====CAP:\nid:<%s>\nname:<%s>\n", i,devanz,device->id, device->name);
devlist[didx].in_out = 0;
devlist[didx].index = didx;
devlist[didx].active = 1;
}
else
{
*devlist[didx].name = 0;
*devlist[didx].id = 0;
}
soundio_device_unref(device);
}
for (int i = 0; i < soundio_output_device_count(soundio); i++)
{
struct SoundIoDevice* device = soundio_get_output_device(soundio, i);
if (device == NULL) continue;
if (strstr(device->name, "onitor")) continue;
if (device->probe_error) continue;
didx = getDevlistIndex(device->name, device->id);
if (getDeviceParameters(didx, device) == 1)
{
//printf("====PB :\nid:<%s>\nname:<%s>\n", device->id, device->name);
devlist[didx].in_out = 1;
devlist[didx].index = didx;
devlist[didx].active = 1;
}
else
{
*devlist[didx].name = 0;
*devlist[didx].id = 0;
}
soundio_device_unref(device);
}
return 0;
}
#endif // ifndef WIN32

View File

@ -0,0 +1,171 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
*
* 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.
*
* libkmaudio_init.cpp ... initialize portaudio (Windows only)
*
*/
#include "libkmaudio.h"
void kmaudio_close();
//int keeprunning = 1; // to stop callbacks at program end
int kmaudio_init()
{
kmaudio_close();
sleep_ms(100);
printf("libkmaudio_init\n");
keeprunning = 1;
init_pipes(); // init fifo
init_maxarray(); // init array for maxlevel measurement
#ifdef WIN32
int err = Pa_Initialize();
if (err != paNoError)
{
printf("ERROR: Pa_Initialize returned 0x%x\n", err);
return -1;
}
printf("PortAudio version: 0x%08X\n", Pa_GetVersion());
#else
return kmaudio_init_linux();
#endif
return 0;
}
void kmaudio_close()
{
printf("libkmaudio_close\n");
#ifdef WIN32
for (int i = 0; i < devanz; i++)
{
if (devlist[i].capStream != NULL)
{
Pa_CloseStream(devlist[i].capStream);
devlist[i].capStream = NULL;
}
if (devlist[i].pbStream != NULL)
{
Pa_CloseStream(devlist[i].pbStream);
devlist[i].pbStream = NULL;
}
}
Pa_Terminate();
#else
kmaudio_close_linux();
#endif
keeprunning = 0;
}
/*
// diagonstic routines for development
#define MAXSPDARR 10
int spdarr[MAXSPDARR];
int spdarrbps[MAXSPDARR];
#ifdef _LINUX_
uint64_t getms()
{
struct timeval tv;
gettimeofday(&tv, NULL);
uint64_t at = tv.tv_sec * 1000000 + tv.tv_usec;
at = at / 1000;
return at;
}
#endif
#ifdef WIN32
uint64_t getms()
{
// get time in 100ns resolution
FILETIME ft_now;
GetSystemTimeAsFileTime(&ft_now);
// convert to full 64 bit time
uint64_t ll_now = (uint64_t)ft_now.dwLowDateTime + ((uint64_t)(ft_now.dwHighDateTime) << 32LL);
// convert to Milliseconds
ll_now /= (10 * 1000); // still needs 64 bit integer
return ll_now;
}
#else
uint64_t getms()
{
struct timeval tv;
gettimeofday(&tv, NULL);
uint64_t at = tv.tv_sec * 1000000 + tv.tv_usec;
at = at / 1000;
return at;
}
#endif
void measure_speed_bps(int len)
{
static uint64_t lasttim = 0;
static int elems = 0;
uint64_t tim = getms();
int timespan = (int)(tim - lasttim);
if (timespan < 0)
{
lasttim = tim;
return;
}
elems += len;
if (timespan < 1000) return;
double dspd = elems;
dspd = dspd * 1e3 / timespan;
int speed = (int)dspd;
// here we have number of elements after 1s
printf(" ======================= %d bit/s\n", speed);
elems = 0;
lasttim = tim;
}
void sleep_ms(int ms)
{
#ifdef WIN32
Sleep(ms);
#else
usleep(ms * 1000);
#endif
}
*/

View File

@ -0,0 +1,78 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
*
* 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.
*
* libkmaudio_init_linux.cpp ... initialize libsoundio (Linux only)
*
*/
#include "libkmaudio.h"
struct SoundIo* soundio = NULL;
#ifndef WIN32 // Linux
int kmaudio_init_linux()
{
int err;
// prepare and connect to libsoundio
soundio = soundio_create();
if (!soundio) {
printf("soundio_create: out of memory\n");
return -1;
}
if ((err = soundio_connect(soundio))) {
printf("soundio_connect: %s\n", soundio_strerror(err));
return -1;
}
return 0;
}
void kmaudio_close_linux()
{
for (int i = 0; i < devanz; i++)
{
if (devlist[i].instream) soundio_instream_destroy(devlist[i].instream);
devlist[i].instream = NULL;
if (devlist[i].outstream) soundio_outstream_destroy(devlist[i].outstream);
devlist[i].outstream = NULL;
if (devlist[i].io_pb_device) soundio_device_unref(devlist[i].io_pb_device);
devlist[i].io_pb_device = NULL;
if (devlist[i].io_cap_device) soundio_device_unref(devlist[i].io_cap_device);
devlist[i].io_cap_device = NULL;
}
if (soundio) soundio_destroy(soundio);
soundio = NULL;
}
#endif // ndef WIN32

View File

@ -0,0 +1,155 @@
#include "libkmaudio.h"
void getMax(int id, float fv);
/*
* reads len samples from device id into psamp
* returns: number of values written to psamp , -1=error
* id ... device id returned by kmaudio_startCapture
* psamp ... float array of length len getting the audio data (mono)
* len ... number of float values to write into psamp
* volume ... 0.0f..2.0f will be multiplied with the input sample
* wait ... 1=wait for data, 0=return if not enough data available (in this case psamp will return 0,0,0...)
*
* if resampling is required the number of returned samples may differ from the number of requested samples
* it can be larger, so the buffer psamp should be larger than "len" by factor 1.1
*/
int kmaudio_readsamples(int id, float* psamp, int len, float volume, int wait)
{
int e = io_fifo_elems_avail(id);
if (e < len) return 0;
if (devlist[id].requested_samprate == devlist[id].real_samprate)
{
// data rate is ok, take samples as is
int nl = io_read_fifo_num(id, psamp, len);
for (int i = 0; i < nl; i++)
{
psamp[i] *= volume;
getMax(id, psamp[i]);
//kmaudio_detectDropouts(id);
}
return nl;
}
// resampling is required
int num = io_read_fifo_num(id, psamp, len);
if (num == 0) return 0;
int newlen = 0;
float *f = resample(id, psamp, len, &newlen);
for (int i = 0; i < newlen; i++)
{
psamp[i] = f[i] * volume;
getMax(id, psamp[i]);
}
return newlen;
}
/*
* plays len samples from psamp to device id
* returns: 0=ok, -1=error
* id ... device id returned by kmaudio_startPlayback
* psamp ... float array of length len with the audio data (mono)
* len ... number of float values in psamp
* volume ... 0.0f..2.0f will be multiplied with the output sample
*/
int kmaudio_playsamples(int id, float* psamp, int len, float volume)
{
// check if resampling is required
//printf("%d %d\n", devlist[id].requested_samprate , devlist[id].real_samprate);
if (devlist[id].requested_samprate == devlist[id].real_samprate)
{
// sampling rate is ok, just play samples
for (int i = 0; i < len; i++)
{
io_write_fifo(id, psamp[i] * volume);
getMax(id, psamp[i] * volume);
}
return 0;
}
// resampling is required
int newlen = 0;
float *f = resample(id, psamp, len, &newlen);
for (int i = 0; i < newlen; i++)
{
io_write_fifo(id, f[i] * volume);
getMax(id, psamp[i] * volume);
}
return 0;
}
#define MCHECK 48000 // abt. 1s of samples
float farr[MAXDEVICES][MCHECK];
int farridx[MAXDEVICES];
void init_maxarray()
{
// initialize arrays
for (int md = 0; md < MAXDEVICES; md++)
{
farridx[md] = 0;
for (int i = 0; i < MCHECK; i++)
farr[md][i] = 0;
}
}
void getMax(int id, float fv)
{
// put value into array
farr[id][farridx[id]] = fv;
if (++farridx[id] == MCHECK)
farridx[id] = 0;
}
/*
* returns the max level (within 1 second) of this stream in % (0..100)
* if the level >= 100 the signal will get clipped and distorted
*/
uint8_t kmaudio_maxlevel(int id)
{
float max = 0;
for (int i = 0; i < MCHECK; i++)
if (farr[id][i] > max) max = farr[id][i];
return (uint8_t)(max * 100);
}
void kmaudio_detectDropouts(int id)
{
int dropout = 0;
int stat = 0;
int drlen = 0;
for (int i = 0; i < MCHECK; i++)
{
switch (stat)
{
case 0: // search beginning of dropout
if (farr[id][i] == 0.0f)
stat = 1;
break;
case 1: // count length of dropout
if (farr[id][i] == 0.0f) drlen++;
else
{
// end of dropout
if (drlen > 0)
{
printf("Dropout len:%d\n", drlen);
}
drlen = 0;
stat = 0;
}
break;
}
}
}

View File

@ -0,0 +1,169 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
*
* 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.
*
* libkmaudio_playback.cpp ...
* starts a portaudio playback stream and a callback routine. Plays the
* audio samples coming via the fifo (Windows only)
*/
#include "libkmaudio.h"
#define FRAMES_PER_BUFFER 512
int playCallback(const void* inputBuffer,
void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData);
int kmaudio_startPlayback(char* devname, int samprate)
{
printf("Start request for PB stream:%s\n", devname);
if (devname == NULL || strlen(devname) < 3) // no devices defined yet
{
printf("no PB devices specified\n");
return -1;
}
int idx = searchDevice(devname, 1);
if (idx == -1)
{
printf("Playback Device:<%s> not found\n", devname);
return -1;
}
devlist[idx].working = 0;
if (devlist[idx].pbStream != NULL)
{
printf("Closing old PB stream:%s [%d]\n", devname, idx);
Pa_CloseStream(devlist[idx].pbStream);
devlist[idx].pbStream = NULL;
}
printf("Starting PB stream:%s [%d]\n", devname, idx);
io_fifo_clear(idx);
devlist[idx].requested_samprate = samprate;
if (getRealSamprate(idx) == -1)
{
printf("Samplerate %d not supported by device:<%s>\n", samprate, devname);
return -1;
}
if (devlist[idx].requested_samprate != devlist[idx].real_samprate)
resampler_create(idx);
struct PaWasapiStreamInfo wasapiInfo;
memset(&wasapiInfo, 0, sizeof(PaWasapiStreamInfo));
wasapiInfo.size = sizeof(PaWasapiStreamInfo);
wasapiInfo.hostApiType = paWASAPI;
wasapiInfo.version = 1;
wasapiInfo.flags = (paWinWasapiExclusive | paWinWasapiThreadPriority);
wasapiInfo.threadPriority = eThreadPriorityProAudio;
devlist[idx].outputParameters.hostApiSpecificStreamInfo = (&wasapiInfo);
PaError e = Pa_IsFormatSupported(&devlist[idx].outputParameters, NULL, (double)devlist[idx].real_samprate);
printf("Playback : err:%d device:%d PAdev:%d samprate: %f chans:%d\n", e, idx, devlist[idx].devnum, (double)devlist[idx].real_samprate, devlist[idx].outputParameters.channelCount);
devlist[idx].index = idx;
int err = Pa_OpenStream(
&devlist[idx].pbStream,
NULL,
&devlist[idx].outputParameters,
(double)devlist[idx].real_samprate,
FRAMES_PER_BUFFER,
paClipOff,
playCallback,
&(devlist[idx].index));
if (err != paNoError)
{
printf("cannot open playback stream for device:<%s> %d\n", devname, err);
return -1;
}
err = Pa_StartStream(devlist[idx].pbStream);
if (err != paNoError)
{
printf("cannot start playback stream for device:<%s>\n", devname);
return -1;
}
printf("Playback started sucessfully\n");
devlist[idx].working = 1;
return idx;
}
int playCallback( const void* inputBuffer,
void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData)
{
int16_t* rptr = (int16_t*)outputBuffer;
int devidx = *((int*)userData);
int chans = devlist[devidx].outputParameters.channelCount;
//measure_speed_bps(framesPerBuffer);
int16_t f[FRAMES_PER_BUFFER];
memset(f, 0, sizeof(int16_t) * FRAMES_PER_BUFFER);
unsigned int num = io_read_fifo_num_short(devidx, f, framesPerBuffer);
if (num < framesPerBuffer)
{
//printf("got %d from fifo, requested %d\n", num, framesPerBuffer);
}
int av = io_fifo_elems_avail(devidx);
for (unsigned int i = 0; i < framesPerBuffer; i++)
{
if (chans == 1) rptr[i] = f[i];
else
{
rptr[i * 2] = f[i];
rptr[i * 2 + 1] = f[i];
}
}
// Prevent unused variable warnings
(void)inputBuffer;
(void)timeInfo;
(void)statusFlags;
if (keeprunning == 1)
return paContinue;
return paComplete;
}

View File

@ -0,0 +1,236 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
*
* 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.
*
* libkmaudio_playback.cpp ...
* starts a libsoundio playback stream and a callback routine. Plays the
* audio samples coming via the fifo (Linux only)
*/
#ifndef WIN32
#include "libkmaudio.h"
// #define SINEWAVETEST
#ifdef SINEWAVETEST
static const double PI = 3.14159265358979323846264338328;
static double seconds_offset = 0.0;
#endif
void write_sample_float32ne(char* ptr, double sample)
{
float* buf = (float*)ptr;
*buf = (float)sample;
}
static void write_callback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max)
{
if (outstream == NULL || soundio == NULL) return;
//printf("pb: %d %d\n", frame_count_min, frame_count_max);
//printf("pb :%d\n", outstream->sample_rate);
int idx = *((int*)(outstream->userdata));
#ifdef SINEWAVETEST
double float_sample_rate = outstream->sample_rate;
double seconds_per_frame = 1.0 / float_sample_rate;
double pitch = 440.0;
double radians_per_second = pitch * 2.0 * PI;
#endif
struct SoundIoChannelArea* areas;
int err;
int frames_left = 4800;
if (frame_count_max < frames_left)
frames_left = frame_count_max;
for (;;) {
int frame_count = frames_left;
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) {
fprintf(stderr, "write_callback unrecoverable soundio_outstream_begin_write error: %s\n", soundio_strerror(err));
return;
}
if (!frame_count)
break;
//printf("ck: %d read from fifo:%d\n", frame_count,idx);
if (frame_count >= 10000)
{
printf("frame count >= 1000: %d\n", frame_count);
exit(0);
}
float f[10000];
memset(f, 0, sizeof(float) * frame_count);
if (io_fifo_elems_avail(idx) >= frame_count)
{
// if fifo does not have enough data, don't take any
// this gives the fifo a chance to fill up a bit
io_read_fifo_num(idx, f, frame_count);
}
//measure_speed_bps(frame_count);
const struct SoundIoChannelLayout* layout = &outstream->layout;
for (int frame = 0; frame < frame_count; frame += 1)
{
#ifdef SINEWAVETEST
double sample = sin((seconds_offset + frame * seconds_per_frame) * radians_per_second);
#endif
for (int channel = 0; channel < layout->channel_count; channel += 1)
{
float ftx = f[frame];
//getTXMax(f[frame]);
#ifdef SINEWAVETEST
write_sample_float32ne(areas[channel].ptr, sample); // sine wave test tone
#endif
write_sample_float32ne(areas[channel].ptr, ftx);
areas[channel].ptr += areas[channel].step;
}
}
#ifdef SINEWAVETEST
seconds_offset = fmod(seconds_offset + seconds_per_frame * frame_count, 1.0);
#endif
if ((err = soundio_outstream_end_write(outstream))) {
if (err == SoundIoErrorUnderflow)
return;
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
return;
}
frames_left -= frame_count;
if (frames_left <= 0)
break;
}
}
void underflow_callback(struct SoundIoOutStream* outstream)
{
static int count = 0;
printf("underflow %d\n", count++);
}
int kmaudio_startPlayback(char* devname, int samprate)
{
printf("Start request for PB stream:%s\n", devname);
if (devname == NULL || strlen(devname) < 3) // no devices defined yet
{
printf("no PB devices specified\n");
return -1;
}
int idx = 0; // index into devlist
char* pbdevid = getDevID(devname, 1, &idx);
if (pbdevid == NULL) return -1;
// if an old stream is open, close it
if (devlist[idx].outstream != NULL)
{
printf("Closing old PB stream:%s [%d]\n", devname, idx);
soundio_outstream_destroy(devlist[idx].outstream);
devlist[idx].outstream = NULL;
}
printf("Starting PB stream:%s [%d]\n", devname, idx);
io_fifo_clear(idx);
devlist[idx].working = 0;
// define the capture device
soundio_flush_events(soundio);
for (int i = 0; i < soundio_output_device_count(soundio); i++)
{
devlist[idx].io_pb_device = NULL;
struct SoundIoDevice* device = soundio_get_output_device(soundio, i);
if (strcmp(device->id, pbdevid) == 0)
{
devlist[idx].io_pb_device = device;
break;
}
soundio_device_unref(device);
}
if (!devlist[idx].io_pb_device)
{
printf("Invalid device id: %s\n", pbdevid);
return -1;
}
if (devlist[idx].io_pb_device->probe_error)
{
printf("Unable to probe device: %s\n", soundio_strerror(devlist[idx].io_pb_device->probe_error));
return -1;
}
// create playback callback
devlist[idx].outstream = soundio_outstream_create(devlist[idx].io_pb_device);
if (!devlist[idx].outstream) {
printf("soundio_outstream_create: out of memory\n");
return 0;
}
devlist[idx].requested_samprate = samprate;
if (getRealSamprate(idx) == -1)
{
printf("Samplerate %d not supported by device:<%s>\n", samprate, devname);
return -1;
}
if (devlist[idx].requested_samprate != devlist[idx].real_samprate)
resampler_create(idx);
devlist[idx].outstream->format = SoundIoFormatFloat32NE;
devlist[idx].outstream->sample_rate = devlist[idx].real_samprate;
devlist[idx].outstream->software_latency = 0.1f;
devlist[idx].outstream->write_callback = write_callback;
devlist[idx].outstream->underflow_callback = underflow_callback;
devlist[idx].outstream->userdata = &(devlist[idx].index);
int err = 0;
if ((err = soundio_outstream_open(devlist[idx].outstream))) {
printf("unable to open output stream: %s", soundio_strerror(err));
return -1;
}
if ((err = soundio_outstream_start(devlist[idx].outstream))) {
printf("unable to start output device: %s", soundio_strerror(err));
return -1;
}
printf("selected PLAYBACK device:\nname:%s\nid :%s\n", devname, pbdevid);
printf("physical playback rate:%d, requested capture rate:%d\n", devlist[idx].real_samprate, devlist[idx].requested_samprate);
printf("format: %s\n\n", soundio_format_string(devlist[idx].outstream->format));
devlist[idx].working = 1;
return idx;
}
#endif // ndef WIN32

View File

@ -0,0 +1,109 @@
/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
*
* 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.
*
* libkmaudio_resampler.cpp ... converts audio streams
* between 44100 and 48000 samples/s in both directions
* uses the libliquid library
*/
#include "libkmaudio.h"
#define MAXRLEN 3000
resamp_crcf q[MAXDEVICES];
float fresamp[MAXDEVICES][MAXRLEN];
unsigned int h_len = 13; // filter semi-length (filter delay)
float r = 0.9f; // resampling rate (output/input)
float bw = 0.45f; // resampling filter bandwidth
float slsl = 60.0f; // resampling filter sidelobe suppression level
unsigned int npfb = 32; // number of filters in bank (timing resolution)
void resampler_create(int devidx)
{
static int f = 1;
if(f)
{
f = 0;
for (int i = 0; i < MAXDEVICES; i++)
q[i] = NULL;
}
printf("create resampler %d real %d req %d\n", devidx, devlist[devidx].real_samprate, devlist[devidx].requested_samprate);
if (q[devidx] != NULL) resamp_crcf_destroy(q[devidx]);
int src_rate = 0;
int dst_rate = 0;
if (devlist[devidx].in_out == 0)
{
// capture device:
src_rate = devlist[devidx].real_samprate;
dst_rate = devlist[devidx].requested_samprate;
}
else
{
// playback device:
src_rate = devlist[devidx].requested_samprate;
dst_rate = devlist[devidx].real_samprate;
}
r = (float)dst_rate / (float)src_rate;
printf("%f %f %f\n", r, (float)dst_rate, (float)src_rate);
q[devidx] = resamp_crcf_create(r, h_len, bw, slsl, npfb);
}
float* resample(int id, float*psamp, int len, int *pnewlen)
{
int didx = 0;
for (int i = 0; i < len; i++)
{
unsigned int num_written = 0;
liquid_float_complex in;
liquid_float_complex out[2];
in.real = psamp[i];
in.imag = 0;
resamp_crcf_execute(q[id], in, out, &num_written);
for (unsigned int r = 0; r < num_written; r++)
{
if (didx < MAXRLEN)
fresamp[id][didx++] = out[r].real;
else
printf("MAXRLEN too small\n");
}
}
*pnewlen = didx;
return fresamp[id];
}

8823
hsmodem/libkmaudio/liquid.h Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,443 @@
#ifndef PA_WIN_WASAPI_H
#define PA_WIN_WASAPI_H
/*
* $Id: $
* PortAudio Portable Real-Time Audio Library
* DirectSound specific extensions
*
* Copyright (c) 1999-2007 Ross Bencina and Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/
/** @file
@ingroup public_header
@brief WASAPI-specific PortAudio API extension header file.
*/
#include "portaudio.h"
#include "pa_win_waveformat.h"
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
/* Setup flags */
typedef enum PaWasapiFlags
{
/* puts WASAPI into exclusive mode */
paWinWasapiExclusive = (1 << 0),
/* allows to skip internal PA processing completely */
paWinWasapiRedirectHostProcessor = (1 << 1),
/* assigns custom channel mask */
paWinWasapiUseChannelMask = (1 << 2),
/* selects non-Event driven method of data read/write
Note: WASAPI Event driven core is capable of 2ms latency!!!, but Polling
method can only provide 15-20ms latency. */
paWinWasapiPolling = (1 << 3),
/* forces custom thread priority setting, must be used if PaWasapiStreamInfo::threadPriority
is set to a custom value */
paWinWasapiThreadPriority = (1 << 4)
}
PaWasapiFlags;
#define paWinWasapiExclusive (paWinWasapiExclusive)
#define paWinWasapiRedirectHostProcessor (paWinWasapiRedirectHostProcessor)
#define paWinWasapiUseChannelMask (paWinWasapiUseChannelMask)
#define paWinWasapiPolling (paWinWasapiPolling)
#define paWinWasapiThreadPriority (paWinWasapiThreadPriority)
/* Host processor. Allows to skip internal PA processing completely.
You must set paWinWasapiRedirectHostProcessor flag to PaWasapiStreamInfo::flags member
in order to have host processor redirected to your callback.
Use with caution! inputFrames and outputFrames depend solely on final device setup.
To query maximal values of inputFrames/outputFrames use PaWasapi_GetFramesPerHostBuffer.
*/
typedef void (*PaWasapiHostProcessorCallback) (void *inputBuffer, long inputFrames,
void *outputBuffer, long outputFrames,
void *userData);
/* Device role. */
typedef enum PaWasapiDeviceRole
{
eRoleRemoteNetworkDevice = 0,
eRoleSpeakers,
eRoleLineLevel,
eRoleHeadphones,
eRoleMicrophone,
eRoleHeadset,
eRoleHandset,
eRoleUnknownDigitalPassthrough,
eRoleSPDIF,
eRoleHDMI,
eRoleUnknownFormFactor
}
PaWasapiDeviceRole;
/* Jack connection type. */
typedef enum PaWasapiJackConnectionType
{
eJackConnTypeUnknown,
eJackConnType3Point5mm,
eJackConnTypeQuarter,
eJackConnTypeAtapiInternal,
eJackConnTypeRCA,
eJackConnTypeOptical,
eJackConnTypeOtherDigital,
eJackConnTypeOtherAnalog,
eJackConnTypeMultichannelAnalogDIN,
eJackConnTypeXlrProfessional,
eJackConnTypeRJ11Modem,
eJackConnTypeCombination
}
PaWasapiJackConnectionType;
/* Jack geometric location. */
typedef enum PaWasapiJackGeoLocation
{
eJackGeoLocUnk = 0,
eJackGeoLocRear = 0x1, /* matches EPcxGeoLocation::eGeoLocRear */
eJackGeoLocFront,
eJackGeoLocLeft,
eJackGeoLocRight,
eJackGeoLocTop,
eJackGeoLocBottom,
eJackGeoLocRearPanel,
eJackGeoLocRiser,
eJackGeoLocInsideMobileLid,
eJackGeoLocDrivebay,
eJackGeoLocHDMI,
eJackGeoLocOutsideMobileLid,
eJackGeoLocATAPI,
eJackGeoLocReserved5,
eJackGeoLocReserved6,
}
PaWasapiJackGeoLocation;
/* Jack general location. */
typedef enum PaWasapiJackGenLocation
{
eJackGenLocPrimaryBox = 0,
eJackGenLocInternal,
eJackGenLocSeparate,
eJackGenLocOther
}
PaWasapiJackGenLocation;
/* Jack's type of port. */
typedef enum PaWasapiJackPortConnection
{
eJackPortConnJack = 0,
eJackPortConnIntegratedDevice,
eJackPortConnBothIntegratedAndJack,
eJackPortConnUnknown
}
PaWasapiJackPortConnection;
/* Thread priority. */
typedef enum PaWasapiThreadPriority
{
eThreadPriorityNone = 0,
eThreadPriorityAudio, //!< Default for Shared mode.
eThreadPriorityCapture,
eThreadPriorityDistribution,
eThreadPriorityGames,
eThreadPriorityPlayback,
eThreadPriorityProAudio, //!< Default for Exclusive mode.
eThreadPriorityWindowManager
}
PaWasapiThreadPriority;
/* Stream descriptor. */
typedef struct PaWasapiJackDescription
{
unsigned long channelMapping;
unsigned long color; /* derived from macro: #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) */
PaWasapiJackConnectionType connectionType;
PaWasapiJackGeoLocation geoLocation;
PaWasapiJackGenLocation genLocation;
PaWasapiJackPortConnection portConnection;
unsigned int isConnected;
}
PaWasapiJackDescription;
/** Stream category.
Note:
- values are equal to WASAPI AUDIO_STREAM_CATEGORY enum
- supported since Windows 8.0, noop on earler versions
- values 1,2 are deprecated on Windows 10 and not included into enumeration
@version Available as of 19.6.0
*/
typedef enum PaWasapiStreamCategory
{
eAudioCategoryOther = 0,
eAudioCategoryCommunications = 3,
eAudioCategoryAlerts = 4,
eAudioCategorySoundEffects = 5,
eAudioCategoryGameEffects = 6,
eAudioCategoryGameMedia = 7,
eAudioCategoryGameChat = 8,
eAudioCategorySpeech = 9,
eAudioCategoryMovie = 10,
eAudioCategoryMedia = 11
}
PaWasapiStreamCategory;
/** Stream option.
Note:
- values are equal to WASAPI AUDCLNT_STREAMOPTIONS enum
- supported since Windows 8.1, noop on earler versions
@version Available as of 19.6.0
*/
typedef enum PaWasapiStreamOption
{
eStreamOptionNone = 0, //!< default
eStreamOptionRaw = 1, //!< bypass WASAPI Audio Engine DSP effects, supported since Windows 8.1
eStreamOptionMatchFormat = 2 //!< force WASAPI Audio Engine into a stream format, supported since Windows 10
}
PaWasapiStreamOption;
/* Stream descriptor. */
typedef struct PaWasapiStreamInfo
{
unsigned long size; /**< sizeof(PaWasapiStreamInfo) */
PaHostApiTypeId hostApiType; /**< paWASAPI */
unsigned long version; /**< 1 */
unsigned long flags; /**< collection of PaWasapiFlags */
/** Support for WAVEFORMATEXTENSIBLE channel masks. If flags contains
paWinWasapiUseChannelMask this allows you to specify which speakers
to address in a multichannel stream. Constants for channelMask
are specified in pa_win_waveformat.h. Will be used only if
paWinWasapiUseChannelMask flag is specified.
*/
PaWinWaveFormatChannelMask channelMask;
/** Delivers raw data to callback obtained from GetBuffer() methods skipping
internal PortAudio processing inventory completely. userData parameter will
be the same that was passed to Pa_OpenStream method. Will be used only if
paWinWasapiRedirectHostProcessor flag is specified.
*/
PaWasapiHostProcessorCallback hostProcessorOutput;
PaWasapiHostProcessorCallback hostProcessorInput;
/** Specifies thread priority explicitly. Will be used only if paWinWasapiThreadPriority flag
is specified.
Please note, if Input/Output streams are opened simultaniously (Full-Duplex mode)
you shall specify same value for threadPriority or othervise one of the values will be used
to setup thread priority.
*/
PaWasapiThreadPriority threadPriority;
/** Stream category.
@see PaWasapiStreamCategory
@version Available as of 19.6.0
*/
PaWasapiStreamCategory streamCategory;
/** Stream option.
@see PaWasapiStreamOption
@version Available as of 19.6.0
*/
PaWasapiStreamOption streamOption;
}
PaWasapiStreamInfo;
/** Returns default sound format for device. Format is represented by PaWinWaveFormat or
WAVEFORMATEXTENSIBLE structure.
@param pFormat Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
@param nFormatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes.
@param nDevice Device index.
@return Non-negative value indicating the number of bytes copied into format decriptor
or, a PaErrorCode (which are always negative) if PortAudio is not initialized
or an error is encountered.
*/
int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice );
/** Returns device role (PaWasapiDeviceRole enum).
@param nDevice device index.
@return Non-negative value indicating device role or, a PaErrorCode (which are always negative)
if PortAudio is not initialized or an error is encountered.
*/
int/*PaWasapiDeviceRole*/ PaWasapi_GetDeviceRole( PaDeviceIndex nDevice );
/** Boost thread priority of calling thread (MMCSS). Use it for Blocking Interface only for thread
which makes calls to Pa_WriteStream/Pa_ReadStream.
@param hTask Handle to pointer to priority task. Must be used with PaWasapi_RevertThreadPriority
method to revert thread priority to initial state.
@param nPriorityClass Id of thread priority of PaWasapiThreadPriority type. Specifying
eThreadPriorityNone does nothing.
@return Error code indicating success or failure.
@see PaWasapi_RevertThreadPriority
*/
PaError PaWasapi_ThreadPriorityBoost( void **hTask, PaWasapiThreadPriority nPriorityClass );
/** Boost thread priority of calling thread (MMCSS). Use it for Blocking Interface only for thread
which makes calls to Pa_WriteStream/Pa_ReadStream.
@param hTask Task handle obtained by PaWasapi_BoostThreadPriority method.
@return Error code indicating success or failure.
@see PaWasapi_BoostThreadPriority
*/
PaError PaWasapi_ThreadPriorityRevert( void *hTask );
/** Get number of frames per host buffer. This is maximal value of frames of WASAPI buffer which
can be locked for operations. Use this method as helper to findout maximal values of
inputFrames/outputFrames of PaWasapiHostProcessorCallback.
@param pStream Pointer to PaStream to query.
@param nInput Pointer to variable to receive number of input frames. Can be NULL.
@param nOutput Pointer to variable to receive number of output frames. Can be NULL.
@return Error code indicating success or failure.
@see PaWasapiHostProcessorCallback
*/
PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput, unsigned int *nOutput );
/** Get number of jacks associated with a WASAPI device. Use this method to determine if
there are any jacks associated with the provided WASAPI device. Not all audio devices
will support this capability. This is valid for both input and output devices.
@param nDevice device index.
@param jcount Number of jacks is returned in this variable
@return Error code indicating success or failure
@see PaWasapi_GetJackDescription
*/
PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount);
/** Get the jack description associated with a WASAPI device and jack number
Before this function is called, use PaWasapi_GetJackCount to determine the
number of jacks associated with device. If jcount is greater than zero, then
each jack from 0 to jcount can be queried with this function to get the jack
description.
@param nDevice device index.
@param jindex Which jack to return information
@param KSJACK_DESCRIPTION This structure filled in on success.
@return Error code indicating success or failure
@see PaWasapi_GetJackCount
*/
PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription);
/*
IMPORTANT:
WASAPI is implemented for Callback and Blocking interfaces. It supports Shared and Exclusive
share modes.
Exclusive Mode:
Exclusive mode allows to deliver audio data directly to hardware bypassing
software mixing.
Exclusive mode is specified by 'paWinWasapiExclusive' flag.
Callback Interface:
Provides best audio quality with low latency. Callback interface is implemented in
two versions:
1) Event-Driven:
This is the most powerful WASAPI implementation which provides glitch-free
audio at around 3ms latency in Exclusive mode. Lowest possible latency for this mode is
3 ms for HD Audio class audio chips. For the Shared mode latency can not be
lower than 20 ms.
2) Poll-Driven:
Polling is another 2-nd method to operate with WASAPI. It is less efficient than Event-Driven
and provides latency at around 10-13ms. Polling must be used to overcome a system bug
under Windows Vista x64 when application is WOW64(32-bit) and Event-Driven method simply
times out (event handle is never signalled on buffer completion). Please note, such WOW64 bug
does not exist in Vista x86 or Windows 7.
Polling can be setup by speciying 'paWinWasapiPolling' flag. Our WASAPI implementation detects
WOW64 bug and sets 'paWinWasapiPolling' automatically.
Thread priority:
Normally thread priority is set automatically and does not require modification. Although
if user wants some tweaking thread priority can be modified by setting 'paWinWasapiThreadPriority'
flag and specifying 'PaWasapiStreamInfo::threadPriority' with value from PaWasapiThreadPriority
enum.
Blocking Interface:
Blocking interface is implemented but due to above described Poll-Driven method can not
deliver lowest possible latency. Specifying too low latency in Shared mode will result in
distorted audio although Exclusive mode adds stability.
Pa_IsFormatSupported:
To check format with correct Share Mode (Exclusive/Shared) you must supply
PaWasapiStreamInfo with flags paWinWasapiExclusive set through member of
PaStreamParameters::hostApiSpecificStreamInfo structure.
Pa_OpenStream:
To set desired Share Mode (Exclusive/Shared) you must supply
PaWasapiStreamInfo with flags paWinWasapiExclusive set through member of
PaStreamParameters::hostApiSpecificStreamInfo structure.
*/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* PA_WIN_WASAPI_H */

View File

@ -0,0 +1,199 @@
#ifndef PA_WIN_WAVEFORMAT_H
#define PA_WIN_WAVEFORMAT_H
/*
* PortAudio Portable Real-Time Audio Library
* Windows WAVEFORMAT* data structure utilities
* portaudio.h should be included before this file.
*
* Copyright (c) 2007 Ross Bencina
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/
/** @file
@ingroup public_header
@brief Windows specific PortAudio API extension and utilities header file.
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
The following #defines for speaker channel masks are the same
as those in ksmedia.h, except with PAWIN_ prepended, KSAUDIO_ removed
in some cases, and casts to PaWinWaveFormatChannelMask added.
*/
typedef unsigned long PaWinWaveFormatChannelMask;
/* Speaker Positions: */
#define PAWIN_SPEAKER_FRONT_LEFT ((PaWinWaveFormatChannelMask)0x1)
#define PAWIN_SPEAKER_FRONT_RIGHT ((PaWinWaveFormatChannelMask)0x2)
#define PAWIN_SPEAKER_FRONT_CENTER ((PaWinWaveFormatChannelMask)0x4)
#define PAWIN_SPEAKER_LOW_FREQUENCY ((PaWinWaveFormatChannelMask)0x8)
#define PAWIN_SPEAKER_BACK_LEFT ((PaWinWaveFormatChannelMask)0x10)
#define PAWIN_SPEAKER_BACK_RIGHT ((PaWinWaveFormatChannelMask)0x20)
#define PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER ((PaWinWaveFormatChannelMask)0x40)
#define PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER ((PaWinWaveFormatChannelMask)0x80)
#define PAWIN_SPEAKER_BACK_CENTER ((PaWinWaveFormatChannelMask)0x100)
#define PAWIN_SPEAKER_SIDE_LEFT ((PaWinWaveFormatChannelMask)0x200)
#define PAWIN_SPEAKER_SIDE_RIGHT ((PaWinWaveFormatChannelMask)0x400)
#define PAWIN_SPEAKER_TOP_CENTER ((PaWinWaveFormatChannelMask)0x800)
#define PAWIN_SPEAKER_TOP_FRONT_LEFT ((PaWinWaveFormatChannelMask)0x1000)
#define PAWIN_SPEAKER_TOP_FRONT_CENTER ((PaWinWaveFormatChannelMask)0x2000)
#define PAWIN_SPEAKER_TOP_FRONT_RIGHT ((PaWinWaveFormatChannelMask)0x4000)
#define PAWIN_SPEAKER_TOP_BACK_LEFT ((PaWinWaveFormatChannelMask)0x8000)
#define PAWIN_SPEAKER_TOP_BACK_CENTER ((PaWinWaveFormatChannelMask)0x10000)
#define PAWIN_SPEAKER_TOP_BACK_RIGHT ((PaWinWaveFormatChannelMask)0x20000)
/* Bit mask locations reserved for future use */
#define PAWIN_SPEAKER_RESERVED ((PaWinWaveFormatChannelMask)0x7FFC0000)
/* Used to specify that any possible permutation of speaker configurations */
#define PAWIN_SPEAKER_ALL ((PaWinWaveFormatChannelMask)0x80000000)
/* DirectSound Speaker Config */
#define PAWIN_SPEAKER_DIRECTOUT 0
#define PAWIN_SPEAKER_MONO (PAWIN_SPEAKER_FRONT_CENTER)
#define PAWIN_SPEAKER_STEREO (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT)
#define PAWIN_SPEAKER_QUAD (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \
PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT)
#define PAWIN_SPEAKER_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \
PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_BACK_CENTER)
#define PAWIN_SPEAKER_5POINT1 (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \
PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \
PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT)
#define PAWIN_SPEAKER_7POINT1 (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \
PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \
PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT | \
PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER | PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER)
#define PAWIN_SPEAKER_5POINT1_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \
PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \
PAWIN_SPEAKER_SIDE_LEFT | PAWIN_SPEAKER_SIDE_RIGHT)
#define PAWIN_SPEAKER_7POINT1_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \
PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \
PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT | \
PAWIN_SPEAKER_SIDE_LEFT | PAWIN_SPEAKER_SIDE_RIGHT)
/*
According to the Microsoft documentation:
The following are obsolete 5.1 and 7.1 settings (they lack side speakers). Note this means
that the default 5.1 and 7.1 settings (KSAUDIO_SPEAKER_5POINT1 and KSAUDIO_SPEAKER_7POINT1 are
similarly obsolete but are unchanged for compatibility reasons).
*/
#define PAWIN_SPEAKER_5POINT1_BACK PAWIN_SPEAKER_5POINT1
#define PAWIN_SPEAKER_7POINT1_WIDE PAWIN_SPEAKER_7POINT1
/* DVD Speaker Positions */
#define PAWIN_SPEAKER_GROUND_FRONT_LEFT PAWIN_SPEAKER_FRONT_LEFT
#define PAWIN_SPEAKER_GROUND_FRONT_CENTER PAWIN_SPEAKER_FRONT_CENTER
#define PAWIN_SPEAKER_GROUND_FRONT_RIGHT PAWIN_SPEAKER_FRONT_RIGHT
#define PAWIN_SPEAKER_GROUND_REAR_LEFT PAWIN_SPEAKER_BACK_LEFT
#define PAWIN_SPEAKER_GROUND_REAR_RIGHT PAWIN_SPEAKER_BACK_RIGHT
#define PAWIN_SPEAKER_TOP_MIDDLE PAWIN_SPEAKER_TOP_CENTER
#define PAWIN_SPEAKER_SUPER_WOOFER PAWIN_SPEAKER_LOW_FREQUENCY
/*
PaWinWaveFormat is defined here to provide compatibility with
compilation environments which don't have headers defining
WAVEFORMATEXTENSIBLE (e.g. older versions of MSVC, Borland C++ etc.
The fields for WAVEFORMATEX and WAVEFORMATEXTENSIBLE are declared as an
unsigned char array here to avoid clients who include this file having
a dependency on windows.h and mmsystem.h, and also to to avoid having
to write separate packing pragmas for each compiler.
*/
#define PAWIN_SIZEOF_WAVEFORMATEX 18
#define PAWIN_SIZEOF_WAVEFORMATEXTENSIBLE (PAWIN_SIZEOF_WAVEFORMATEX + 22)
typedef struct{
unsigned char fields[ PAWIN_SIZEOF_WAVEFORMATEXTENSIBLE ];
unsigned long extraLongForAlignment; /* ensure that compiler aligns struct to DWORD */
} PaWinWaveFormat;
/*
WAVEFORMATEXTENSIBLE fields:
union {
WORD wValidBitsPerSample;
WORD wSamplesPerBlock;
WORD wReserved;
} Samples;
DWORD dwChannelMask;
GUID SubFormat;
*/
#define PAWIN_INDEXOF_WVALIDBITSPERSAMPLE (PAWIN_SIZEOF_WAVEFORMATEX+0)
#define PAWIN_INDEXOF_DWCHANNELMASK (PAWIN_SIZEOF_WAVEFORMATEX+2)
#define PAWIN_INDEXOF_SUBFORMAT (PAWIN_SIZEOF_WAVEFORMATEX+6)
/*
Valid values to pass for the waveFormatTag PaWin_InitializeWaveFormatEx and
PaWin_InitializeWaveFormatExtensible functions below. These must match
the standard Windows WAVE_FORMAT_* values.
*/
#define PAWIN_WAVE_FORMAT_PCM (1)
#define PAWIN_WAVE_FORMAT_IEEE_FLOAT (3)
#define PAWIN_WAVE_FORMAT_DOLBY_AC3_SPDIF (0x0092)
#define PAWIN_WAVE_FORMAT_WMA_SPDIF (0x0164)
/*
returns PAWIN_WAVE_FORMAT_PCM or PAWIN_WAVE_FORMAT_IEEE_FLOAT
depending on the sampleFormat parameter.
*/
int PaWin_SampleFormatToLinearWaveFormatTag( PaSampleFormat sampleFormat );
/*
Use the following two functions to initialize the waveformat structure.
*/
void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat,
int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate );
void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat,
int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate,
PaWinWaveFormatChannelMask channelMask );
/* Map a channel count to a speaker channel mask */
PaWinWaveFormatChannelMask PaWin_DefaultChannelMask( int numChannels );
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* PA_WIN_WAVEFORMAT_H */

1225
hsmodem/libkmaudio/portaudio.h Executable file

File diff suppressed because it is too large Load Diff

1209
hsmodem/libkmaudio/soundio.h Executable file

File diff suppressed because it is too large Load Diff

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