This commit is contained in:
Kurt Moraw
2020-11-07 18:07:55 +01:00
parent 6b16e3b676
commit 208e6fca8d
23 changed files with 2389 additions and 1466 deletions
+248 -93
View File
@@ -43,12 +43,13 @@ void cap_write_fifo(float sample);
int pb_fifo_freespace(int nolock);
void init_pipes();
#define CHANNELS 1 // no of channels used
HRECORD rchan = 0; // recording channel
BASS_INFO info;
HSTREAM stream = 0;
int openpbdev = -1;
int opencapdev = -1;
/*void showDeviceInfo(BASS_DEVICEINFO info)
{
if (info.flags & BASS_DEVICE_ENABLED) printf("%s\n","BASS_DEVICE_ENABLED ");
@@ -69,77 +70,132 @@ HSTREAM stream = 0;
}*/
#define MAXDEVSTRLEN 2000
uint8_t devstring[MAXDEVSTRLEN +100];
char PBdevs[100][256]; // stores the device names, just for diagnosis, has no real fuction
char CAPdevs[100][256];
// build string of audio devices, to be sent to application as response to Broadcast search
void enumerateAudioDevices()
// audio device description table
typedef struct {
int bassdev; // bass (basswasapi) dev no
char name[256]; // DEV name
} AUDIODEVS;
// index is enumerated number, 0=default
AUDIODEVS audioPBdevs[100];
AUDIODEVS audioCAPdevs[100];
int pbanz = 0, capanz = 0;
// populate audio device list
void readAudioDevs()
{
memset(devstring, 0, sizeof(devstring));
devstring[0] = 3; // ID for this UDP message
// playback devices
int a;
int idx = 0;
// enter default device manually
audioPBdevs[pbanz].bassdev = -1;
strcpy(audioPBdevs[pbanz].name, "Default");
pbanz++;
audioCAPdevs[capanz].bassdev = -1;
strcpy(audioCAPdevs[capanz].name, "Default");
capanz++;
#ifdef _LINUX_
BASS_DEVICEINFO info;
strcat((char*)(devstring + 1), "System Default");
strcat((char*)(devstring + 1), "~");
strcpy(PBdevs[idx++], "System Default");
for (a = 1; BASS_GetDeviceInfo(a, &info); a++)
{
printf("PB device:%d = %s\n", a, info.name);
if (strlen((char*)(devstring+1)) > MAXDEVSTRLEN) break;
if (info.flags & BASS_DEVICE_ENABLED)
{
strncpy(PBdevs[idx], info.name, 255);
PBdevs[idx][255] = 0;
idx++;
strcat((char*)(devstring + 1), info.name);
strcat((char*)(devstring + 1), "~"); // audio device separator
if (!strstr(info.name, "HDMI") && !strstr(info.name, "hdmi") && !strstr(info.name, "efault"))
{
audioPBdevs[pbanz].bassdev = a;
strncpy(audioPBdevs[pbanz].name, info.name, 255);
audioPBdevs[pbanz].name[255] = 0;
pbanz++;
}
}
}
for (a = 1; BASS_RecordGetDeviceInfo(a, &info); a++)
{
if (info.flags & BASS_DEVICE_ENABLED)
{
if (!strstr(info.name, "HDMI") && !strstr(info.name, "hdmi") && !strstr(info.name, "efault"))
{
audioCAPdevs[capanz].bassdev = a;
strncpy(audioCAPdevs[capanz].name, info.name, 255);
audioCAPdevs[capanz].name[255] = 0;
capanz++;
}
}
}
#endif
#ifdef _WIN32_
BASS_WASAPI_DEVICEINFO info;
for (a = 0; BASS_WASAPI_GetDeviceInfo(a, &info); a++)
{
if (!(info.flags & BASS_DEVICE_INPUT) && (info.flags & BASS_DEVICE_ENABLED))
{
if (!strstr(info.name, "HDMI") && !strstr(info.name, "hdmi") && !strstr(info.name, "efault"))
{
audioPBdevs[pbanz].bassdev = a;
strncpy(audioPBdevs[pbanz].name, info.name, 255);
audioPBdevs[pbanz].name[255] = 0;
pbanz++;
}
}
if ((info.flags & BASS_DEVICE_INPUT) && (info.flags & BASS_DEVICE_ENABLED))
{
if (!strstr(info.name, "HDMI") && !strstr(info.name, "hdmi") && !strstr(info.name, "efault"))
{
audioCAPdevs[capanz].bassdev = a;
strncpy(audioCAPdevs[capanz].name, info.name, 255);
audioCAPdevs[capanz].name[255] = 0;
capanz++;
}
}
}
#endif
}
void printAudioDevs()
{
printf("PB devices:\n");
for (int i = 0; i < pbanz; i++)
printf("idx:%d bass:%d name:%s\n", i, audioPBdevs[i].bassdev, audioPBdevs[i].name);
printf("CAP devices:\n");
for (int i = 0; i < capanz; i++)
printf("idx:%d bass:%d name:%s\n", i, audioCAPdevs[i].bassdev, audioCAPdevs[i].name);
}
// 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: ~
void buildUdpAudioList()
{
memset(devstring, 0, sizeof(devstring));
devstring[0] = ' '; // placeholder for ID for this UDP message
// playback devices
for (int i = 0; i < pbanz; i++)
{
strcat((char*)devstring, audioPBdevs[i].name);
strcat((char*)devstring, "~"); // audio device separator
}
strcat((char*)(devstring + 1), "^"); // PB, CAP separator
// capture devices
BASS_DEVICEINFO recinfo;
idx = 0;
strcat((char*)(devstring + 1), "System Default");
strcat((char*)(devstring + 1), "~");
strcpy(CAPdevs[idx++], "System Default");
for (a = 0; BASS_RecordGetDeviceInfo(a, &recinfo); a++)
for (int i = 0; i < capanz; i++)
{
printf("CAP device:%d = %s\n", a, recinfo.name);
if (strlen((char*)(devstring + 1)) > MAXDEVSTRLEN) break;
if (recinfo.flags & BASS_DEVICE_ENABLED)
{
strncpy(CAPdevs[idx], recinfo.name, 255);
CAPdevs[idx][255] = 0;
idx++;
strcat((char*)(devstring + 1), recinfo.name);
strcat((char*)(devstring + 1), "~");
}
strcat((char*)devstring, audioCAPdevs[i].name);
strcat((char*)devstring, "~"); // audio device separator
}
}
/*
* Audio Device numbering:
*
* Playback:
* 0 ... no audio, we use 0 for default, which is -1
* 1 ... audio devices
*
* Record:
* 0 ... audio devices
* we insert "Default" at position 0, and let the audio devices start with 1, so we are compatible with playback
* but in init_audio() we have to substract 1
*/
devstring[0] = 3; // ID for this UDP message
}
uint8_t* getAudioDevicelist(int *len)
{
@@ -148,59 +204,89 @@ uint8_t* getAudioDevicelist(int *len)
}
// pbdev, capdev: -1=default device
int init_audio(int pbdev, int capdev)
int init_audio(int setpbdev, int setcapdev)
{
static int f = 1;
int ocd = capdev;
// PB devices start with 1 (0 not used, but here used for Default which is -1)
if (pbdev == 255 || pbdev == 0) pbdev = -1;
// CAP devices start with 0, but we use 0 for Default (-1)
// so we have to substract 1 from the real devices
if (capdev == 255 || capdev == 0 || capdev == -1) capdev = -1;
else capdev--;
static int f = 1;
if (f == 1)
{
// do only once after program start
f = 0;
enumerateAudioDevices();
readAudioDevs();
printAudioDevs();
buildUdpAudioList();
init_pipes();
}
close_audio();
// translate requested device numbers to bass device numbers
if (setpbdev < 0 || setpbdev >= pbanz) setpbdev = 0;
if (setcapdev < 0 || setcapdev >= capanz) setcapdev = 0;
int pbdev = -1;
if (setpbdev >=0 && setpbdev < pbanz) pbdev = audioPBdevs[setpbdev].bassdev;
int capdev = -1;
if (setcapdev >= 0 && setcapdev < capanz) capdev = audioCAPdevs[setcapdev].bassdev;
printf("init audio, caprate:%d\n",caprate);
if (pbdev != -1)
printf("playback device %d: %s\n", pbdev, PBdevs[pbdev]);
else
printf("playback device %d: %s\n", pbdev, "Default");
printf("requested PB device: %d bassno:%d name:%s\n", setpbdev, pbdev, audioPBdevs[setpbdev].name);
printf("requested CAP device: %d bassno:%d name:%s\n", setcapdev, capdev, audioCAPdevs[setcapdev].name);
if (capdev != -1)
printf("capture device %d: %s\n", capdev, CAPdevs[ocd]);
else
printf("capture device %d: %s\n", capdev, "Default");
// check the correct BASS was loaded
if (HIWORD(BASS_GetVersion()) != BASSVERSION)
if (HIWORD(BASS_GetVersion()) != BASSVERSION)
{
printf("An incorrect version of BASS was loaded\n");
printf("An incorrect version of BASS was loaded\n");
return -1;
}
}
#ifdef _WIN32_
// use WASAPI for Windows to get exclusive access to sound card
return init_wasapi(pbdev, capdev);
#endif
#ifdef _LINUX_
close_audio();
// ===== PLAYBACK ======
// initialize default output device
if (!BASS_Init(pbdev, caprate, 0, NULL, NULL))
{
printf("Can't initialize output device\n");
return -1;
}
// read real device number
int ret = BASS_GetDevice();
if (ret == -1)
{
printf("BASS_GetDevice: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
}
pbdev = ret;
// set play callback
BASS_GetInfo(&info);
stream = BASS_StreamCreate(info.freq, CHANNELS, BASS_SAMPLE_FLOAT, (STREAMPROC*)WriteStream, 0); // sample: 32 bit float
BASS_ChannelSetAttribute(stream, BASS_ATTRIB_BUFFER, 0); // no buffering for minimum latency
BASS_ChannelPlay(stream, FALSE); // start it
// ===== CAPTURE ====
// initalize default recording device
if (!BASS_RecordInit(capdev))
{
printf("Can't initialize recording device: %d\n", BASS_ErrorGetCode());
return -1;
}
// initialize default output device
if (!BASS_Init(pbdev, caprate, 0, NULL, NULL))
// read real device number
ret = BASS_GetDevice();
if (ret == -1)
{
printf("Can't initialize output device\n");
printf("BASS_GetDevice: %d err:%d\n", capdev, BASS_ErrorGetCode());
return -1;
}
capdev = ret;
// set capture callback
rchan = BASS_RecordStart(caprate, CHANNELS, BASS_SAMPLE_FLOAT, RecordingCallback, 0);
@@ -208,23 +294,23 @@ int init_audio(int pbdev, int capdev)
printf("Can't start capturing: %d\n", BASS_ErrorGetCode());
return -1;
}
// set play callback
BASS_GetInfo(&info);
stream = BASS_StreamCreate(info.freq, CHANNELS, BASS_SAMPLE_FLOAT, (STREAMPROC*)WriteStream, 0); // sample: 32 bit float
BASS_ChannelSetAttribute(stream, BASS_ATTRIB_BUFFER, 0); // no buffering for minimum latency
BASS_ChannelPlay(stream, FALSE); // start it
printf("audio initialized\n");
openpbdev = pbdev;
opencapdev = capdev;
return 0;
#endif
}
#ifdef _LINUX_
void close_audio()
{
if(stream != 0)
{
printf("!close Audio Devices\n");
printf("close Audio Devices\n");
BASS_ChannelStop(rchan);
int rr = BASS_RecordFree();
if (!rr) printf("Bass_RecordFree error: %d\n", BASS_ErrorGetCode());
@@ -236,11 +322,50 @@ void close_audio()
}
}
void selectPBdevice()
{
if (!BASS_SetDevice(openpbdev))
printf("BASS_SetDevice: %d err:%d\n", openpbdev, BASS_ErrorGetCode());
}
void selectCAPdevice()
{
if (!BASS_SetDevice(opencapdev))
printf("BASS_SetDevice: %d err:%d\n", opencapdev, BASS_ErrorGetCode());
}
void setPBvolume(int v)
{
// the volume comes in % 0..99
// map to 0..1
float vf = v;
vf /= 100;
printf("set PB volume to:%d / %f [0..1]\n", v, vf );
selectPBdevice();
if (!BASS_SetVolume(vf))
printf("setPBvolume: %d err:%d\n", openpbdev, BASS_ErrorGetCode());
}
void setCAPvolume(int v)
{
// the volume comes in % 0..99
// map to min/maxPBvol
float vf = v;
vf /= 100;
printf("set CAP volume to:%d / %f [0..1]\n", v, vf);
selectCAPdevice();
if (!BASS_RecordSetInput(-1,BASS_INPUT_ON,vf))
printf("setCAPvolume: %d err:%d\n", opencapdev, BASS_ErrorGetCode());
}
// capture callback
// length: bytes. short=2byte, 2channels, so it requests samples*4
BOOL CALLBACK RecordingCallback(HRECORD handle, const void *buffer, DWORD length, void *user)
{
//printf("captured %ld samples\n",length/sizeof(float));
//printf("captured %ld samples, channels:%d\n",length/sizeof(float),CHANNELS);
//measure_speed(length/sizeof(float));
float *fbuffer = (float *)buffer;
@@ -269,6 +394,15 @@ DWORD CALLBACK WriteStream(HSTREAM handle, float *buffer, DWORD length, void *us
return length;
}
#endif // _LINUX_
// set volume
void setVolume(int pbcap, int v)
{
if (pbcap == 0) setPBvolume(v);
else setCAPvolume(v);
}
// ================ thread safe fifo for audio callback routines ===============
#ifdef _WIN32_
@@ -371,6 +505,26 @@ void pb_write_fifo_clear()
pb_wridx = pb_rdidx = 0;
}
int pb_fifo_usedBlocks()
{
static int old_fill = 0;
int fill = 0;
int fs = pb_fifo_freespace(0);
int used = AUDIO_PLAYBACK_BUFLEN - fs;
used /= (txinterpolfactor * UDPBLOCKLEN * 8 / bitsPerSymbol);
if (used > 0) fill = 1; else fill = 0;
if (fill == 1 && old_fill == 0)
printf("fifo has data to send\n");
if (fill == 0 && old_fill == 1)
printf("fifo now empty\n");
old_fill = fill;
//printf("free:%d used blocks:%d\n", fs, used);
return used;
}
int pb_fifo_freespace(int nolock)
{
int freebuf = 0;
@@ -412,3 +566,4 @@ int pb_read_fifo(float *data, int elements)
PB_UNLOCK();
return 1;
}
+229
View File
@@ -0,0 +1,229 @@
/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* audio_wasabi.c ... functions to handle audio in/out via a soundcard uses the "BASSWASAPI" library
* wasapi is needed because we need exclusive access to the sound card which is not provided for Windows with the normal bass.lib
*/
#include "hsmodem.h"
#ifdef _WIN32_
#define WASAPI_CHANNELS 2 // wasapi works with 2 only
void init_pipes();
void cap_write_fifo(float sample);
int pb_read_fifo(float* data, int elements);
void close_wasapi();
DWORD CALLBACK PBcallback(void* buffer, DWORD length, void* user);
DWORD CALLBACK CAPcallback(void* buffer, DWORD length, void* user);
float minPBvol = 0;
float maxPBvol = 99;
float minCAPvol = 0;
float maxCAPvol = 99;
extern int openpbdev;
extern int opencapdev;
float softwareCAPvolume = 0.5;
int init_wasapi(int pbdev, int capdev)
{
close_wasapi();
// ======= init PLAYBACK device ========
// initialize default output device
if (!BASS_WASAPI_Init(pbdev, caprate, WASAPI_CHANNELS, BASS_WASAPI_EXCLUSIVE, 0.1f/*buffer in seconds*/, 0, PBcallback, NULL))
{
printf("Can't initialize output device: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
}
// read real device number since a -1 cannot be started
int ret = BASS_WASAPI_GetDevice();
if (ret == -1)
{
printf("BASS_WASAPI_GetDevice: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
}
pbdev = ret;
// read the possible volume settings
BASS_WASAPI_INFO info;
if (!BASS_WASAPI_GetInfo(&info))
{
printf("BASS_WASAPI_GetInfo: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
}
minPBvol = info.volmin;
maxPBvol = info.volmax;
// start playback
if (!BASS_WASAPI_Start())
{
printf("BASS_WASAPI_Start: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
}
// ======= init CAPTURE device ========
// initalize default recording device
if (capdev == -1) capdev = -2; // cap: -2 is the default device for input
if (!BASS_WASAPI_Init(capdev, caprate, WASAPI_CHANNELS, BASS_WASAPI_EXCLUSIVE, 0.1f/*buffer in seconds*/, 0, CAPcallback, NULL))
{
printf("Can't initialize recording device: %d\n", BASS_ErrorGetCode());
return -1;
}
// read real device number since a -2 cannot be started
ret = BASS_WASAPI_GetDevice();
if (ret == -1)
{
printf("BASS_WASAPI_GetDevice: %d err:%d\n", capdev, BASS_ErrorGetCode());
return -1;
}
capdev = ret;
// read the possible volume settings
if (!BASS_WASAPI_GetInfo(&info))
{
printf("BASS_WASAPI_GetInfo: %d err:%d\n", pbdev, BASS_ErrorGetCode());
return -1;
}
minCAPvol = info.volmin;
maxCAPvol = info.volmax;
// start recording
if (!BASS_WASAPI_Start())
{
printf("BASS_WASAPI_Start: %d err:%d\n", capdev, BASS_ErrorGetCode());
return -1;
}
printf("WASAPI started successfully for PBdev:%d and CAPdev:%d\n", pbdev, capdev);
openpbdev = pbdev;
opencapdev = capdev;
return 0;
}
void selectPBdevice()
{
if (!BASS_WASAPI_SetDevice(openpbdev))
printf("BASS_WASAPI_SetDevice: %d err:%d\n", openpbdev, BASS_ErrorGetCode());
}
void selectCAPdevice()
{
if (!BASS_WASAPI_SetDevice(opencapdev))
printf("BASS_WASAPI_SetDevice: %d err:%d\n", opencapdev, BASS_ErrorGetCode());
}
void setPBvolume(int v)
{
// the volume comes in % 0..99
// map to min/maxPBvol
float vf = v * (maxPBvol - minPBvol) / 100 + minPBvol;
if (vf < minPBvol) vf = minPBvol;
if (vf > maxPBvol) vf = maxPBvol;
printf("set PB volume to:%d / %f [%f..%f]\n", v, vf, minPBvol, maxPBvol);
selectPBdevice();
if (!BASS_WASAPI_SetVolume(BASS_WASAPI_CURVE_DB, vf))
printf("setPBvolume: %d err:%d\n", openpbdev, BASS_ErrorGetCode());
}
void setCAPvolume(int v)
{
// non of the BASS input level functions are working in WASAPI exclusive mode
// so we adjust the input level by software
softwareCAPvolume = (float)v;
softwareCAPvolume /= 50;
}
void close_wasapi()
{
printf("close WASAPI Audio Devices\n");
if (openpbdev != -1)
{
selectPBdevice();
if (!BASS_WASAPI_Free()) printf("BASS_WASAPI_Free: dev:%d err:%d\n", openpbdev, BASS_ErrorGetCode());
}
if (opencapdev != -1)
{
selectCAPdevice();
if (!BASS_WASAPI_Free()) printf("BASS_WASAPI_Free: dev:%d err:%d\n", opencapdev, BASS_ErrorGetCode());
}
}
DWORD CALLBACK PBcallback(void* buffer, DWORD length, void* user)
{
float* fbuffer = (float*)buffer;
// requested number of stereo samples: length/sizeof(float)
// requested real number of samples
int req_samples = length / sizeof(float) / WASAPI_CHANNELS;
// prepare a buffer to store the mono samples from the fifo
float* fdata = (float*)malloc(sizeof(float) * req_samples);
// read mono samples from fifo
int ret = pb_read_fifo(fdata, req_samples);
if (ret == 0)
{
// fifo empty, send 00
memset(fdata, 0, sizeof(float) * req_samples);
}
// copy the mono samples into the stereo output buffer
int didx = 0;
for (int i = 0; i < req_samples; i++)
{
fbuffer[didx++] = fdata[i];
fbuffer[didx++] = fdata[i];
}
free(fdata);
return length;
}
DWORD CALLBACK CAPcallback(void* buffer, DWORD length, void* user)
{
//printf("CAP callback, len:%d\n",length);
//measure_speed_bps(length/sizeof(float)/ WASAPI_CHANNELS);
float* fbuffer = (float*)buffer;
//showbytestringf((char*)"rx: ", fbuffer, 20);
for (unsigned int i = 0; i < (length / sizeof(float)); i += WASAPI_CHANNELS)
{
cap_write_fifo(fbuffer[i]);
}
return TRUE; // continue recording
}
#endif // _WIN32_
+1147 -1147
View File
File diff suppressed because it is too large Load Diff
+161
View File
@@ -0,0 +1,161 @@
/*
BASSWASAPI 2.4 C/C++ header file
Copyright (c) 2009-2020 Un4seen Developments Ltd.
See the BASSWASAPI.CHM file for more detailed documentation
*/
#ifndef BASSWASAPI_H
#define BASSWASAPI_H
#include "bass.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef BASSWASAPIDEF
#define BASSWASAPIDEF(f) WINAPI f
#endif
// Additional error codes returned by BASS_ErrorGetCode
#define BASS_ERROR_WASAPI 5000 // no WASAPI
#define BASS_ERROR_WASAPI_BUFFER 5001 // buffer size is invalid
#define BASS_ERROR_WASAPI_CATEGORY 5002 // can't set category
#define BASS_ERROR_WASAPI_DENIED 5003 // access denied
// Device info structure
typedef struct {
const char *name;
const char *id;
DWORD type;
DWORD flags;
float minperiod;
float defperiod;
DWORD mixfreq;
DWORD mixchans;
} BASS_WASAPI_DEVICEINFO;
typedef struct {
DWORD initflags;
DWORD freq;
DWORD chans;
DWORD format;
DWORD buflen;
float volmax;
float volmin;
float volstep;
} BASS_WASAPI_INFO;
// BASS_WASAPI_DEVICEINFO "type"
#define BASS_WASAPI_TYPE_NETWORKDEVICE 0
#define BASS_WASAPI_TYPE_SPEAKERS 1
#define BASS_WASAPI_TYPE_LINELEVEL 2
#define BASS_WASAPI_TYPE_HEADPHONES 3
#define BASS_WASAPI_TYPE_MICROPHONE 4
#define BASS_WASAPI_TYPE_HEADSET 5
#define BASS_WASAPI_TYPE_HANDSET 6
#define BASS_WASAPI_TYPE_DIGITAL 7
#define BASS_WASAPI_TYPE_SPDIF 8
#define BASS_WASAPI_TYPE_HDMI 9
#define BASS_WASAPI_TYPE_UNKNOWN 10
// BASS_WASAPI_DEVICEINFO flags
#define BASS_DEVICE_ENABLED 1
#define BASS_DEVICE_DEFAULT 2
#define BASS_DEVICE_INIT 4
#define BASS_DEVICE_LOOPBACK 8
#define BASS_DEVICE_INPUT 16
#define BASS_DEVICE_UNPLUGGED 32
#define BASS_DEVICE_DISABLED 64
// BASS_WASAPI_Init flags
#define BASS_WASAPI_EXCLUSIVE 1
#define BASS_WASAPI_AUTOFORMAT 2
#define BASS_WASAPI_BUFFER 4
#define BASS_WASAPI_EVENT 16
#define BASS_WASAPI_SAMPLES 32
#define BASS_WASAPI_DITHER 64
#define BASS_WASAPI_RAW 128
#define BASS_WASAPI_ASYNC 0x100
#define BASS_WASAPI_CATEGORY_MASK 0xf000
#define BASS_WASAPI_CATEGORY_OTHER 0x0000
#define BASS_WASAPI_CATEGORY_FOREGROUNDONLYMEDIA 0x1000
#define BASS_WASAPI_CATEGORY_BACKGROUNDCAPABLEMEDIA 0x2000
#define BASS_WASAPI_CATEGORY_COMMUNICATIONS 0x3000
#define BASS_WASAPI_CATEGORY_ALERTS 0x4000
#define BASS_WASAPI_CATEGORY_SOUNDEFFECTS 0x5000
#define BASS_WASAPI_CATEGORY_GAMEEFFECTS 0x6000
#define BASS_WASAPI_CATEGORY_GAMEMEDIA 0x7000
#define BASS_WASAPI_CATEGORY_GAMECHAT 0x8000
#define BASS_WASAPI_CATEGORY_SPEECH 0x9000
#define BASS_WASAPI_CATEGORY_MOVIE 0xa000
#define BASS_WASAPI_CATEGORY_MEDIA 0xb000
// BASS_WASAPI_INFO "format"
#define BASS_WASAPI_FORMAT_FLOAT 0
#define BASS_WASAPI_FORMAT_8BIT 1
#define BASS_WASAPI_FORMAT_16BIT 2
#define BASS_WASAPI_FORMAT_24BIT 3
#define BASS_WASAPI_FORMAT_32BIT 4
// BASS_WASAPI_Set/GetVolume modes
#define BASS_WASAPI_CURVE_DB 0
#define BASS_WASAPI_CURVE_LINEAR 1
#define BASS_WASAPI_CURVE_WINDOWS 2
#define BASS_WASAPI_VOL_SESSION 8
typedef DWORD (CALLBACK WASAPIPROC)(void *buffer, DWORD length, void *user);
/* WASAPI callback function.
buffer : Buffer containing the sample data
length : Number of bytes
user : The 'user' parameter given when calling BASS_WASAPI_Init
RETURN : The number of bytes written (output devices), 0/1 = stop/continue (input devices) */
// Special WASAPIPROCs
#define WASAPIPROC_PUSH (WASAPIPROC*)0 // push output
#define WASAPIPROC_BASS (WASAPIPROC*)-1 // BASS channel
typedef void (CALLBACK WASAPINOTIFYPROC)(DWORD notify, DWORD device, void *user);
/* WASAPI device notification callback function.
notify : The notification (BASS_WASAPI_NOTIFY_xxx)
device : Device that the notification applies to
user : The 'user' parameter given when calling BASS_WASAPI_SetNotify */
// Device notifications
#define BASS_WASAPI_NOTIFY_ENABLED 0
#define BASS_WASAPI_NOTIFY_DISABLED 1
#define BASS_WASAPI_NOTIFY_DEFOUTPUT 2
#define BASS_WASAPI_NOTIFY_DEFINPUT 3
#define BASS_WASAPI_NOTIFY_FAIL 0x100
DWORD BASSWASAPIDEF(BASS_WASAPI_GetVersion)();
BOOL BASSWASAPIDEF(BASS_WASAPI_SetNotify)(WASAPINOTIFYPROC *proc, void *user);
BOOL BASSWASAPIDEF(BASS_WASAPI_GetDeviceInfo)(DWORD device, BASS_WASAPI_DEVICEINFO *info);
float BASSWASAPIDEF(BASS_WASAPI_GetDeviceLevel)(DWORD device, int chan);
BOOL BASSWASAPIDEF(BASS_WASAPI_SetDevice)(DWORD device);
DWORD BASSWASAPIDEF(BASS_WASAPI_GetDevice)();
DWORD BASSWASAPIDEF(BASS_WASAPI_CheckFormat)(DWORD device, DWORD freq, DWORD chans, DWORD flags);
BOOL BASSWASAPIDEF(BASS_WASAPI_Init)(int device, DWORD freq, DWORD chans, DWORD flags, float buffer, float period, WASAPIPROC *proc, void *user);
BOOL BASSWASAPIDEF(BASS_WASAPI_Free)();
BOOL BASSWASAPIDEF(BASS_WASAPI_GetInfo)(BASS_WASAPI_INFO *info);
float BASSWASAPIDEF(BASS_WASAPI_GetCPU)();
BOOL BASSWASAPIDEF(BASS_WASAPI_Lock)(BOOL lock);
BOOL BASSWASAPIDEF(BASS_WASAPI_Start)();
BOOL BASSWASAPIDEF(BASS_WASAPI_Stop)(BOOL reset);
BOOL BASSWASAPIDEF(BASS_WASAPI_IsStarted)();
BOOL BASSWASAPIDEF(BASS_WASAPI_SetVolume)(DWORD mode, float volume);
float BASSWASAPIDEF(BASS_WASAPI_GetVolume)(DWORD mode);
BOOL BASSWASAPIDEF(BASS_WASAPI_SetMute)(DWORD mode, BOOL mute);
BOOL BASSWASAPIDEF(BASS_WASAPI_GetMute)(DWORD mode);
DWORD BASSWASAPIDEF(BASS_WASAPI_PutData)(void *buffer, DWORD length);
DWORD BASSWASAPIDEF(BASS_WASAPI_GetData)(void *buffer, DWORD length);
DWORD BASSWASAPIDEF(BASS_WASAPI_GetLevel)();
BOOL BASSWASAPIDEF(BASS_WASAPI_GetLevelEx)(float *levels, float length, DWORD flags);
#ifdef __cplusplus
}
#endif
#endif
Binary file not shown.
+2 -2
View File
@@ -80,8 +80,8 @@ void init_packer()
rotate8APSKsyms(_8PSK_headertab[i-1], _8PSK_headertab[i], 8);
}
for(int i=0; i<8; i++)
showbytestring((char*)"8CONST: ",_8PSK_headertab[i],8);
/*for(int i=0; i<8; i++)
showbytestring((char*)"8CONST: ",_8PSK_headertab[i],8);*/
}
// packs a payload into an udp data block
+33 -10
View File
@@ -104,6 +104,8 @@ int rxPreInterpolfactor = 5;
int captureDeviceNo = -1;
int playbackDeviceNo = -1;
int initialPBvol = -1;
int initialCAPvol = -1;
int main(int argc, char* argv[])
{
@@ -164,6 +166,7 @@ int main(int argc, char* argv[])
}
}
#endif
init_packer();
initFEC();
@@ -248,10 +251,12 @@ void startModem()
// int TX audio and modulator
close_dsp();
init_audio(playbackDeviceNo, captureDeviceNo);
setPBvolume(initialPBvol);
setCAPvolume(initialCAPvol);
init_dsp();
}
void setAudioDevices(int pb, int cap)
void setAudioDevices(int pb, int cap, int pbvol, int capvol)
{
//printf("%d %d\n", pb, cap);
@@ -260,6 +265,8 @@ void setAudioDevices(int pb, int cap)
restart_modems = 1;
playbackDeviceNo = pb;
captureDeviceNo = cap;
initialPBvol = pbvol;
initialCAPvol = capvol;
}
}
@@ -268,7 +275,7 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
{
if (len > 0 && pdata[0] == 0x3c)
{
setAudioDevices(pdata[1], pdata[2]);
setAudioDevices(pdata[1], pdata[2], pdata[3], pdata[4]);
char rxip[20];
strcpy(rxip, inet_ntoa(rxsock->sin_addr));
@@ -311,12 +318,6 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
uint8_t type = pdata[0];
uint8_t minfo = pdata[1];
if (len != (PAYLOADLEN + 2))
{
printf("data from app: wrong length:%d (should be %d)\n", len - 2, PAYLOADLEN);
return;
}
// type values: see oscardata config.cs: frame types
if (type == 16)
{
@@ -362,8 +363,30 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
{
// reset liquid RX modem
resetModem();
return;
}
if (type == 21)
{
// set playback volume (in % 0..100)
setVolume(0,minfo);
return;
}
if (type == 22)
{
// set capture volume (in % 0..100)
setVolume(1,minfo);
return;
}
if (len != (PAYLOADLEN + 2))
{
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)
@@ -376,7 +399,7 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
// and bits: symbols * bitsPerSymbol
// and bytes/second: bits/8 = (caprate/txinterpolfactor) * bitsPerSymbol / 8
// one frame has 258 bytes, so we need for 5s: 5* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
int numframespreamble = 3 * ((caprate / txinterpolfactor) * bitsPerSymbol / 8) / 258 + 1;
int numframespreamble = 5 * ((caprate / txinterpolfactor) * bitsPerSymbol / 8) / 258 + 1;
for (int i = 0; i < numframespreamble; i++)
toGR_sendData(pdata + 2, type, minfo);
}
@@ -427,7 +450,7 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
// no frame found
// if longer ws seconds nothing found, reset liquid RX modem
// comes here with symbol rate, i.e. 4000 S/s
int ws = 2;
int ws = 4;
int wt = sr[speedmode].audio / sr[speedmode].tx;
if (++fnd >= (wt * ws))
{
+14 -2
View File
@@ -33,6 +33,7 @@
#include <math.h>
#pragma comment(lib, "bass.lib")
#pragma comment(lib, "basswasapi.lib")
#pragma comment(lib, "libliquid.lib")
#pragma comment(lib, "fftw_lib/libfftw3-3.lib")
#endif
@@ -53,6 +54,7 @@
#endif
#include "bass.h"
#include "basswasapi.h"
#include "liquid.h"
#include "frameformat.h"
#include "fec.h"
@@ -64,6 +66,10 @@
#define CRC16RX 1
#define CRC16FILE 2
// definitions for audio
#define MAXDEVSTRLEN 2000
#define CHANNELS 1 // no of channels used
void init_packer();
uint8_t* Pack(uint8_t* payload, int type, int status, int* plen);
uint8_t* unpack_data(uint8_t* rxd, int len);
@@ -88,7 +94,8 @@ uint8_t* RX_Scramble(uint8_t* data, int len);
uint16_t Crc16_messagecalc(int rxtx, uint8_t* data, int len);
void showbytestring(char* title, uint8_t* data, int anz);
void measure_speed(int len);
void measure_speed_syms(int len);
void measure_speed_bps(int len);
void initFEC();
void GetFEC(uint8_t* txblock, int len, uint8_t* destArray);
@@ -100,11 +107,16 @@ void pb_write_fifo_clear();
void pb_write_fifo(float sample);
int cap_read_fifo(float* data);
uint8_t* getAudioDevicelist(int* len);
void setPBvolume(int v);
void setCAPvolume(int v);
void setVolume(int pbcap, int v);
int init_wasapi(int pbdev, int capdev);
void sleep_ms(int ms);
void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock);
void modulator(uint8_t sym_in);
int pb_fifo_usedBlocks();
void init_dsp();
int demodulator();
void sendToModulator(uint8_t* d, int len);
@@ -127,7 +139,7 @@ extern int UdpDataPort_ModemToApp;
extern int txinterpolfactor;
extern int rxPreInterpolfactor;
extern char appIP[20];
extern float softwareCAPvolume;
#ifdef _LINUX_
int isRunning(char* prgname);
+3
View File
@@ -220,6 +220,8 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="bass.h" />
<ClInclude Include="basswasapi.h" />
<ClInclude Include="fec.h" />
<ClInclude Include="fftw3.h" />
<ClInclude Include="fftw_lib\fftw3.h" />
<ClInclude Include="frameformat.h" />
@@ -229,6 +231,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="audio.cpp" />
<ClCompile Include="audio_wasapi.cpp" />
<ClCompile Include="constellation.cpp" />
<ClCompile Include="crc16.cpp" />
<ClCompile Include="fec.cpp" />
+9
View File
@@ -51,6 +51,9 @@
<ClCompile Include="liquid_if.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="audio_wasapi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="hsmodem.h">
@@ -74,5 +77,11 @@
<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>
</ItemGroup>
</Project>
+10 -2
View File
@@ -288,6 +288,9 @@ void make_FFTdata(float f)
int bidx = 0;
txpl[bidx++] = 4; // type 4: FFT data follows
int us = pb_fifo_usedBlocks();
if (us > 255) us = 255;
txpl[bidx++] = us; // usage of TX fifo
for (int i = 0; i < fftlen; i++)
{
@@ -311,6 +314,11 @@ static int ccol_idx = 0;
int ret = cap_read_fifo(&f);
if(ret == 0) return 0;
// input volume
#ifdef _WIN32_
f *= softwareCAPvolume;
#endif
make_FFTdata(f*120);
// downconvert into baseband
@@ -345,7 +353,7 @@ static int ccol_idx = 0;
unsigned int sym_out; // output symbol
modem_demodulate(demod, syms, &sym_out);
measure_speed(1);
//measure_speed_syms(1);
// try to extract a complete frame
uint8_t symb = sym_out;
@@ -356,7 +364,7 @@ static int ccol_idx = 0;
// 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 >= 2)
if (++ev >= 2)
{
ev = 0;
uint32_t re = (uint32_t)(syms.real * 16777216.0);
+60 -3
View File
@@ -28,6 +28,7 @@ int speed = 0;
#define MAXSPDARR 5
int spdarr[MAXSPDARR];
int spdarrbps[MAXSPDARR];
#ifdef _LINUX_
int getus()
@@ -79,9 +80,37 @@ static int f=1;
return ssum;
}
int meanvalbps(int v)
{
static int f = 1;
if (f)
{
for (int i = 0; i < MAXSPDARR; i++) spdarrbps[i] = -1;
f = 0;
}
for (int i = (MAXSPDARR - 1); i > 0; i--)
spdarrbps[i] = spdarrbps[i - 1];
spdarrbps[0] = v;
int ssum = 0;
int cnt = 0;
for (int i = 0; i < MAXSPDARR; i++)
{
if (spdarrbps[i] != -1)
{
ssum += spdarrbps[i];
cnt++;
}
}
ssum /= cnt;
return ssum;
}
// len ... number of symbols
// measures and calculates the speed in bit / s
void measure_speed(int len)
void measure_speed_syms(int len)
{
static int lasttim = 0;
static int elems = 0;
@@ -96,15 +125,43 @@ void measure_speed(int len)
elems += len;
if(timespan < 2000000) return;
if(timespan < 1000000) return;
double dspd = elems;
dspd = dspd * 1e6 / timespan;
speed = meanval((int)dspd) * bitsPerSymbol;
// here we have number of elements after 1s
//printf("%d items/s\n",speed);
printf("%d sym/s\n",speed);
elems=0;
lasttim = tim;
}
void measure_speed_bps(int len)
{
static int lasttim = 0;
static int elems = 0;
int tim = getus();
int timespan = tim - lasttim;
if (timespan < 0)
{
lasttim = tim;
return;
}
elems += len;
if (timespan < 1000000) return;
double dspd = elems;
dspd = dspd * 1e6 / timespan;
speed = meanvalbps((int)dspd);
// here we have number of elements after 1s
printf("%d bit/s\n", speed);
elems = 0;
lasttim = tim;
}
+2
View File
@@ -106,6 +106,7 @@ void UdpRxInit(int *sock, int port, void (*rxfunc)(uint8_t *, int, struct sockad
#ifdef _LINUX_
void* threadfunction(void* param) {
socklen_t fromlen;
pthread_detach(pthread_self());
#endif
#ifdef _WIN32_
@@ -129,6 +130,7 @@ void threadfunction(void* param) {
}
#ifdef _LINUX_
pthread_exit(NULL); // self terminate this thread
return NULL;
#endif
}