mirror of
https://github.com/dj0abr/SSB_HighSpeed_Modem.git
synced 2025-06-13 04:02:24 -04:00
update
This commit is contained in:
parent
429ec008a9
commit
46faf838bc
0
WinRelease/audio/1200.pcm
Normal file → Executable file
0
WinRelease/audio/1200.pcm
Normal file → Executable file
0
WinRelease/audio/2400.pcm
Normal file → Executable file
0
WinRelease/audio/2400.pcm
Normal file → Executable file
0
WinRelease/audio/3000.pcm
Normal file → Executable file
0
WinRelease/audio/3000.pcm
Normal file → Executable file
0
WinRelease/audio/4000.pcm
Normal file → Executable file
0
WinRelease/audio/4000.pcm
Normal file → Executable file
0
WinRelease/audio/4410.pcm
Normal file → Executable file
0
WinRelease/audio/4410.pcm
Normal file → Executable file
0
WinRelease/audio/4800.pcm
Normal file → Executable file
0
WinRelease/audio/4800.pcm
Normal file → Executable file
0
WinRelease/audio/5500.pcm
Normal file → Executable file
0
WinRelease/audio/5500.pcm
Normal file → Executable file
0
WinRelease/audio/6000.pcm
Normal file → Executable file
0
WinRelease/audio/6000.pcm
Normal file → Executable file
0
WinRelease/audio/6600.pcm
Normal file → Executable file
0
WinRelease/audio/6600.pcm
Normal file → Executable file
0
WinRelease/audio/7200.pcm
Normal file → Executable file
0
WinRelease/audio/7200.pcm
Normal file → Executable file
0
WinRelease/audio/amsat.pcm
Normal file → Executable file
0
WinRelease/audio/amsat.pcm
Normal file → Executable file
0
WinRelease/audio/bpsk.pcm
Normal file → Executable file
0
WinRelease/audio/bpsk.pcm
Normal file → Executable file
0
WinRelease/audio/kbps.pcm
Normal file → Executable file
0
WinRelease/audio/kbps.pcm
Normal file → Executable file
0
WinRelease/audio/psk8.pcm
Normal file → Executable file
0
WinRelease/audio/psk8.pcm
Normal file → Executable file
0
WinRelease/audio/qpsk.pcm
Normal file → Executable file
0
WinRelease/audio/qpsk.pcm
Normal file → Executable file
Binary file not shown.
BIN
WinRelease/hsmodem.iobj
Executable file
BIN
WinRelease/hsmodem.iobj
Executable file
Binary file not shown.
BIN
WinRelease/hsmodem.ipdb
Executable file
BIN
WinRelease/hsmodem.ipdb
Executable file
Binary file not shown.
BIN
WinRelease/hsmodem.pdb
Executable file
BIN
WinRelease/hsmodem.pdb
Executable file
Binary file not shown.
Binary file not shown.
BIN
WinRelease/portaudio_x86.dll
Executable file
BIN
WinRelease/portaudio_x86.dll
Executable file
Binary file not shown.
0
hsmodem.sln
Executable file → Normal file
0
hsmodem.sln
Executable file → Normal file
0
hsmodem.wse
Executable file → Normal file
0
hsmodem.wse
Executable file → Normal 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
0
hsmodem/SharedLibs/aarch64/libliquid.so
Normal file → Executable file
0
hsmodem/SharedLibs/aarch64/libsoundio.so
Normal file → Executable file
0
hsmodem/SharedLibs/aarch64/libsoundio.so
Normal file → Executable file
0
hsmodem/SharedLibs/aarch64/libsoundio.so.2
Normal file → Executable file
0
hsmodem/SharedLibs/aarch64/libsoundio.so.2
Normal file → Executable file
0
hsmodem/SharedLibs/aarch64/libsoundio.so.2.0.0
Normal file → Executable file
0
hsmodem/SharedLibs/aarch64/libsoundio.so.2.0.0
Normal file → Executable file
BIN
hsmodem/SharedLibs/windows/portaudio_x86.dll
Executable file
BIN
hsmodem/SharedLibs/windows/portaudio_x86.dll
Executable file
Binary file not shown.
@ -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
0
hsmodem/audio/1200.pcm
Normal file → Executable file
0
hsmodem/audio/2400.pcm
Normal file → Executable file
0
hsmodem/audio/2400.pcm
Normal file → Executable file
0
hsmodem/audio/3000.pcm
Normal file → Executable file
0
hsmodem/audio/3000.pcm
Normal file → Executable file
0
hsmodem/audio/4000.pcm
Normal file → Executable file
0
hsmodem/audio/4000.pcm
Normal file → Executable file
0
hsmodem/audio/4410.pcm
Normal file → Executable file
0
hsmodem/audio/4410.pcm
Normal file → Executable file
0
hsmodem/audio/4800.pcm
Normal file → Executable file
0
hsmodem/audio/4800.pcm
Normal file → Executable file
0
hsmodem/audio/5500.pcm
Normal file → Executable file
0
hsmodem/audio/5500.pcm
Normal file → Executable file
0
hsmodem/audio/6000.pcm
Normal file → Executable file
0
hsmodem/audio/6000.pcm
Normal file → Executable file
0
hsmodem/audio/6600.pcm
Normal file → Executable file
0
hsmodem/audio/6600.pcm
Normal file → Executable file
0
hsmodem/audio/7200.pcm
Normal file → Executable file
0
hsmodem/audio/7200.pcm
Normal file → Executable file
0
hsmodem/audio/amsat.pcm
Normal file → Executable file
0
hsmodem/audio/amsat.pcm
Normal file → Executable file
0
hsmodem/audio/bpsk.pcm
Normal file → Executable file
0
hsmodem/audio/bpsk.pcm
Normal file → Executable file
0
hsmodem/audio/kbps.pcm
Normal file → Executable file
0
hsmodem/audio/kbps.pcm
Normal file → Executable file
0
hsmodem/audio/psk8.pcm
Normal file → Executable file
0
hsmodem/audio/psk8.pcm
Normal file → Executable file
0
hsmodem/audio/qpsk.pcm
Normal file → Executable file
0
hsmodem/audio/qpsk.pcm
Normal file → Executable file
0
hsmodem/audio/sound0.pcm
Normal file → Executable file
0
hsmodem/audio/sound0.pcm
Normal file → Executable file
0
hsmodem/audio/sound1.pcm
Normal file → Executable file
0
hsmodem/audio/sound1.pcm
Normal file → Executable file
0
hsmodem/audio/wav2pcm.py
Normal file → Executable file
0
hsmodem/audio/wav2pcm.py
Normal file → Executable 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
0
hsmodem/endian.h
Normal file → Executable file
0
hsmodem/fec.h
Normal file → Executable file
0
hsmodem/fec.h
Normal file → Executable file
0
hsmodem/fec/schifra_crc.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_crc.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_ecc_traits.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_ecc_traits.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_erasure_channel.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_erasure_channel.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_error_processes.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_error_processes.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_fileio.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_fileio.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_galois_field.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_galois_field.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_galois_field_element.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_galois_field_element.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_galois_field_polynomial.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_galois_field_polynomial.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_galois_utilities.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_galois_utilities.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_bitio.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_bitio.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_block.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_block.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_codec_validator.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_codec_validator.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_encoder.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_encoder.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_file_decoder.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_file_decoder.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_file_encoder.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_file_encoder.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_file_interleaver.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_file_interleaver.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_general_codec.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_general_codec.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_interleaving.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_interleaving.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_product_code.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_product_code.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_speed_evaluator.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_reed_solomon_speed_evaluator.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_sequential_root_generator_polynomial_creator.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_sequential_root_generator_polynomial_creator.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_utilities.hpp
Normal file → Executable file
0
hsmodem/fec/schifra_utilities.hpp
Normal file → Executable 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
0
hsmodem/fftw_lib/fftw3.h
Normal file → Executable 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
0
hsmodem/frameformat.h
Normal file → Executable 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
|
||||
|
@ -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_
|
||||
|
@ -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">
|
||||
|
@ -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
97
hsmodem/libkmaudio/endian.h
Executable 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
170
hsmodem/libkmaudio/libkmaudio.cpp
Executable 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
252
hsmodem/libkmaudio/libkmaudio.h
Executable 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
|
||||
|
152
hsmodem/libkmaudio/libkmaudio_capture.cpp
Executable file
152
hsmodem/libkmaudio/libkmaudio_capture.cpp
Executable 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;
|
||||
}
|
212
hsmodem/libkmaudio/libkmaudio_capture_linux.cpp
Executable file
212
hsmodem/libkmaudio/libkmaudio_capture_linux.cpp
Executable 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
|
236
hsmodem/libkmaudio/libkmaudio_fifo.cpp
Executable file
236
hsmodem/libkmaudio/libkmaudio_fifo.cpp
Executable 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;
|
||||
}
|
||||
|
293
hsmodem/libkmaudio/libkmaudio_getDevices.cpp
Executable file
293
hsmodem/libkmaudio/libkmaudio_getDevices.cpp
Executable 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;
|
||||
}
|
217
hsmodem/libkmaudio/libkmaudio_getDevices_Linux.cpp
Executable file
217
hsmodem/libkmaudio/libkmaudio_getDevices_Linux.cpp
Executable 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
|
171
hsmodem/libkmaudio/libkmaudio_init.cpp
Executable file
171
hsmodem/libkmaudio/libkmaudio_init.cpp
Executable 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
|
||||
}
|
||||
|
||||
*/
|
78
hsmodem/libkmaudio/libkmaudio_init_linux.cpp
Executable file
78
hsmodem/libkmaudio/libkmaudio_init_linux.cpp
Executable 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
|
155
hsmodem/libkmaudio/libkmaudio_interface.cpp
Executable file
155
hsmodem/libkmaudio/libkmaudio_interface.cpp
Executable 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;
|
||||
}
|
||||
}
|
||||
}
|
169
hsmodem/libkmaudio/libkmaudio_playback.cpp
Executable file
169
hsmodem/libkmaudio/libkmaudio_playback.cpp
Executable 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;
|
||||
}
|
236
hsmodem/libkmaudio/libkmaudio_playback_linux.cpp
Executable file
236
hsmodem/libkmaudio/libkmaudio_playback_linux.cpp
Executable 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
|
109
hsmodem/libkmaudio/libkmaudio_resampler.cpp
Executable file
109
hsmodem/libkmaudio/libkmaudio_resampler.cpp
Executable 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
8823
hsmodem/libkmaudio/liquid.h
Executable file
File diff suppressed because it is too large
Load Diff
443
hsmodem/libkmaudio/pa_win_wasapi.h
Executable file
443
hsmodem/libkmaudio/pa_win_wasapi.h
Executable 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 */
|
199
hsmodem/libkmaudio/pa_win_waveformat.h
Executable file
199
hsmodem/libkmaudio/pa_win_waveformat.h
Executable 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
1225
hsmodem/libkmaudio/portaudio.h
Executable file
File diff suppressed because it is too large
Load Diff
1209
hsmodem/libkmaudio/soundio.h
Executable file
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
Loading…
x
Reference in New Issue
Block a user