mirror of
https://github.com/dj0abr/SSB_HighSpeed_Modem.git
synced 2024-11-21 19:55:17 -05:00
update
This commit is contained in:
parent
6adaf44425
commit
c8c377468f
BIN
WinRelease/hsmodem.exe
Executable file
BIN
WinRelease/hsmodem.exe
Executable file
Binary file not shown.
Binary file not shown.
@ -52,10 +52,11 @@ uint16_t *make_waterfall(float fre, int *retlen)
|
||||
// caprate 48k: downsample by 6
|
||||
// caprate 44,1k: downsample by 5,5
|
||||
|
||||
if (caprate == 48000)
|
||||
if (physcaprate == 48000)
|
||||
if (++downsamp < 6) return NULL;
|
||||
|
||||
if (caprate == 44100)
|
||||
// TODO: the following simple resamp results in double peeks in fft
|
||||
if (physcaprate == 44100)
|
||||
{
|
||||
if (downphase <= 1100)
|
||||
{
|
||||
@ -95,43 +96,60 @@ uint16_t *make_waterfall(float fre, int *retlen)
|
||||
fftrdy = 1;
|
||||
}
|
||||
|
||||
// signal detection
|
||||
// measure level at band edges
|
||||
float edgelevel = 0;
|
||||
for (int e = 0; e < 10; e++)
|
||||
edgelevel += f_fftout[e];
|
||||
for (int e = 390; e < fftcnt; e++)
|
||||
edgelevel += f_fftout[e];
|
||||
edgelevel /= 20;
|
||||
|
||||
// measure level at mid band
|
||||
float midlevel = 0;
|
||||
for (int e = 100; e < 300; e++)
|
||||
midlevel += f_fftout[e];
|
||||
midlevel /= 20;
|
||||
|
||||
//calc difference in %
|
||||
int idiff = (int)((edgelevel * 100) / midlevel);
|
||||
//printf("diff:%d %% edge:%10.6f midband:%10.6f\n", ldiff, idiff,edgelevel, midlevel);
|
||||
|
||||
// IC9700 ... noise makes about 5% idiff
|
||||
// Signal makes 0-2%, so we take the decision at 3%
|
||||
const int maxchecks = 3;
|
||||
static int rxstat = 0;
|
||||
if (idiff < 3)
|
||||
if (rx_in_sync == 0)
|
||||
{
|
||||
if (rxstat == maxchecks)
|
||||
// signal detection
|
||||
// measure level at band edges
|
||||
float edgelevel = 0;
|
||||
for (int e = 0; e < 10; e++)
|
||||
edgelevel += f_fftout[e];
|
||||
edgelevel /= 10;
|
||||
|
||||
for (int e = 300; e < 320; e++)
|
||||
edgelevel += f_fftout[e];
|
||||
edgelevel /= 20;
|
||||
|
||||
// measure level at mid band
|
||||
float midlevel = 0;
|
||||
for (int e = 100; e < 300; e++)
|
||||
midlevel += f_fftout[e];
|
||||
midlevel /= 200;
|
||||
|
||||
//calc difference in %
|
||||
int idiff = (int)((edgelevel * 100) / midlevel);
|
||||
//printf("diff:%d %% edge:%10.6f midband:%10.6f\n", idiff,edgelevel, midlevel);
|
||||
|
||||
// idiff SDR Console:
|
||||
// no signal ... > 100
|
||||
// signal < 20
|
||||
static int checks = 0;
|
||||
static int lastsig = 0;
|
||||
int sig = 0;
|
||||
|
||||
// check if signal detected or not
|
||||
if (idiff > 100) sig = 0;
|
||||
if (idiff < 20) sig = 1;
|
||||
|
||||
rxlevel_deteced = sig;
|
||||
|
||||
// check if changed since last check
|
||||
if (sig != lastsig)
|
||||
{
|
||||
printf("===>>> level detected, reset modem\n");
|
||||
trigger_resetmodem = 1;
|
||||
rxlevel_deteced = 1;
|
||||
lastsig = sig;
|
||||
checks = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (checks <= 3) checks++;
|
||||
if (checks == 3)
|
||||
{
|
||||
if (sig == 1)
|
||||
{
|
||||
printf("===>>> level detected, reset modem\n");
|
||||
trigger_resetmodem = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(rxstat <= maxchecks) rxstat++;
|
||||
}
|
||||
else
|
||||
{
|
||||
rxstat = 0;
|
||||
rxlevel_deteced = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ void IO_MIC_UNLOCK() { pthread_mutex_unlock(&io_mic_crit_sec); }
|
||||
void IO_LS_UNLOCK() { pthread_mutex_unlock(&io_ls_crit_sec); }
|
||||
#endif
|
||||
|
||||
#define VOICE_PLAYBACK_BUFLEN (48000 * 15) // space for 10 seconds of samples
|
||||
#define VOICE_PLAYBACK_BUFLEN (500000)
|
||||
#define VOICE_CAPTURE_BUFLEN (10000) //48000)// * 10) // space for 10 seconds of samples
|
||||
|
||||
int io_mic_wridx = 0;
|
||||
|
@ -31,35 +31,6 @@
|
||||
* !!! compile x86 (32bit) version !!! all supplied dlls are 32 bit !!!
|
||||
* ====================================================================
|
||||
*
|
||||
* 3rd party libraries:
|
||||
* 1) BASS Audio from https://www.un4seen.com/
|
||||
copy bass.h and bass.lib into source directory
|
||||
Windows: copy bass.dll into executable directory
|
||||
Linux: copy libbass.so into shared-lib folder, usually /usr/local/lib
|
||||
! NOTE: for PC-Linux and ARM-Linux you need different libraries !
|
||||
|
||||
2) liquid-DSP
|
||||
Linux Install Script:
|
||||
this installs it from source
|
||||
|
||||
sudo apt install git autoconf libsndfile-dev libasound-dev
|
||||
git clone git://github.com/jgaeddert/liquid-dsp.git
|
||||
cd liquid-dsp
|
||||
./bootstrap.sh
|
||||
./configure
|
||||
make -j 8
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
a working copy of the source code is in ../3rdParty/liquid-dsp
|
||||
to use this source simply remove the "git clone" line from above script
|
||||
it installs libliquid.so into /usr/local/lib (Ubuntu) and
|
||||
liquid.h into /usr/local/include/liquid/
|
||||
|
||||
Windows:
|
||||
ready libraries are in ../3rdParty/liquid-dsp-windows
|
||||
copy liquid.h and liquid.lib into source directory
|
||||
copy liquid.dll into executable directory
|
||||
*/
|
||||
|
||||
|
||||
@ -97,6 +68,7 @@ int restart_modems = 0;
|
||||
int trigger_resetmodem = 0;
|
||||
|
||||
int caprate = 44100;
|
||||
int physcaprate = 44100;
|
||||
int txinterpolfactor = 20;
|
||||
int rxPreInterpolfactor = 5;
|
||||
int linespeed = 4410;
|
||||
@ -203,7 +175,7 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
// loop voice mic to LS
|
||||
float f;
|
||||
if (io_mic_read_fifo(&f))
|
||||
while (io_mic_read_fifo(&f))
|
||||
{
|
||||
io_ls_write_fifo(f);
|
||||
}
|
||||
@ -213,7 +185,7 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
// send mic to codec
|
||||
float f;
|
||||
if (io_mic_read_fifo(&f))
|
||||
while (io_mic_read_fifo(&f))
|
||||
{
|
||||
encode(f);
|
||||
}
|
||||
@ -590,7 +562,7 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
||||
fnd = 0;
|
||||
trigger_resetmodem = 0;
|
||||
rx_in_sync = 0;
|
||||
printf("no signal detected %d, reset RX modem\n", wt);
|
||||
//printf("no signal detected %d, reset RX modem\n", wt);
|
||||
resetModem();
|
||||
}
|
||||
else if (fnd >= wt)
|
||||
|
@ -76,6 +76,7 @@
|
||||
|
||||
// voice audio sampling rate
|
||||
#define VOICE_SAMPRATE 48000 // do NOT change, OPUS works with 48k only
|
||||
#define AUDIO_SAMPRATE 48000 // do NOT change, WASAPI VACs work with 48k only
|
||||
|
||||
enum _VOICEMODES_ {
|
||||
VOICEMODE_OFF,
|
||||
@ -180,6 +181,8 @@ 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 km_symtrack_cccf_create(int _ftype,
|
||||
unsigned int _k,
|
||||
@ -222,6 +225,8 @@ extern int rxlevel_deteced;
|
||||
extern int rx_in_sync;
|
||||
extern float softwareMICvolume;
|
||||
extern float softwareLSvolume;
|
||||
extern int physcaprate;
|
||||
extern int restart_modems;
|
||||
|
||||
#ifdef _LINUX_
|
||||
int isRunning(char* prgname);
|
||||
|
@ -223,10 +223,6 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="bass.h" />
|
||||
<ClInclude Include="bassenc.h" />
|
||||
<ClInclude Include="bassenc_opus.h" />
|
||||
<ClInclude Include="basswasapi.h" />
|
||||
<ClInclude Include="codec2.h" />
|
||||
<ClInclude Include="endian.h" />
|
||||
<ClInclude Include="fec.h" />
|
||||
|
@ -83,9 +83,6 @@
|
||||
<ClInclude Include="frameformat.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="bass.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="udp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -95,21 +92,12 @@
|
||||
<ClInclude Include="fftw_lib\fftw3.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="basswasapi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fec.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="symboltracker.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="bassenc_opus.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="bassenc.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="opus.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -212,11 +212,16 @@ void modulator(uint8_t sym_in)
|
||||
nco_crcf dnnco = NULL;
|
||||
symtrack_cccf symtrack = NULL;
|
||||
firdecim_crcf decim = NULL;
|
||||
msresamp_crcf adecim = NULL;
|
||||
|
||||
// decimator parameters
|
||||
unsigned int m_predec = 8; // filter delay
|
||||
float As_predec = 40.0f; // stop-band att
|
||||
|
||||
// adecimator parameters
|
||||
float r_OutDivInRatio; // resampling rate (output/input)
|
||||
float As_adecim = 60.0f; // resampling filter stop-band attenuation [dB]
|
||||
|
||||
// symtrack parameters
|
||||
int ftype_st = LIQUID_FIRFILT_RRC;
|
||||
unsigned int k_st = 4; // samples per symbol
|
||||
@ -240,20 +245,24 @@ void init_demodulator()
|
||||
// create pre-decimator
|
||||
decim = firdecim_crcf_create_kaiser(rxPreInterpolfactor, m_predec, As_predec);
|
||||
firdecim_crcf_set_scale(decim, 1.0f/(float)rxPreInterpolfactor);
|
||||
|
||||
// create arbitrary pre decimator
|
||||
// if Audio SR is 48000 but caprate is 44100
|
||||
r_OutDivInRatio = (float)((float)caprate / 48000.0);
|
||||
adecim = msresamp_crcf_create(r_OutDivInRatio, As_adecim);
|
||||
|
||||
// create symbol tracking synchronizer
|
||||
//k_st = txinterpolfactor;
|
||||
//symtrack = km_symtrack_cccf_create(ftype_st,k_st,m_st,beta_st,getMod());
|
||||
km_symtrack_cccf_create(ftype_st, k_st, m_st, beta_st, getMod());
|
||||
//symtrack_cccf_set_bandwidth(symtrack,bandwidth_st);
|
||||
km_symtrack_cccf_set_bandwidth(bandwidth_st);
|
||||
}
|
||||
|
||||
void close_demodulator()
|
||||
{
|
||||
if(decim != NULL) firdecim_crcf_destroy(decim);
|
||||
if(adecim) msresamp_crcf_destroy(adecim);
|
||||
symtrack = NULL;
|
||||
decim = NULL;
|
||||
adecim = NULL;
|
||||
}
|
||||
|
||||
void resetModem()
|
||||
@ -340,7 +349,7 @@ static int ccol_idx = 0;
|
||||
float f;
|
||||
int ret = io_cap_read_fifo(&f);
|
||||
if(ret == 0) return 0;
|
||||
|
||||
|
||||
if (VoiceAudioMode == VOICEMODE_LISTENAUDIOIN)
|
||||
{
|
||||
io_ls_write_fifo(f);
|
||||
@ -351,7 +360,21 @@ static int ccol_idx = 0;
|
||||
|
||||
getMax(f);
|
||||
|
||||
make_FFTdata(f*60);
|
||||
make_FFTdata(f * 60);
|
||||
|
||||
if (caprate == 44100 && physcaprate == 48000)
|
||||
{
|
||||
// the sound card capture for a VAC always works with 48000 because
|
||||
// a VAC cannot be set to a specific cap rate in shared mode
|
||||
unsigned int num_written = 0;
|
||||
liquid_float_complex in;
|
||||
liquid_float_complex out;
|
||||
in.real = f;
|
||||
in.imag = 0;
|
||||
msresamp_crcf_execute(adecim, &in, 1, &out, &num_written);
|
||||
if (num_written == 0) return 1;
|
||||
f = out.real;
|
||||
}
|
||||
|
||||
// downconvert into baseband
|
||||
// still at soundcard sample rate
|
||||
@ -376,51 +399,55 @@ static int ccol_idx = 0;
|
||||
liquid_float_complex y;
|
||||
firdecim_crcf_execute(decim, ccol, &y);
|
||||
|
||||
unsigned int num_symbols_sync;
|
||||
liquid_float_complex syms;
|
||||
//symtrack_cccf_execute(symtrack, y, &syms, &num_symbols_sync);
|
||||
unsigned int nsym_out; // output symbol
|
||||
km_symtrack_execute(y, &syms, &num_symbols_sync,&nsym_out);
|
||||
|
||||
if(num_symbols_sync > 1) printf("symtrack_cccf_execute %d output symbols ???\n",num_symbols_sync);
|
||||
if(num_symbols_sync != 0)
|
||||
{
|
||||
unsigned int sym_out; // output symbol
|
||||
sym_out = nsym_out;
|
||||
unsigned int num_written = 1;
|
||||
|
||||
measure_speed_syms(1);
|
||||
|
||||
// try to extract a complete frame
|
||||
uint8_t symb = sym_out;
|
||||
if(bitsPerSymbol == 2) symb ^= (symb>>1);
|
||||
GRdata_rxdata(&symb, 1, NULL);
|
||||
|
||||
// send the data "as is" to app for Constellation Diagram
|
||||
// we have about 2000 S/s, but this many points would make the GUI slow
|
||||
// so we send only every x
|
||||
static int ev = 0;
|
||||
if (++ev >= 10)
|
||||
for (unsigned int sa = 0; sa < num_written; sa++)
|
||||
{
|
||||
unsigned int num_symbols_sync;
|
||||
liquid_float_complex syms;
|
||||
unsigned int nsym_out; // output symbol
|
||||
km_symtrack_execute(y, &syms, &num_symbols_sync, &nsym_out);
|
||||
|
||||
if (num_symbols_sync > 1) printf("symtrack_cccf_execute %d output symbols ???\n", num_symbols_sync);
|
||||
if (num_symbols_sync != 0)
|
||||
{
|
||||
ev = 0;
|
||||
int32_t re = (int32_t)(syms.real * 16777216.0);
|
||||
int32_t im = (int32_t)(syms.imag * 16777216.0);
|
||||
uint8_t txpl[13];
|
||||
int idx = 0;
|
||||
txpl[idx++] = 5; // type 5: IQ data follows
|
||||
uint32_t sy = 0x3e8;
|
||||
txpl[idx++] = sy >> 24;
|
||||
txpl[idx++] = sy >> 16;
|
||||
txpl[idx++] = sy >> 8;
|
||||
txpl[idx++] = sy;
|
||||
txpl[idx++] = re >> 24;
|
||||
txpl[idx++] = re >> 16;
|
||||
txpl[idx++] = re >> 8;
|
||||
txpl[idx++] = re;
|
||||
txpl[idx++] = im >> 24;
|
||||
txpl[idx++] = im >> 16;
|
||||
txpl[idx++] = im >> 8;
|
||||
txpl[idx++] = im;
|
||||
sendUDP(appIP, UdpDataPort_ModemToApp, txpl, 13);
|
||||
unsigned int sym_out; // output symbol
|
||||
sym_out = nsym_out;
|
||||
|
||||
//measure_speed_syms(1);
|
||||
|
||||
// try to extract a complete frame
|
||||
uint8_t symb = sym_out;
|
||||
if (bitsPerSymbol == 2) symb ^= (symb >> 1);
|
||||
GRdata_rxdata(&symb, 1, NULL);
|
||||
|
||||
// send the data "as is" to app for Constellation Diagram
|
||||
// we have about 2000 S/s, but this many points would make the GUI slow
|
||||
// so we send only every x
|
||||
static int ev = 0;
|
||||
if (++ev >= 10)
|
||||
{
|
||||
ev = 0;
|
||||
int32_t re = (int32_t)(syms.real * 16777216.0);
|
||||
int32_t im = (int32_t)(syms.imag * 16777216.0);
|
||||
uint8_t txpl[13];
|
||||
int idx = 0;
|
||||
txpl[idx++] = 5; // type 5: IQ data follows
|
||||
uint32_t sy = 0x3e8;
|
||||
txpl[idx++] = sy >> 24;
|
||||
txpl[idx++] = sy >> 16;
|
||||
txpl[idx++] = sy >> 8;
|
||||
txpl[idx++] = sy;
|
||||
txpl[idx++] = re >> 24;
|
||||
txpl[idx++] = re >> 16;
|
||||
txpl[idx++] = re >> 8;
|
||||
txpl[idx++] = re;
|
||||
txpl[idx++] = im >> 24;
|
||||
txpl[idx++] = im >> 16;
|
||||
txpl[idx++] = im >> 8;
|
||||
txpl[idx++] = im;
|
||||
sendUDP(appIP, UdpDataPort_ModemToApp, txpl, 13);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,9 @@ typedef struct _AUDIODEV_ {
|
||||
AUDIODEV audiodev[MAXAUDIODEVICES];
|
||||
int audiodevidx = 0;
|
||||
|
||||
bool pbrawdev = true;
|
||||
bool caprawdev = true;
|
||||
|
||||
void print_devs()
|
||||
{
|
||||
printf("\n ==== AUDIO devices ====\n");
|
||||
@ -80,11 +83,6 @@ int print_device(struct SoundIoDevice* device)
|
||||
{
|
||||
if (!device->probe_error)
|
||||
{
|
||||
/*#ifdef _WIN32_
|
||||
// only use raw (exclusive) devices
|
||||
if (device->is_raw == false) return 0;
|
||||
#endif*/
|
||||
|
||||
// ignore if exists
|
||||
for (int i = 0; i < audiodevidx; i++)
|
||||
if (!strcmp(device->id, audiodev[i].id)) return 0;
|
||||
@ -223,8 +221,8 @@ int min_int(int a, int b)
|
||||
|
||||
void read_callback(struct SoundIoInStream* instream, int frame_count_min, int frame_count_max)
|
||||
{
|
||||
|
||||
int err;
|
||||
if (instream == NULL) return;
|
||||
//printf("cap: %d %d\n", frame_count_min, frame_count_max);
|
||||
//int chans = instream->layout.channel_count;
|
||||
|
||||
@ -237,7 +235,8 @@ void read_callback(struct SoundIoInStream* instream, int frame_count_min, int fr
|
||||
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
|
||||
{
|
||||
fprintf(stderr, "begin read error: %s", soundio_strerror(err));
|
||||
exit(1);
|
||||
restart_modems = 1;
|
||||
return;
|
||||
}
|
||||
if (!frame_count)
|
||||
break;
|
||||
@ -246,25 +245,47 @@ void read_callback(struct SoundIoInStream* instream, int frame_count_min, int fr
|
||||
{
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1)
|
||||
{
|
||||
int16_t rxdata;
|
||||
memcpy(&rxdata, areas[ch].ptr, instream->bytes_per_sample);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
if (ch == 0)
|
||||
if (caprawdev == false)
|
||||
{
|
||||
float f = rxdata;
|
||||
f /= 32768;
|
||||
f *= softwareCAPvolume;
|
||||
io_cap_write_fifo(f);
|
||||
// shared device
|
||||
float frxdata;
|
||||
memcpy(&frxdata, areas[ch].ptr, instream->bytes_per_sample);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
if (ch == 0)
|
||||
{
|
||||
float f = frxdata;
|
||||
f *= softwareCAPvolume;
|
||||
io_cap_write_fifo(f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// raw device
|
||||
// shared device
|
||||
int16_t rxdata;
|
||||
memcpy(&rxdata, areas[ch].ptr, instream->bytes_per_sample);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
if (ch == 0)
|
||||
{
|
||||
float f = rxdata;
|
||||
f /= 32768;
|
||||
f *= softwareCAPvolume;
|
||||
io_cap_write_fifo(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf("%d into fifo\n", frame_count);
|
||||
// needs to sleep or it will not work correctly, no idea why
|
||||
sleep_ms(1);
|
||||
|
||||
//measure_speed_bps(frame_count);
|
||||
|
||||
if ((err = soundio_instream_end_read(instream)))
|
||||
{
|
||||
fprintf(stderr, "end read error: %s", soundio_strerror(err));
|
||||
exit(1);
|
||||
restart_modems = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
@ -272,106 +293,91 @@ void read_callback(struct SoundIoInStream* instream, int frame_count_min, int fr
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
void read_callback(struct SoundIoInStream* instream, int frame_count_min, int frame_count_max)
|
||||
{
|
||||
int err;
|
||||
//printf("cap: %d %d\n", frame_count_min, frame_count_max);
|
||||
// bytes_per_frame == 4 because we use float
|
||||
// instream->bytes_per_sample/bytes_per_frame = 1 (mono) or 2 (stereo)
|
||||
int chans = instream->layout.channel_count;
|
||||
|
||||
struct SoundIoChannelArea* areas;
|
||||
// samples are in areas.ptr
|
||||
int frames_left = frame_count_max; // take all
|
||||
while (1)
|
||||
{
|
||||
int frame_count = frames_left;
|
||||
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
|
||||
{
|
||||
fprintf(stderr, "begin read error: %s", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
// do something with the data in *area.ptr
|
||||
// take a float every chans*4 Bytes
|
||||
int16_t* samples = (int16_t*)(areas[0].ptr);
|
||||
int pos = 0;
|
||||
for (int i = 0; i < frame_count; i++)
|
||||
{
|
||||
float f = samples[pos];
|
||||
f /= 32768;
|
||||
f *= softwareCAPvolume;
|
||||
io_cap_write_fifo(f);
|
||||
pos += chans;
|
||||
}
|
||||
|
||||
//measure_speed_bps(frame_count);
|
||||
|
||||
if ((err = soundio_instream_end_read(instream))) {
|
||||
fprintf(stderr, "end read error: %s", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
if (frames_left <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
void overflow_callback(struct SoundIoInStream* instream)
|
||||
{
|
||||
static int count = 0;
|
||||
printf("overflow %d\n", ++count);
|
||||
}
|
||||
|
||||
#define MAXCAPCHUNKLEN 50000
|
||||
// #define SINEWAVETEST
|
||||
|
||||
#ifdef SINEWAVETEST
|
||||
static const double PI = 3.14159265358979323846264338328;
|
||||
static double seconds_offset = 0.0;
|
||||
#endif
|
||||
|
||||
static void write_callback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max)
|
||||
{
|
||||
//printf("pb: %d %d\n", frame_count_min, frame_count_max);
|
||||
#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 = frame_count_max;
|
||||
|
||||
while (1)
|
||||
{
|
||||
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, "unrecoverable stream error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
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));
|
||||
restart_modems = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
float f[MAXCAPCHUNKLEN];
|
||||
//printf("ck: %d\n", frame_count);
|
||||
|
||||
float* f = (float*)malloc(frame_count * sizeof(float));
|
||||
int fiforet = io_pb_read_fifo_num(f, frame_count);
|
||||
if (fiforet == 0)
|
||||
{
|
||||
// elements not available, fill with zeroes
|
||||
//printf("not enough data, send zeroes\n");
|
||||
memset(f, 0, sizeof(float) * frame_count);
|
||||
}
|
||||
|
||||
const struct SoundIoChannelLayout* layout = &outstream->layout;
|
||||
|
||||
for (int frame = 0; frame < frame_count; frame++)
|
||||
for (int frame = 0; frame < frame_count; frame += 1)
|
||||
{
|
||||
for (int channel = 0; channel < layout->channel_count; channel++)
|
||||
#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)
|
||||
{
|
||||
write_sample_s16ne(areas[channel].ptr, f[frame]);
|
||||
float ftx = f[frame] * softwarePBvolume;
|
||||
if (pbrawdev == false)
|
||||
{
|
||||
#ifdef SINEWAVETEST
|
||||
write_sample_float32ne(areas[channel].ptr, sample); // sine wave test tone
|
||||
#endif
|
||||
write_sample_float32ne(areas[channel].ptr, ftx);
|
||||
}
|
||||
else
|
||||
write_sample_s16ne(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
|
||||
|
||||
free(f);
|
||||
|
||||
if ((err = soundio_outstream_end_write(outstream))) {
|
||||
if (err == SoundIoErrorUnderflow)
|
||||
return;
|
||||
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
restart_modems = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
@ -379,66 +385,7 @@ static void write_callback(struct SoundIoOutStream* outstream, int frame_count_m
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
static void write_callback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max)
|
||||
{
|
||||
int chans = outstream->layout.channel_count;
|
||||
struct SoundIoChannelArea* areas;
|
||||
int err;
|
||||
int frames_left = min_int(frame_count_max,MAXCAPCHUNKLEN);// frame_count_max;
|
||||
//printf("\nmin: %d max:%d\n", frame_count_min, frame_count_max);
|
||||
|
||||
// we have to write frame_count_max, not less, or we get an underrun
|
||||
// this has to be written in chunks requested by soundio_outstream_begin_write
|
||||
float f[MAXCAPCHUNKLEN];
|
||||
while (1)
|
||||
{
|
||||
int frame_count = frames_left;
|
||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) {
|
||||
printf("unrecoverable soundio_outstream_begin_write error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
if (!frame_count) break; // will normally never happen
|
||||
//printf("chunk: %d\n", frame_count);
|
||||
|
||||
// soundio_outstream_begin_write requested to write frame_count elements
|
||||
int fiforet = io_pb_read_fifo_num(f, frame_count);
|
||||
if (fiforet == 0)
|
||||
{
|
||||
// elements not available, fill with zeroes
|
||||
//printf("not enough data, send zeroes\n");
|
||||
memset(f, 0, sizeof(float) * frame_count);
|
||||
}
|
||||
|
||||
// apply volume
|
||||
for (int i = 0; i < frame_count; i++)
|
||||
f[i] *= softwarePBvolume;
|
||||
|
||||
// put data into soundio buffer
|
||||
for (int frame = 0; frame < frame_count; frame++)
|
||||
{
|
||||
for (int ch = 0; ch < chans; ch++)
|
||||
{
|
||||
int16_t* s = (int16_t*)areas[ch].ptr;
|
||||
*s = (int16_t)(f[frame] * 32768.0);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
}
|
||||
}
|
||||
|
||||
// and finalize this chunk
|
||||
if ((err = soundio_outstream_end_write(outstream))) {
|
||||
if (err == SoundIoErrorUnderflow)
|
||||
return;
|
||||
printf("unrecoverable soundio_outstream_end_write error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
if (frames_left <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
void underflow_callback(struct SoundIoOutStream* outstream)
|
||||
{
|
||||
static int count = 0;
|
||||
@ -452,7 +399,7 @@ int io_init_sound(char *pbname, char *capname)
|
||||
init_audio_result = 0;
|
||||
|
||||
printf("\n ==== IO INIT AUDIO devices ====\n");
|
||||
printf("requested: <%s> <%s>\ncapture rate:%d\n",pbname,capname,caprate);
|
||||
printf("requested\nTX:<%s>\nRX:<%s>\ncapture rate:%d\n\n",pbname,capname,caprate);
|
||||
|
||||
io_close_audio();
|
||||
|
||||
@ -491,17 +438,26 @@ int io_init_sound(char *pbname, char *capname)
|
||||
if (capdevid == NULL) return 0;
|
||||
|
||||
// define the capture device
|
||||
printf("selected CAP device:\nname:%s\nid :%s\n", capname, capdevid);
|
||||
|
||||
soundio_flush_events(soundio);
|
||||
|
||||
// under Windows we usually use raw devices. This does not work with
|
||||
// virtual sound cards due to problems in libsoundio
|
||||
// for VACs we use shared devices, otherwise raw
|
||||
pbrawdev = true;
|
||||
if (strstr(pbname, "irtual") || strstr(pbname, "VAC"))
|
||||
pbrawdev = false;
|
||||
|
||||
caprawdev = true;
|
||||
if (strstr(capname, "irtual") || strstr(capname, "VAC"))
|
||||
caprawdev = false;
|
||||
|
||||
for (int i = 0; i < soundio_input_device_count(soundio); i++)
|
||||
{
|
||||
io_cap_device = NULL;
|
||||
struct SoundIoDevice* device = soundio_get_input_device(soundio, i);
|
||||
if (strcmp(device->id, capdevid) == 0
|
||||
#ifdef _WIN32_
|
||||
&& device->is_raw == true
|
||||
&& device->is_raw == caprawdev
|
||||
#endif
|
||||
)
|
||||
{
|
||||
@ -529,15 +485,27 @@ int io_init_sound(char *pbname, char *capname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
instream->format = SoundIoFormatS16NE;
|
||||
instream->sample_rate = caprate;
|
||||
// raw devices: 16bit LE, shared devices float
|
||||
if (caprawdev)
|
||||
{
|
||||
instream->format = SoundIoFormatS16NE;
|
||||
instream->sample_rate = caprate;
|
||||
physcaprate = caprate;
|
||||
}
|
||||
else
|
||||
{
|
||||
// a VAC needs these settings or it will not work with 44100
|
||||
instream->format = SoundIoFormatFloat32NE;
|
||||
instream->sample_rate = AUDIO_SAMPRATE;
|
||||
physcaprate = AUDIO_SAMPRATE;
|
||||
}
|
||||
instream->software_latency = 0.0;
|
||||
instream->read_callback = read_callback;
|
||||
instream->overflow_callback = overflow_callback;
|
||||
instream->userdata = NULL;
|
||||
|
||||
if ((err = soundio_instream_open(instream))) {
|
||||
printf("unable to open input stream: %s", soundio_strerror(err));
|
||||
printf("unable to open input stream: %d: %s", err, soundio_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -546,18 +514,21 @@ int io_init_sound(char *pbname, char *capname)
|
||||
return 0;
|
||||
}
|
||||
init_audio_result |= 2;
|
||||
|
||||
printf("selected CAPTURE device:\nname:%s\nid :%s\n", capname, capdevid);
|
||||
printf("physical capture rate:%d, logical capture rate:%d\n", physcaprate, caprate);
|
||||
printf("format: %s\n\n", soundio_format_string(instream->format));
|
||||
|
||||
// the CAP callback is running now
|
||||
|
||||
|
||||
// define the playback device
|
||||
printf("selected PB device:\nname:%s\nid :%s\n", pbname, pbdevid);
|
||||
|
||||
for (int i = 0; i < soundio_output_device_count(soundio); i++)
|
||||
{
|
||||
io_pb_device = NULL;
|
||||
struct SoundIoDevice* device = soundio_get_output_device(soundio, i);
|
||||
if (strcmp(device->id, pbdevid) == 0
|
||||
#ifdef _WIN32_
|
||||
&& device->is_raw == true
|
||||
&& device->is_raw == pbrawdev
|
||||
#endif
|
||||
)
|
||||
{
|
||||
@ -585,9 +556,14 @@ int io_init_sound(char *pbname, char *capname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
outstream->format = SoundIoFormatS16NE;
|
||||
// raw devices: 16bit LE, shared devices float
|
||||
if (pbrawdev)
|
||||
outstream->format = SoundIoFormatS16NE;
|
||||
else
|
||||
outstream->format = SoundIoFormatFloat32NE;
|
||||
|
||||
outstream->sample_rate = caprate;
|
||||
outstream->software_latency = 0.0;
|
||||
outstream->software_latency = 1.0;
|
||||
outstream->write_callback = write_callback;
|
||||
outstream->underflow_callback = underflow_callback;
|
||||
outstream->userdata = NULL;
|
||||
@ -603,7 +579,9 @@ int io_init_sound(char *pbname, char *capname)
|
||||
}
|
||||
init_audio_result |= 1;
|
||||
|
||||
printf("==== Audio init finished: %d ====\n", init_audio_result);
|
||||
printf("selected PLAYBACK device:\nname:%s\nid :%s\n", pbname, pbdevid);
|
||||
printf("physical capture rate:%d, logical capture rate:%d\n", caprate, caprate);
|
||||
printf("format: %s\n\n", soundio_format_string(outstream->format));
|
||||
|
||||
return init_audio_result;
|
||||
}
|
||||
|
665
hsmodem/soundio_backup.cpp
Executable file
665
hsmodem/soundio_backup.cpp
Executable file
@ -0,0 +1,665 @@
|
||||
/*
|
||||
* High Speed modem to transfer data in a 2,7kHz SSB channel
|
||||
* =========================================================
|
||||
* Author: DJ0ABR
|
||||
*
|
||||
* (c) DJ0ABR
|
||||
* www.dj0abr.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* soundio.c ... interface to libsoundio
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hsmodem.h"
|
||||
|
||||
void io_cap_write_fifo(float sample);
|
||||
|
||||
#define MAXAUDIODEVICES 50
|
||||
|
||||
struct SoundIo* soundio = NULL;
|
||||
struct SoundIoDevice* io_pb_device = NULL;
|
||||
struct SoundIoDevice* io_cap_device = NULL;
|
||||
struct SoundIoInStream* instream = NULL;
|
||||
struct SoundIoOutStream* outstream = NULL;
|
||||
|
||||
|
||||
typedef struct _AUDIODEV_ {
|
||||
int in_out = 0; // 0=in, 1=out
|
||||
char name[1000] = { 0 };
|
||||
char id[1000] = { 0 };
|
||||
int minsamprate = 44100;
|
||||
int maxsamprate = 48000;
|
||||
int stereo_mono = 2; // 1=mono, 2=stereo
|
||||
} AUDIODEV;
|
||||
|
||||
AUDIODEV audiodev[MAXAUDIODEVICES];
|
||||
int audiodevidx = 0;
|
||||
|
||||
void print_devs()
|
||||
{
|
||||
printf("\n ==== AUDIO devices ====\n");
|
||||
for (int i = 0; i < audiodevidx; i++)
|
||||
{
|
||||
if(i>0) printf(" -----------------\n");
|
||||
printf("Name: %s\n", audiodev[i].name);
|
||||
printf("ID : %s\n", audiodev[i].id);
|
||||
printf("I/O : %s\n", (audiodev[i].in_out == 0) ? "record":"playback");
|
||||
printf("Chan: %s\n", (audiodev[i].stereo_mono == 2) ? "stereo" : "mono");
|
||||
printf("minR: %d\n", audiodev[i].minsamprate);
|
||||
printf("maxR: %d\n", audiodev[i].maxsamprate);
|
||||
}
|
||||
printf("\n =======================\n");
|
||||
}
|
||||
|
||||
static void get_channel_layout(const struct SoundIoChannelLayout* layout)
|
||||
{
|
||||
if (layout->name)
|
||||
{
|
||||
if (strstr(layout->name, "ereo"))
|
||||
audiodev[audiodevidx].stereo_mono = 2;
|
||||
if (strstr(layout->name, "ono"))
|
||||
audiodev[audiodevidx].stereo_mono = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int print_device(struct SoundIoDevice* device)
|
||||
{
|
||||
if (!device->probe_error)
|
||||
{
|
||||
/*#ifdef _WIN32_
|
||||
// only use raw (exclusive) devices
|
||||
if (device->is_raw == false) return 0;
|
||||
#endif*/
|
||||
|
||||
// ignore if exists
|
||||
for (int i = 0; i < audiodevidx; i++)
|
||||
if (!strcmp(device->id, audiodev[i].id)) return 0;
|
||||
|
||||
if (strstr(device->name, "onitor")) return 0;
|
||||
|
||||
strncpy(audiodev[audiodevidx].id, device->id, 999);
|
||||
audiodev[audiodevidx].id[999] = 0;
|
||||
strncpy(audiodev[audiodevidx].name, device->name, 999);
|
||||
audiodev[audiodevidx].name[999] = 0;
|
||||
|
||||
for (int i = 0; i < device->layout_count; i++)
|
||||
get_channel_layout(&device->layouts[i]);
|
||||
|
||||
for (int i = 0; i < device->sample_rate_count; i++)
|
||||
{
|
||||
struct SoundIoSampleRateRange* range = &device->sample_rates[i];
|
||||
if (range->min < audiodev[audiodevidx].minsamprate)
|
||||
audiodev[audiodevidx].minsamprate = range->min;
|
||||
|
||||
if (range->max > audiodev[audiodevidx].maxsamprate)
|
||||
audiodev[audiodevidx].maxsamprate = range->max;
|
||||
}
|
||||
if (audiodev[audiodevidx].minsamprate > 44100)
|
||||
return 0;
|
||||
if (audiodev[audiodevidx].maxsamprate < 48000)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scan_devices(struct SoundIo* soundio)
|
||||
{
|
||||
audiodevidx = 0;
|
||||
for (int i = 0; i < soundio_input_device_count(soundio); i++)
|
||||
{
|
||||
|
||||
struct SoundIoDevice* device = soundio_get_input_device(soundio, i);
|
||||
if (print_device(device) == 1)
|
||||
{
|
||||
audiodev[audiodevidx].in_out = 0;
|
||||
audiodevidx++;
|
||||
}
|
||||
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 (print_device(device) == 1)
|
||||
{
|
||||
audiodev[audiodevidx].in_out = 1;
|
||||
audiodevidx++;
|
||||
}
|
||||
soundio_device_unref(device);
|
||||
}
|
||||
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: ~
|
||||
uint8_t io_devstring[MAXDEVSTRLEN + 100];
|
||||
|
||||
void io_buildUdpAudioList()
|
||||
{
|
||||
memset(io_devstring, 0, sizeof(io_devstring));
|
||||
io_devstring[0] = ' '; // placeholder for ID for this UDP message
|
||||
io_devstring[1] = '0' + init_audio_result;
|
||||
io_devstring[2] = '0' + init_voice_result;
|
||||
|
||||
// playback devices
|
||||
for (int i = 0; i < audiodevidx; i++)
|
||||
{
|
||||
if (audiodev[i].in_out == 1)
|
||||
{
|
||||
strcat((char*)io_devstring, audiodev[i].name);
|
||||
strcat((char*)io_devstring, "~"); // audio device separator
|
||||
}
|
||||
}
|
||||
|
||||
strcat((char*)(io_devstring + 1), "^"); // PB, CAP separator
|
||||
|
||||
// capture devices
|
||||
for (int i = 0; i < audiodevidx; i++)
|
||||
{
|
||||
if (audiodev[i].in_out == 0)
|
||||
{
|
||||
strcat((char*)io_devstring, audiodev[i].name);
|
||||
strcat((char*)io_devstring, "~"); // audio device separator
|
||||
}
|
||||
}
|
||||
|
||||
io_devstring[0] = 3; // ID for this UDP message
|
||||
}
|
||||
|
||||
uint8_t* io_getAudioDevicelist(int* len)
|
||||
{
|
||||
// update Status
|
||||
io_devstring[1] = '0' + init_audio_result;
|
||||
io_devstring[2] = '0' + init_voice_result;
|
||||
|
||||
*len = strlen((char*)(io_devstring + 1)) + 1;
|
||||
return io_devstring;
|
||||
}
|
||||
|
||||
void io_readAudioDevices()
|
||||
{
|
||||
if (soundio == NULL) return;
|
||||
// to get actual data
|
||||
soundio_flush_events(soundio);
|
||||
|
||||
scan_devices(soundio); // read devices
|
||||
io_buildUdpAudioList();
|
||||
|
||||
//print_devs();
|
||||
}
|
||||
|
||||
char* getDevID(char* devname, int io)
|
||||
{
|
||||
for (int i = 0; i < audiodevidx; i++)
|
||||
{
|
||||
if (!strcmp(devname, audiodev[i].name) && io == audiodev[i].in_out)
|
||||
{
|
||||
return audiodev[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;
|
||||
//printf("cap: %d %d\n", frame_count_min, frame_count_max);
|
||||
//int chans = instream->layout.channel_count;
|
||||
|
||||
struct SoundIoChannelArea* areas;
|
||||
// samples are in areas.ptr
|
||||
int frames_left = frame_count_max; // take all
|
||||
while (1)
|
||||
{
|
||||
int frame_count = frames_left;
|
||||
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
|
||||
{
|
||||
fprintf(stderr, "begin read error: %s", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
for (int frame = 0; frame < frame_count; frame += 1)
|
||||
{
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1)
|
||||
{
|
||||
int16_t rxdata;
|
||||
memcpy(&rxdata, areas[ch].ptr, instream->bytes_per_sample);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
if (ch == 0)
|
||||
{
|
||||
float f = rxdata;
|
||||
f /= 32768;
|
||||
f *= softwareCAPvolume;
|
||||
io_cap_write_fifo(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//measure_speed_bps(frame_count);
|
||||
|
||||
if ((err = soundio_instream_end_read(instream)))
|
||||
{
|
||||
fprintf(stderr, "end read error: %s", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
if (frames_left <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
void read_callback(struct SoundIoInStream* instream, int frame_count_min, int frame_count_max)
|
||||
{
|
||||
int err;
|
||||
//printf("cap: %d %d\n", frame_count_min, frame_count_max);
|
||||
// bytes_per_frame == 4 because we use float
|
||||
// instream->bytes_per_sample/bytes_per_frame = 1 (mono) or 2 (stereo)
|
||||
int chans = instream->layout.channel_count;
|
||||
|
||||
struct SoundIoChannelArea* areas;
|
||||
// samples are in areas.ptr
|
||||
int frames_left = frame_count_max; // take all
|
||||
while (1)
|
||||
{
|
||||
int frame_count = frames_left;
|
||||
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
|
||||
{
|
||||
fprintf(stderr, "begin read error: %s", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
// do something with the data in *area.ptr
|
||||
// take a float every chans*4 Bytes
|
||||
int16_t* samples = (int16_t*)(areas[0].ptr);
|
||||
int pos = 0;
|
||||
for (int i = 0; i < frame_count; i++)
|
||||
{
|
||||
float f = samples[pos];
|
||||
f /= 32768;
|
||||
f *= softwareCAPvolume;
|
||||
io_cap_write_fifo(f);
|
||||
pos += chans;
|
||||
}
|
||||
|
||||
//measure_speed_bps(frame_count);
|
||||
|
||||
if ((err = soundio_instream_end_read(instream))) {
|
||||
fprintf(stderr, "end read error: %s", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
if (frames_left <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
void overflow_callback(struct SoundIoInStream* instream)
|
||||
{
|
||||
static int count = 0;
|
||||
printf("overflow %d\n", ++count);
|
||||
}
|
||||
|
||||
#define MAXCAPCHUNKLEN 50000
|
||||
|
||||
static void write_callback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max)
|
||||
{
|
||||
struct SoundIoChannelArea* areas;
|
||||
int err;
|
||||
int frames_left = frame_count_max;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int frame_count = frames_left;
|
||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
||||
{
|
||||
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
float f[MAXCAPCHUNKLEN];
|
||||
int fiforet = io_pb_read_fifo_num(f, frame_count);
|
||||
if (fiforet == 0)
|
||||
{
|
||||
// elements not available, fill with zeroes
|
||||
//printf("not enough data, send zeroes\n");
|
||||
memset(f, 0, sizeof(float) * frame_count);
|
||||
}
|
||||
|
||||
const struct SoundIoChannelLayout* layout = &outstream->layout;
|
||||
|
||||
for (int frame = 0; frame < frame_count; frame++)
|
||||
{
|
||||
for (int channel = 0; channel < layout->channel_count; channel++)
|
||||
{
|
||||
write_sample_s16ne(areas[channel].ptr, f[frame]);
|
||||
areas[channel].ptr += areas[channel].step;
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = soundio_outstream_end_write(outstream))) {
|
||||
if (err == SoundIoErrorUnderflow)
|
||||
return;
|
||||
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
if (frames_left <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
static void write_callback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max)
|
||||
{
|
||||
int chans = outstream->layout.channel_count;
|
||||
struct SoundIoChannelArea* areas;
|
||||
int err;
|
||||
int frames_left = min_int(frame_count_max,MAXCAPCHUNKLEN);// frame_count_max;
|
||||
//printf("\nmin: %d max:%d\n", frame_count_min, frame_count_max);
|
||||
|
||||
// we have to write frame_count_max, not less, or we get an underrun
|
||||
// this has to be written in chunks requested by soundio_outstream_begin_write
|
||||
float f[MAXCAPCHUNKLEN];
|
||||
while (1)
|
||||
{
|
||||
int frame_count = frames_left;
|
||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) {
|
||||
printf("unrecoverable soundio_outstream_begin_write error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
if (!frame_count) break; // will normally never happen
|
||||
//printf("chunk: %d\n", frame_count);
|
||||
|
||||
// soundio_outstream_begin_write requested to write frame_count elements
|
||||
int fiforet = io_pb_read_fifo_num(f, frame_count);
|
||||
if (fiforet == 0)
|
||||
{
|
||||
// elements not available, fill with zeroes
|
||||
//printf("not enough data, send zeroes\n");
|
||||
memset(f, 0, sizeof(float) * frame_count);
|
||||
}
|
||||
|
||||
// apply volume
|
||||
for (int i = 0; i < frame_count; i++)
|
||||
f[i] *= softwarePBvolume;
|
||||
|
||||
// put data into soundio buffer
|
||||
for (int frame = 0; frame < frame_count; frame++)
|
||||
{
|
||||
for (int ch = 0; ch < chans; ch++)
|
||||
{
|
||||
int16_t* s = (int16_t*)areas[ch].ptr;
|
||||
*s = (int16_t)(f[frame] * 32768.0);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
}
|
||||
}
|
||||
|
||||
// and finalize this chunk
|
||||
if ((err = soundio_outstream_end_write(outstream))) {
|
||||
if (err == SoundIoErrorUnderflow)
|
||||
return;
|
||||
printf("unrecoverable soundio_outstream_end_write error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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 io_init_sound(char *pbname, char *capname)
|
||||
{
|
||||
int err;
|
||||
init_audio_result = 0;
|
||||
|
||||
printf("\n ==== IO INIT AUDIO devices ====\n");
|
||||
printf("requested: <%s> <%s>\ncapture rate:%d\n",pbname,capname,caprate);
|
||||
|
||||
io_close_audio();
|
||||
|
||||
// prepare and connect to libsoundio
|
||||
soundio = soundio_create();
|
||||
if (!soundio) {
|
||||
printf("soundio_create: out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
#ifdef _WIN32_
|
||||
if ((err=soundio_connect_backend(soundio, SoundIoBackendWasapi))) {
|
||||
printf("soundio_connect: %s\n", soundio_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef _LINUX_
|
||||
if ((err = soundio_connect(soundio))) {
|
||||
printf("soundio_connect: %s\n", soundio_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
io_readAudioDevices();
|
||||
io_init_pipes();
|
||||
|
||||
if (pbname == NULL || capname == NULL || strlen(pbname) < 3 || strlen(capname) < 3) // no devices defined yet
|
||||
{
|
||||
printf("no devices specified\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* pbdevid = getDevID(pbname,1);
|
||||
if (pbdevid == NULL) return 0;
|
||||
|
||||
char* capdevid = getDevID(capname,0);
|
||||
if (capdevid == NULL) return 0;
|
||||
|
||||
// define the capture device
|
||||
printf("selected CAP device:\nname:%s\nid :%s\n", capname, capdevid);
|
||||
|
||||
soundio_flush_events(soundio);
|
||||
|
||||
for (int i = 0; i < soundio_input_device_count(soundio); i++)
|
||||
{
|
||||
io_cap_device = NULL;
|
||||
struct SoundIoDevice* device = soundio_get_input_device(soundio, i);
|
||||
if (strcmp(device->id, capdevid) == 0
|
||||
#ifdef _WIN32_
|
||||
&& device->is_raw == true
|
||||
#endif
|
||||
)
|
||||
{
|
||||
io_cap_device = device;
|
||||
break;
|
||||
}
|
||||
soundio_device_unref(device);
|
||||
}
|
||||
if (!io_cap_device)
|
||||
{
|
||||
printf("Invalid device id: %s\n", capdevid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (io_cap_device->probe_error)
|
||||
{
|
||||
printf("Unable to probe device: %s\n", soundio_strerror(io_cap_device->probe_error));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// create capture callback
|
||||
instream = soundio_instream_create(io_cap_device);
|
||||
if (!instream) {
|
||||
printf("out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
instream->format = SoundIoFormatS16NE;
|
||||
instream->sample_rate = caprate;
|
||||
instream->software_latency = 0.0;
|
||||
instream->read_callback = read_callback;
|
||||
instream->overflow_callback = overflow_callback;
|
||||
instream->userdata = NULL;
|
||||
|
||||
if ((err = soundio_instream_open(instream))) {
|
||||
printf("unable to open input stream: %s", soundio_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((err = soundio_instream_start(instream))) {
|
||||
fprintf(stderr, "unable to start input device: %s", soundio_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
init_audio_result |= 2;
|
||||
// the CAP callback is running now
|
||||
|
||||
// define the playback device
|
||||
printf("selected PB device:\nname:%s\nid :%s\n", pbname, pbdevid);
|
||||
|
||||
for (int i = 0; i < soundio_output_device_count(soundio); i++)
|
||||
{
|
||||
io_pb_device = NULL;
|
||||
struct SoundIoDevice* device = soundio_get_output_device(soundio, i);
|
||||
if (strcmp(device->id, pbdevid) == 0
|
||||
#ifdef _WIN32_
|
||||
&& device->is_raw == true
|
||||
#endif
|
||||
)
|
||||
{
|
||||
io_pb_device = device;
|
||||
break;
|
||||
}
|
||||
soundio_device_unref(device);
|
||||
}
|
||||
if (!io_pb_device)
|
||||
{
|
||||
printf("Invalid device id: %s\n", pbdevid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (io_pb_device->probe_error)
|
||||
{
|
||||
printf("Unable to probe device: %s\n", soundio_strerror(io_pb_device->probe_error));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// create playback callback
|
||||
outstream = soundio_outstream_create(io_pb_device);
|
||||
if (!outstream) {
|
||||
printf("soundio_outstream_create: out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
outstream->format = SoundIoFormatS16NE;
|
||||
outstream->sample_rate = caprate;
|
||||
outstream->software_latency = 0.0;
|
||||
outstream->write_callback = write_callback;
|
||||
outstream->underflow_callback = underflow_callback;
|
||||
outstream->userdata = NULL;
|
||||
|
||||
if ((err = soundio_outstream_open(outstream))) {
|
||||
printf("unable to open output stream: %s", soundio_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((err = soundio_outstream_start(outstream))) {
|
||||
fprintf(stderr, "unable to start output device: %s", soundio_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
init_audio_result |= 1;
|
||||
|
||||
printf("==== Audio init finished: %d ====\n", init_audio_result);
|
||||
|
||||
return init_audio_result;
|
||||
}
|
||||
|
||||
void io_close_audio()
|
||||
{
|
||||
printf("close Audio\n");
|
||||
if(instream) soundio_instream_destroy(instream);
|
||||
instream = NULL;
|
||||
|
||||
if (outstream) soundio_outstream_destroy(outstream);
|
||||
outstream = NULL;
|
||||
|
||||
if(io_pb_device) soundio_device_unref(io_pb_device);
|
||||
io_pb_device = NULL;
|
||||
|
||||
if (io_cap_device) soundio_device_unref(io_cap_device);
|
||||
io_cap_device = NULL;
|
||||
|
||||
if (soundio) soundio_destroy(soundio);
|
||||
soundio = NULL;
|
||||
}
|
||||
|
||||
void io_setPBvolume(int v)
|
||||
{
|
||||
// the volume comes in % 0..99
|
||||
softwarePBvolume = ((float)v) / 50.0f;
|
||||
}
|
||||
|
||||
void io_setCAPvolume(int v)
|
||||
{
|
||||
// the volume comes in % 0..99
|
||||
softwareCAPvolume = ((float)v) / 50.0f;
|
||||
}
|
||||
|
||||
// set volume
|
||||
void io_setVolume(int pbcap, int v)
|
||||
{
|
||||
if (pbcap == 0) io_setPBvolume(v);
|
||||
else io_setCAPvolume(v);
|
||||
}
|
||||
|
||||
void io_setLSvolume(int v)
|
||||
{
|
||||
// the volume comes in % 0..99
|
||||
softwareLSvolume = ((float)v) / 50.0f;
|
||||
}
|
||||
|
||||
void io_setMICvolume(int v)
|
||||
{
|
||||
// the volume comes in % 0..99
|
||||
softwareMICvolume = ((float)v) / 50.0f;
|
||||
}
|
||||
|
||||
void setVolume_voice(int pbcap, int v)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
int speed = 0;
|
||||
|
||||
#define MAXSPDARR 50
|
||||
#define MAXSPDARR 10
|
||||
int spdarr[MAXSPDARR];
|
||||
int spdarrbps[MAXSPDARR];
|
||||
|
||||
@ -132,7 +132,7 @@ void measure_speed_syms(int len)
|
||||
speed = meanval((int)dspd) * bitsPerSymbol;
|
||||
|
||||
// here we have number of elements after 1s
|
||||
//printf("%d sym/s\n",speed);
|
||||
printf("%d sym/s\n",speed);
|
||||
|
||||
elems=0;
|
||||
lasttim = tim;
|
||||
|
@ -32,9 +32,11 @@ struct SoundIoDevice* io_mic_device = NULL;
|
||||
struct SoundIoOutStream* outlsstream = NULL;
|
||||
struct SoundIoInStream* inmicstream = NULL;
|
||||
|
||||
bool lsrawdev = true;
|
||||
bool micrawdev = true;
|
||||
|
||||
void read_voicecallback(struct SoundIoInStream* instream, int frame_count_min, int frame_count_max)
|
||||
{
|
||||
|
||||
int err;
|
||||
//printf("cap: %d %d\n", frame_count_min, frame_count_max);
|
||||
//int chans = instream->layout.channel_count;
|
||||
@ -57,19 +59,37 @@ void read_voicecallback(struct SoundIoInStream* instream, int frame_count_min, i
|
||||
{
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1)
|
||||
{
|
||||
int16_t rxdata;
|
||||
memcpy(&rxdata, areas[ch].ptr, instream->bytes_per_sample);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
if (ch == 0)
|
||||
if (micrawdev == false)
|
||||
{
|
||||
float f = rxdata;
|
||||
f /= 32768;
|
||||
f *= softwareCAPvolume;
|
||||
io_mic_write_fifo(f);
|
||||
float frxdata;
|
||||
memcpy(&frxdata, areas[ch].ptr, instream->bytes_per_sample);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
if (ch == 0)
|
||||
{
|
||||
float f = frxdata;
|
||||
f *= softwareMICvolume;
|
||||
io_mic_write_fifo(f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int16_t rxdata;
|
||||
memcpy(&rxdata, areas[ch].ptr, instream->bytes_per_sample);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
if (ch == 0)
|
||||
{
|
||||
float f = rxdata;
|
||||
f /= 32768;
|
||||
f *= softwareMICvolume;
|
||||
io_mic_write_fifo(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// needs to sleep or it will not work correctly, no idea why
|
||||
sleep_ms(1);
|
||||
|
||||
//measure_speed_bps(frame_count);
|
||||
|
||||
if ((err = soundio_instream_end_read(instream)))
|
||||
@ -97,52 +117,79 @@ void write_sample_s16ne(char* ptr, double sample) {
|
||||
*buf = (int16_t)val;
|
||||
}
|
||||
|
||||
void write_sample_float32ne(char* ptr, double sample) {
|
||||
float* buf = (float*)ptr;
|
||||
*buf = (float)sample;
|
||||
}
|
||||
|
||||
#define MAXCAPCHUNKLEN 50000
|
||||
|
||||
//static const double PI = 3.14159265358979323846264338328;
|
||||
//static double seconds_offset = 0.0;
|
||||
static void write_voicecallback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max)
|
||||
{
|
||||
//printf("pb: %d %d\n", frame_count_min, frame_count_max);
|
||||
|
||||
//double float_sample_rate = outstream->sample_rate;
|
||||
//double seconds_per_frame = 1.0 / float_sample_rate;
|
||||
struct SoundIoChannelArea* areas;
|
||||
int err;
|
||||
int frames_left = frame_count_max;
|
||||
|
||||
while(1)
|
||||
{
|
||||
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)))
|
||||
{
|
||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) {
|
||||
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!frame_count)
|
||||
break;
|
||||
|
||||
// soundio_outstream_begin_write requested to write frame_count elements
|
||||
float f[MAXCAPCHUNKLEN];
|
||||
//printf("ck: %d\n", frame_count);
|
||||
|
||||
//float f[MAXCAPCHUNKLEN];
|
||||
float *f = (float *)malloc(frame_count * sizeof(float));
|
||||
int fiforet = io_ls_read_fifo_num(f, frame_count);
|
||||
if (fiforet == 0)
|
||||
{
|
||||
// elements not available, fill with zeroes
|
||||
//printf("not enough data, send zeroes\n");
|
||||
//printf("only %d not enough data, send zeroes\n", io_ls_fifo_usedspace());
|
||||
memset(f, 0, sizeof(float) * frame_count);
|
||||
}
|
||||
|
||||
const struct SoundIoChannelLayout* layout = &outstream->layout;
|
||||
|
||||
for (int frame = 0; frame < frame_count; frame++)
|
||||
//double pitch = 440.0;
|
||||
//double radians_per_second = pitch * 2.0 * PI;
|
||||
for (int frame = 0; frame < frame_count; frame += 1)
|
||||
{
|
||||
for (int channel = 0; channel < layout->channel_count; channel++)
|
||||
//double sample = sin((seconds_offset + frame * seconds_per_frame) * radians_per_second);
|
||||
for (int channel = 0; channel < layout->channel_count; channel += 1)
|
||||
{
|
||||
write_sample_s16ne(areas[channel].ptr, f[frame]);
|
||||
float ftx = f[frame] * softwareLSvolume;
|
||||
//write_sample_float32ne(areas[channel].ptr, sample);
|
||||
if(lsrawdev == false)
|
||||
write_sample_float32ne(areas[channel].ptr, ftx);
|
||||
else
|
||||
write_sample_s16ne(areas[channel].ptr, ftx);
|
||||
areas[channel].ptr += areas[channel].step;
|
||||
}
|
||||
}
|
||||
//seconds_offset = fmod(seconds_offset + seconds_per_frame * frame_count, 1.0);
|
||||
|
||||
free(f);
|
||||
|
||||
//measure_speed_bps(frame_count);
|
||||
|
||||
if ((err = soundio_outstream_end_write(outstream))) {
|
||||
if (err == SoundIoErrorUnderflow)
|
||||
return;
|
||||
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
@ -151,82 +198,6 @@ static void write_voicecallback(struct SoundIoOutStream* outstream, int frame_co
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
static void write_voicecallback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max)
|
||||
{
|
||||
float f[MAXCAPCHUNKLEN];
|
||||
|
||||
int chans = outstream->layout.channel_count;
|
||||
struct SoundIoChannelArea* areas;
|
||||
int err;
|
||||
int frames_left = min_int(frame_count_max, MAXCAPCHUNKLEN);// frame_count_max;
|
||||
printf("min: %d max:%d\n", frame_count_min, frame_count_max);
|
||||
|
||||
// we have to write frame_count_max, not less, or we get an underrun
|
||||
// this has to be written in chunks requested by soundio_outstream_begin_write
|
||||
|
||||
while (1)
|
||||
{
|
||||
int frame_count = frames_left;
|
||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) {
|
||||
printf("unrecoverable soundio_outstream_begin_write error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
printf("chunk: %d\n", frame_count);
|
||||
if (!frame_count) break; // will normally never happen
|
||||
|
||||
// soundio_outstream_begin_write requested to write frame_count elements
|
||||
int fiforet = io_ls_read_fifo_num(f, frame_count);
|
||||
if (fiforet == 0)
|
||||
{
|
||||
// elements not available, fill with zeroes
|
||||
//printf("not enough data, send zeroes\n");
|
||||
memset(f, 0, sizeof(float) * frame_count);
|
||||
}
|
||||
|
||||
// apply volume
|
||||
for (int i = 0; i < frame_count; i++)
|
||||
f[i] *= softwarePBvolume;
|
||||
|
||||
// put data into soundio buffer
|
||||
for (int frame = 0; frame < frame_count; frame++)
|
||||
{
|
||||
for (int ch = 0; ch < chans; ch++)
|
||||
{
|
||||
int16_t* s = (int16_t*)areas[ch].ptr;
|
||||
*s = (int16_t)(f[frame] * 32768.0);
|
||||
areas[ch].ptr += areas[ch].step;
|
||||
}
|
||||
}
|
||||
|
||||
for (int frame = 0; frame < frame_count; frame += 1)
|
||||
{
|
||||
for (int channel = 0; channel < chans; channel += 1)
|
||||
{
|
||||
write_sample_float32ne(areas[channel].ptr, f[frame]);
|
||||
areas[channel].ptr += areas[channel].step;
|
||||
}
|
||||
}
|
||||
|
||||
// and finalize this chunk
|
||||
if ((err = soundio_outstream_end_write(outstream))) {
|
||||
if (err == SoundIoErrorUnderflow)
|
||||
{
|
||||
printf("underflow x\n");
|
||||
return;
|
||||
}
|
||||
printf("unrecoverable soundio_outstream_end_write error: %s\n", soundio_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frames_left -= frame_count;
|
||||
if (frames_left <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void underflow_voicecallback(struct SoundIoOutStream* outstream)
|
||||
{
|
||||
static int count = 0;
|
||||
@ -240,7 +211,7 @@ int io_init_voice(char* lsname, char* micname)
|
||||
init_voice_result = 0;
|
||||
|
||||
printf("\n ==== IO INIT VOICE devices ====\n");
|
||||
printf("requested: <%s> <%s>\ncapture rate:%d\n", lsname, micname, VOICE_SAMPRATE);
|
||||
printf("requested:\nPB :<%s>\nCAP:<%s>\ncapture rate:%d\n", lsname, micname, VOICE_SAMPRATE);
|
||||
|
||||
io_close_voice();
|
||||
|
||||
@ -276,21 +247,28 @@ int io_init_voice(char* lsname, char* micname)
|
||||
if (micdevid == NULL) return 0;
|
||||
|
||||
soundio_flush_events(voice_soundio);
|
||||
// under Windows we usually use raw devices. This does not work with
|
||||
// virtual sound cards due to problems in libsoundio
|
||||
// for VACs we use shared devices, otherwise raw
|
||||
lsrawdev = true;
|
||||
if (strstr(lsname, "irtual") || strstr(lsname, "VAC"))
|
||||
lsrawdev = false;
|
||||
|
||||
micrawdev = true;
|
||||
if (strstr(micname, "irtual") || strstr(micname, "VAC"))
|
||||
micrawdev = false;
|
||||
|
||||
printf("================ %d\n", VoiceAudioMode);
|
||||
if (VoiceAudioMode != VOICEMODE_LISTENAUDIOIN)
|
||||
{
|
||||
|
||||
// define the capture device
|
||||
printf("selected CAP device:\nname:%s\nid :%s\n", micname, micdevid);
|
||||
|
||||
for (int i = 0; i < soundio_input_device_count(voice_soundio); i++)
|
||||
{
|
||||
io_mic_device = NULL;
|
||||
struct SoundIoDevice* device = soundio_get_input_device(voice_soundio, i);
|
||||
if (strcmp(device->id, micdevid) == 0
|
||||
#ifdef _WIN32_
|
||||
&& device->is_raw == true
|
||||
&& device->is_raw == micrawdev
|
||||
#endif
|
||||
)
|
||||
{
|
||||
@ -314,8 +292,6 @@ int io_init_voice(char* lsname, char* micname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("cap raw: %s\n", io_mic_device->is_raw ? "raw" : "---");
|
||||
|
||||
// create capture callback
|
||||
inmicstream = soundio_instream_create(io_mic_device);
|
||||
if (!inmicstream) {
|
||||
@ -323,7 +299,10 @@ int io_init_voice(char* lsname, char* micname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
inmicstream->format = SoundIoFormatS16NE;
|
||||
if (micrawdev)
|
||||
inmicstream->format = SoundIoFormatS16NE;
|
||||
else
|
||||
inmicstream->format = SoundIoFormatFloat32NE;
|
||||
inmicstream->sample_rate = VOICE_SAMPRATE;
|
||||
inmicstream->software_latency = 0.0;
|
||||
inmicstream->read_callback = read_voicecallback;
|
||||
@ -340,18 +319,21 @@ int io_init_voice(char* lsname, char* micname)
|
||||
return 0;
|
||||
}
|
||||
init_voice_result |= 2;
|
||||
|
||||
printf("selected MICROPHONE device:\nname:%s\nid :%s\n", micname, micdevid);
|
||||
printf("physical capture rate:%d\n", VOICE_SAMPRATE);
|
||||
printf("format: %s\n\n", soundio_format_string(inmicstream->format));
|
||||
// the CAP callback is running now
|
||||
}
|
||||
|
||||
// define the playback device
|
||||
printf("selected PB device:\nname:%s\nid :%s\n", lsname, lsdevid);
|
||||
for (int i = 0; i < soundio_output_device_count(voice_soundio); i++)
|
||||
{
|
||||
io_ls_device = NULL;
|
||||
struct SoundIoDevice* device = soundio_get_output_device(voice_soundio, i);
|
||||
if (strcmp(device->id, lsdevid) == 0
|
||||
#ifdef _WIN32_
|
||||
&& device->is_raw == true
|
||||
&& device->is_raw == lsrawdev
|
||||
#endif
|
||||
)
|
||||
{
|
||||
@ -381,7 +363,11 @@ int io_init_voice(char* lsname, char* micname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
outlsstream->format = SoundIoFormatS16NE;
|
||||
|
||||
if (lsrawdev)
|
||||
outlsstream->format = SoundIoFormatS16NE;
|
||||
else
|
||||
outlsstream->format = SoundIoFormatFloat32NE;
|
||||
outlsstream->sample_rate = VOICE_SAMPRATE;
|
||||
outlsstream->software_latency = 0.0;
|
||||
outlsstream->write_callback = write_voicecallback;
|
||||
@ -399,7 +385,9 @@ int io_init_voice(char* lsname, char* micname)
|
||||
}
|
||||
init_voice_result |= 1;
|
||||
|
||||
printf("==== Voice init finished: %d ====\n", init_audio_result);
|
||||
printf("selected LOUDSPEAKER device:\nname:%s\nid :%s\n", lsname, lsdevid);
|
||||
printf("physical capture rate:%d\n", VOICE_SAMPRATE);
|
||||
printf("format: %s\n\n", soundio_format_string(outlsstream->format));
|
||||
|
||||
return init_voice_result;
|
||||
}
|
||||
|
2
oscardata/oscardata/Form1.Designer.cs
generated
2
oscardata/oscardata/Form1.Designer.cs
generated
@ -1428,7 +1428,7 @@
|
||||
this.ForeColor = System.Drawing.SystemColors.ControlText;
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Name = "Form1";
|
||||
this.Text = "QO-100 NB Transponder HS Multimedia Modem AMSAT-DL V0.44 by DJ0ABR";
|
||||
this.Text = "QO-100 NB Transponder HS Multimedia Modem AMSAT-DL V0.45 by DJ0ABR";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
|
@ -137,7 +137,7 @@
|
||||
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
|
||||
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
|
||||
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABw
|
||||
FwAAAk1TRnQBSQFMAgEBDQEAATgBAQE4AQEBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
|
||||
FwAAAk1TRnQBSQFMAgEBDQEAAUABAQFAAQEBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
|
||||
AwABQAMAAUADAAEBAQABCAYAARAYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
|
||||
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
|
||||
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user