This commit is contained in:
[Harper Innes]
2024-02-04 18:15:02 +11:00
parent 800152681c
commit b0ab60c827
823 changed files with 303020 additions and 0 deletions

View File

@ -0,0 +1,609 @@
#include "mscore.h"
#if defined _LINUX_
//#include <QtGui>
#include <pulse/pulseaudio.h>
#include <pulse/simple.h>
pa_simple *s_pulse_rx = NULL;
int MsCore::alsa_read_sound()
{
int count = 0;
if (!is_pulse_a_in)
{
//////////////////////tova go zabavia ne znam kak /////////////////////////////////////////////////////////////
static unsigned long long int time0 = 0; // times are in microseconds
unsigned long long int time;
struct timespec tspec, trem;
int timer;//, count;
struct timeval tv;
#if DEBUG > 2
static unsigned long long int stime = 0;
static int samples;
static int calls=0, waits=0;
#endif
// gettimeofday(&tv, NULL);
tv.tv_sec = 200;
tv.tv_usec = 200;
time = tv.tv_sec * 1000000 + tv.tv_usec;
timer = rad_sound_state.data_poll_usec - (int)(time - time0); // time remaining from last poll
if (timer > 1000)
{ // see if enough time has elapsed
// wait for the remainder of the poll interval
tspec.tv_sec = 0;
tspec.tv_nsec = timer * 1000;
clock_nanosleep(CLOCK_MONOTONIC, 0, &tspec, &trem);
#if DEBUG > 2
waits++;
}
calls++;
if (calls % 400 == 0)
{
#if DEBUG > 3
printf("quisk_read_sound calls %d, waits %d, waits %.2f %%\n", calls, waits, 100.0 * waits / calls);
#endif
calls = waits = 0;
}
#else
}
#endif
// gettimeofday(&tv, NULL); // reset starting time value
tv.tv_sec = 200;
tv.tv_usec = 200;
time0 = tv.tv_sec * 1000000 + tv.tv_usec;
//////////////////////tova go zabavia ne znam kak /////////////////////////////////////////////////////////////
count = read_alsa();// read from ALSA soundcard
//2.57
short *dat_t = new short[count+10];
for (int j = 0; j < count; ++j)
{
if (sample_bytes == 2 || sample_bytes == 4) dat_t[j] = cSamples_l[j]/65536; //int to short
else if (sample_bytes == 3) dat_t[j] = cSamples_l[j]/256; //int to short
}
ResampleAndFilter(dat_t,count);
delete [] dat_t;
//////////////////////tova go zabavia ne znam kak /////////////////////////////////////////////////////////////
#if DEBUG > 3
if (stime == 0)
{
stime = time0;
samples = 0;
}
else if (time0 - stime > 5000000)
{
samples += nSamples;
printf("sample rate %.2f\n", 1e6 * samples / (time0 - stime));
stime = 0;
}
else
{
samples += nSamples;
}
#endif
//////////////////////tova go zabavia ne znam kak /////////////////////////////////////////////////////////////
}
else
{
//int k = 0;
//st->sampc = prm->srate * prm->ch * prm->ptime / 1000;
//num_bytes = st->sampc * st->sampsz;
const int buf_c = 1024;//4096;//2048;
short buf[buf_c];
int bufsize = buf_c * sizeof(short);
//if (bufsize > buf_c) bufsize = buf_c;
// Record some data ...
int error;
if (pa_simple_read(s_pulse_rx, buf, bufsize, &error) < 0)
{
//fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error));
//goto finish;
return 0;
}
int cnt = bufsize / sizeof(short);
for (int i = 0; i<cnt; i += 2, count++)//chan_capt
{
short si = buf[i + channel_I];
short sq = buf[i + channel_Q];
/*int si,sq;
memcpy((unsigned char *)&si + 1, buf + (i + channel_I) * 3, 3);
memcpy((unsigned char *)&sq + 1, buf + (i + channel_Q) * 3, 3);*/
//int16_t si = buf[i] + ((uint32_t)buf[i+1] << 8);
//int16_t sq = buf[i+0] + ((uint32_t)buf[i+1] << 8);
if (si >= CLIP16 || si <= -CLIP16)
quisk_overrange++; // assume overrange returns max int
if (sq >= CLIP16 || sq <= -CLIP16)
quisk_overrange++;
//ii = si << 16;
//qq = sq << 16;
cSamples_l[count] = si;
cSamples_r[count] = sq;
}
//2.57
short *dat_t = new short[count+10];
for (int j = 0; j < count; ++j) dat_t[j] = cSamples_l[j];//int to short
ResampleAndFilter(dat_t,count);
delete [] dat_t;
}
return count;
}
int MsCore::read_alsa()
{ // read sound samples from the ALSA soundcard
int i;
snd_pcm_sframes_t frames, avail;
short si, sq;
int ii, qq;
int nSamples;
/*double c_l;
double c_r;
double dc_remove_l=0;
double dc_remove_r=0;*/
#ifdef FIX_H101
static short save_sq = 0;
#endif
if (!hCapture)
return -1;
avail = 0;
snd_pcm_delay(hCapture, &avail); // samples available in the capture buffer
nSamples = 0;
if (avail > SAMP_BUFFER_SIZE / chan_capt) // limit read request to buffer size
avail = SAMP_BUFFER_SIZE / chan_capt;
switch (sample_bytes)
{
case 2:
frames = snd_pcm_readi (hCapture, buffer2, avail); // read available samples
if (frames == -EAGAIN)
{ // no samples available
break;
}
else if (frames <= 0)
{ // error
rad_sound_state.read_error++;
snd_pcm_prepare (hCapture);
snd_pcm_start (hCapture);
break;
}
for (i = 0; frames; i += chan_capt, nSamples++, frames--)
{
si = buffer2[i + channel_I];
sq = buffer2[i + channel_Q];
if (si >= CLIP16 || si <= -CLIP16)
quisk_overrange++; // assume overrange returns max int
if (sq >= CLIP16 || sq <= -CLIP16)
quisk_overrange++;
ii = si << 16;
#ifdef FIX_H101
qq = save_sq << 16;
save_sq = sq;
#else
qq = sq << 16;
#endif
cSamples_l[nSamples] = ii;
cSamples_r[nSamples] = qq;
}
break;
case 3:
frames = snd_pcm_readi (hCapture, buffer3, avail); // read available samples
if (frames == -EAGAIN)
{ // no samples available
break;
}
else if (frames <= 0)
{ // error
rad_sound_state.read_error++;
snd_pcm_prepare (hCapture);
snd_pcm_start (hCapture);
break;
}
for (i = 0; frames; i += chan_capt, nSamples++, frames--)
{
ii = qq = 0;
if (convert_sample_bytes == ThreeLittle2Big)
{
*((unsigned char *)&ii ) = buffer3[(i + channel_I) * 3 + 2];
*((unsigned char *)&ii + 1) = buffer3[(i + channel_I) * 3 + 1];
*((unsigned char *)&ii + 2) = buffer3[(i + channel_I) * 3 ];
*((unsigned char *)&qq ) = buffer3[(i + channel_Q) * 3 + 2];
*((unsigned char *)&qq + 1) = buffer3[(i + channel_Q) * 3 + 1];
*((unsigned char *)&qq + 2) = buffer3[(i + channel_Q) * 3 ];
}
else
{ // ThreeLittle2Little
memcpy((unsigned char *)&ii + 1, buffer3 + (i + channel_I) * 3, 3);
memcpy((unsigned char *)&qq + 1, buffer3 + (i + channel_Q) * 3, 3);
}
if (ii >= CLIP32 || ii <= -CLIP32)
quisk_overrange++; // assume overrange returns max int
if (qq >= CLIP32 || qq <= -CLIP32)
quisk_overrange++;
cSamples_l[nSamples] = ii;
cSamples_r[nSamples] = qq;
}
break;
case 4:
frames = snd_pcm_readi (hCapture, buffer4, avail); // read available samples
if (frames == -EAGAIN)
{ // no samples available
break;
}
else if (frames <= 0)
{ // error
rad_sound_state.read_error++;
snd_pcm_prepare (hCapture);
snd_pcm_start (hCapture);
break;
}
for (i = 0; frames; i += chan_capt, nSamples++, frames--)
{
ii = buffer4[i + channel_I];
qq = buffer4[i + channel_Q];
if (ii >= CLIP32 || ii <= -CLIP32)
quisk_overrange++; // assume overrange returns max int
if (qq >= CLIP32 || qq <= -CLIP32)
quisk_overrange++;
cSamples_l[nSamples] = ii;
cSamples_r[nSamples] = qq;
}
break;
}
/* for (i=0; i < nSamples; i++)
{ // DC removal; R.G. Lyons page 553
c_l = cSamples_l[i] + dc_remove_l * 0.95;
cSamples_l[i] = c_l - dc_remove_l;
dc_remove_l = c_l;
c_r = cSamples_r[i] + dc_remove_r * 0.95;
cSamples_r[i] = c_r - dc_remove_r;
dc_remove_r = c_r;
//cSamples_l[i]*=2;
//cSamples_r[i]*=2;
}*/
return nSamples;
}
void MsCore::rad_open_sound()
{
rad_close_sound();
if (!is_pulse_a_in)
{
//rad_close_sound();
is_little_endian = 1; // Test machine byte order
if (*(char *)&is_little_endian == 1)
is_little_endian = 1;
else
is_little_endian = 0;
rad_sound_state.read_error = 0;
rad_sound_state.write_error = 0;
rad_sound_state.underrun_error = 0;
rad_sound_state.interupts = 0;
rad_sound_state.rate_min = rad_sound_state.rate_max = -99;
rad_sound_state.chan_min = rad_sound_state.chan_max = -99;
rad_sound_state.msg1[0] = 0;
rad_sound_state.err_msg[0] = 0;
rad_sound_state.bad_device = 1;
// rad_sound_state.sdriq_audio_decim = 1.0; // No audio decimation
open_alsa_capture();
//qDebug()<<"------------"<<hCapture<<(bool)rad_sound_state.err_msg[0];
if (rad_sound_state.err_msg[0])
return; // error return
if (hCapture)
snd_pcm_start(hCapture);
}
else
{
// The sample type to use
/*is_little_endian = 1; // Test machine byte order
if (*(char *)&is_little_endian == 1)
is_little_endian = 1;
else
is_little_endian = 0;
//is_little_endian = 0; // test*/
pa_sample_format_t Format_LE_BE = PA_SAMPLE_S16LE;
//if (!is_little_endian) Format_LE_BE = PA_SAMPLE_S16BE;
pa_sample_spec ss;
ss.format = Format_LE_BE;
ss.rate = (uint32_t)in_sample_rate;
ss.channels = 2;
int latency = 200000;//in useconds 1000000;
pa_buffer_attr bufattr;
//memset(&bufattr, 0, sizeof(bufattr));
bufattr.fragsize = (uint8_t)-1;//=255
bufattr.maxlength = pa_usec_to_bytes(latency,&ss);
bufattr.minreq = pa_usec_to_bytes(0,&ss);
bufattr.prebuf = (uint8_t)-1;//=255
bufattr.tlength = pa_usec_to_bytes(latency,&ss);
//qDebug()<<"-----------------"<<(uint8_t)-1;
/*bufattr.maxlength = (uint32_t)-1;
bufattr.tlength = (uint32_t)-1;
bufattr.prebuf = (uint32_t)-1;
bufattr.minreq = (uint32_t)-1;
bufattr.fragsize = (uint32_t)pa_usec_to_bytes(1 * 10, &ss);*/
/*bufattr.tlength = (uint32_t) latency;
bufattr.minreq = (uint32_t) 1000;
bufattr.maxlength = (uint32_t) -1;
bufattr.prebuf = (uint32_t) -1;
bufattr.fragsize = (uint32_t) latency;*/
int error;
QString str_device_name = (QString)rad_sound_state.dev_capt_name;
str_device_name.remove("pulse: ");
if (str_device_name == "default")
{
//qDebug()<<"-----------------------"<<"default";
if (!(s_pulse_rx = pa_simple_new(NULL, "MSHV", PA_STREAM_RECORD, NULL, "Receive", &ss, NULL, &bufattr, &error)))
{
//fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
return;
}
}
else
{
//char *ddevv = q-strdup(qPrintable(str_device_name));
static char ddevv[128];//2.50
strncpy(ddevv,str_device_name.toUtf8(),127);
//qDebug()<<"-----------------------"<<ddevv;
if (!(s_pulse_rx = pa_simple_new(NULL, "MSHV", PA_STREAM_RECORD, ddevv, "Receive", &ss, NULL, &bufattr, &error)))
{
//fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
return;
}
}
}
}
void MsCore::rad_close_sound()
{
if (hCapture)
{
snd_pcm_drop(hCapture);
snd_pcm_close(hCapture);
hCapture = NULL;
}
strncpy (rad_sound_state.err_msg, CLOSED_TEXT, SC_SIZE_L);
rad_sound_state.bad_device = 1;
//qDebug()<<"close handles";
if (s_pulse_rx)
{
pa_simple_free(s_pulse_rx);
//pa_simple_drain(s_pulse, NULL);
s_pulse_rx = NULL;
//usleep(5000000);
}
}
void MsCore::open_alsa_capture()
{ // Open the ALSA soundcard for capture and perhaps playback. Detect the
// capture parameters and make the playback parameters the same.
int chan_needed, err, dir;
int poll_size;
//unsigned int ui;
snd_pcm_hw_params_t *hware;
snd_pcm_sw_params_t *sware;
snd_pcm_uframes_t frames;
snd_pcm_format_t format;
//qDebug()<<"format="<<hCapture<<rad_sound_state.dev_capt_name<<SND_PCM_STREAM_CAPTURE<<SND_PCM_NONBLOCK;
if ((err = snd_pcm_open (&hCapture, rad_sound_state.dev_capt_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0)
{
//stop 2.26 qt5 gcc7.3.1
//snprintf(rad_sound_state.err_msg, SC_SIZE_L, "Cannot open capture device %s (%s)",
// rad_sound_state.dev_capt_name, snd_strerror (err));
//qDebug()<<"------------"<<hCapture;
return;
}
if ((err = snd_pcm_sw_params_malloc (&sware)) < 0)
{
snprintf (rad_sound_state.err_msg, SC_SIZE_L, "Cannot allocate software parameter structure (%s)\n",
snd_strerror (err));
return;
}
if ((err = snd_pcm_hw_params_malloc (&hware)) < 0)
{
snprintf (rad_sound_state.err_msg, SC_SIZE_L, "Cannot allocate hardware parameter structure (%s)\n",
snd_strerror (err));
snd_pcm_sw_params_free (sware);
return;
}
if ((err = snd_pcm_hw_params_any (hCapture, hware)) < 0)
{
snprintf (rad_sound_state.err_msg, SC_SIZE_L, "Cannot initialize capture parameters (%s)\n",
snd_strerror (err));
goto errend;
}
/* UNAVAILABLE
if ((err = snd_pcm_hw_params_set_rate_resample (hCapture, hware, 0)) < 0) {
snprintf (quisk_sound_state.err_msg, SC_SIZE_L, "Cannot disable resampling (%s)\n",
snd_strerror (err));
goto errend;
}
*/
rad_sound_state.bad_device = 0;
// Get some parameters to send back
if (snd_pcm_hw_params_get_rate_min(hware, &rad_sound_state.rate_min, &dir) != 0)
rad_sound_state.rate_min = 0; // Error
if (snd_pcm_hw_params_get_rate_max(hware, &rad_sound_state.rate_max, &dir) != 0)
rad_sound_state.rate_max = 0; // Error
if (snd_pcm_hw_params_get_channels_min(hware, &rad_sound_state.chan_min) != 0)
rad_sound_state.chan_min= 0; // Error
if (snd_pcm_hw_params_get_channels_max(hware, &rad_sound_state.chan_max) != 0)
rad_sound_state.chan_max= 0; // Error
// Set the capture parameters
format = check_formats(hCapture, hware);
//qDebug()<<"format================="<<format<<SND_PCM_FORMAT_UNKNOWN;
if (format == SND_PCM_FORMAT_UNKNOWN)
{
strncpy (rad_sound_state.err_msg, "MSHV does not support your format.", SC_SIZE_L);
goto errend;
}
//sample_rate = 44100;// rad_sound_state.sample_rate;
//qDebug()<<sample_rate;
if (snd_pcm_hw_params_set_rate (hCapture, hware, in_sample_rate, 0) < 0)
{
snprintf (rad_sound_state.err_msg, SC_SIZE_L, "Can not set sample rate %d",
in_sample_rate);
goto errend;
}
if (snd_pcm_hw_params_set_access (hCapture, hware, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
{
strncpy(rad_sound_state.err_msg, "Interleaved access is not available", SC_SIZE_L);
goto errend;
}
channel_I = rad_sound_state.channel_I;
channel_Q = rad_sound_state.channel_Q;
chan_needed = channel_I; // Set number of channels to highest index + 1
if (chan_needed < channel_Q)
chan_needed = channel_Q;
chan_needed++;
chan_capt = chan_needed;
if (chan_capt < (int)rad_sound_state.chan_min)//hv
chan_capt = rad_sound_state.chan_min;
if (snd_pcm_hw_params_set_channels (hCapture, hware, chan_capt) < 0)
{
snprintf (rad_sound_state.err_msg, SC_SIZE_L, "Can not set channels to %d", chan_capt);
goto errend;
}
// Try to set a capture buffer larger than needed
frames = in_sample_rate * 200 / 1000; // buffer size in milliseconds
if (snd_pcm_hw_params_set_buffer_size_near (hCapture, hware, &frames) < 0)
{
snprintf (rad_sound_state.err_msg, SC_SIZE_L, "Can not set capture buffer size");
goto errend;
}
poll_size = in_sample_rate * rad_sound_state.data_poll_usec / 1000000;
if (frames < (snd_pcm_uframes_t)poll_size * 3)
{ // buffer size is too small, reduce poll time
rad_sound_state.data_poll_usec = frames * 1000000 / in_sample_rate / 3;
#if DEBUG
printf("Reduced data_poll_usec %d for small sound capture buffer\n",
rad_sound_state.data_poll_usec);
#endif
}
#if DEBUG
printf("Capture buffer size %d\n", (int)frames);
if (frames > SAMP_BUFFER_SIZE / chan_capt)
printf("Capture buffer exceeds size of sample buffers\n");
#endif
if ((err = snd_pcm_hw_params (hCapture, hware)) < 0)
{
snprintf (rad_sound_state.err_msg, SC_SIZE_L, "Cannot set hw capture parameters (%s)\n",
snd_strerror (err));
goto errend;
}
if ((err = snd_pcm_sw_params_current (hCapture, sware)) < 0)
{
snprintf (rad_sound_state.err_msg, SC_SIZE_L, "Cannot get software capture parameters (%s)\n",
snd_strerror (err));
goto errend;
}
if (chan_capt <= 0) // ima problem po niakoga go dava 0 igarmi hv
chan_capt = 2; // ima problem po niakoga go dava 0 igarmi hv
//qDebug()<<chan_capt;
if ((err = snd_pcm_prepare (hCapture)) < 0)
{
snprintf (rad_sound_state.err_msg, SC_SIZE_L, "Cannot prepare capture interface for use (%s)\n",
snd_strerror (err));
goto errend;
}
// Now open the microphone
//if (rad_sound_state.mic_dev_name[0])
//open_microphone();
errend:
snd_pcm_hw_params_free (hware);
snd_pcm_sw_params_free (sware); ///qDebug()<<sample_bytes;//qDebug()<<"read";
return;
}
snd_pcm_format_t MsCore::check_formats(snd_pcm_t *h, snd_pcm_hw_params_t *hware)
{
snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
sample_bytes = 0;
strncpy (rad_sound_state.msg1, "Available formats: ", SC_SIZE_L);
if (snd_pcm_hw_params_test_format (h, hware, SND_PCM_FORMAT_S32) == 0)
{
if (!sample_bytes)
{
strncat(rad_sound_state.msg1, "*", SC_SIZE_L);
sample_bytes = 4;
format = SND_PCM_FORMAT_S32;
}
strncat(rad_sound_state.msg1, "S32 ", SC_SIZE_L);
}
if (snd_pcm_hw_params_test_format (h, hware, SND_PCM_FORMAT_U32) == 0)
{
strncat(rad_sound_state.msg1, "U32 ", SC_SIZE_L);
}
if (snd_pcm_hw_params_test_format (h, hware, SND_PCM_FORMAT_S24) == 0)
{
strncat(rad_sound_state.msg1, "S24 ", SC_SIZE_L);
}
if (snd_pcm_hw_params_test_format (h, hware, SND_PCM_FORMAT_U24) == 0)
{
strncat(rad_sound_state.msg1, "U24 ", SC_SIZE_L);
}
if (snd_pcm_hw_params_test_format (h, hware, SND_PCM_FORMAT_S24_3LE) == 0)
{
if (!sample_bytes)
{
strncat(rad_sound_state.msg1, "*", SC_SIZE_L);
sample_bytes = 3;
format = SND_PCM_FORMAT_S24_3LE;
if (is_little_endian)
convert_sample_bytes = ThreeLittle2Little; // Convert little endian to little
else
convert_sample_bytes = ThreeLittle2Big; // Convert little endian to big
}
strncat(rad_sound_state.msg1, "S24_3LE ", SC_SIZE_L);
}
if (snd_pcm_hw_params_test_format (h, hware, SND_PCM_FORMAT_S16) == 0)
{
if (!sample_bytes)
{
strncat(rad_sound_state.msg1, "*", SC_SIZE_L);
sample_bytes = 2;
format = SND_PCM_FORMAT_S16;
}
strncat(rad_sound_state.msg1, "S16 ", SC_SIZE_L);
}
if (snd_pcm_hw_params_test_format (h, hware, SND_PCM_FORMAT_U16) == 0)
{
strncat(rad_sound_state.msg1, "U16 ", SC_SIZE_L);
}
if (format == SND_PCM_FORMAT_UNKNOWN)
strncat(rad_sound_state.msg1, "*UNSUPPORTED", SC_SIZE_L);
else
snd_pcm_hw_params_set_format (h, hware, format);
//qDebug()<<"Format"<<format<<sample_bytes;
return format;
}
#endif

View File

@ -0,0 +1,910 @@
/* MSHV MsCore
* Copyright 2015 Hrisimir Hristov, LZ2HV
* May be used under the terms of the GNU General Public License (GPL)
*/
#include "mscore.h"
#include <algorithm> // zaradi max(
//#include <unistd.h>
using namespace std; // zaradi max(
//static const double IN_SAMPLE_RATE =11025.0;//no inposible hv rawfilter need to be off
//static const double IN_SAMPLE_RATE =22050.0;
static const double IN_SAMPLE_RATE_44100 =44100.0;
static const double IN_SAMPLE_RATE_48000 =48000.0;
//#define FFT_SAMPLE_RATE 11025
static const double ORG_SAMPLE_RATE_11025 = 11025.0;
static const double ORG_SAMPLE_RATE_12000 = 12000.0;
#include <QDateTime>
//#include <QtGui>
MsCore::MsCore()
{
//facalcvd = 1.0;
//f_adle_vd = false;
ftci = false;//tci
is_select_sound_device = true;
//s_fft_cut_hi_frq = FFT_CUT_HI_FRQ;
dec_busy = false;
s_data_dsp_height = DATA_DSP_HEIGHT;
s_fft_end_frq = FFT_END_FRQ;
s_fft_cut_low_frq = FFT_CUT_LOW_FRQ; //1.38 forget in soorry 1.37
s_data_width = DATA_WIDTH;
s_data_height = DATA_HEIGHT;
count_rfesh_sm = 0;// zaradi bavnoto na jt65abc
s_vdisp_speed = 2;
s_freq_beg = 200;
s_freq_end = 2200; //2000 hz bw
f_disp_v_h = false;
last_reset_sc_in = QDateTime::currentDateTimeUtc().toTime_t();
s_in_level = 1.0;
//period_time_sec = (int)STATIC_FFTW_PERIOD_TIME;
//save_rms_points = 2;//vnimanie triabva da e pomalko ot ->RMS_BUF_SIZE w MsCore.h
g_read_snd = false;//true;
sta_sto_flag = false;
draw_flag = false;
y_count = 0;
saved_sinh_val = 0;
compare_sinh_val = 0;
sinh_sleep = 0;
//////////////////////////////////////////////////////////////////////
s_mod_iden = 2;//HV important set to default mode fsk441
fftw_sample_rate = (int)ORG_SAMPLE_RATE_11025;//HV important set to default mode fsk441 sample rate
in_sample_rate = IN_SAMPLE_RATE_44100; //HV important set to default mode fsk441 sample rate
koef_resample = (int)((in_sample_rate/ORG_SAMPLE_RATE_11025)-1);//HV important set to default mode fsk441 sample rate
//////////////////////////////////////////////////////////////////////
THvRawFilter = new HvRawFilter(49,100.0,5000.0,false);//false -> LPF+HPF /* low pass filter and High pass filter */ for RX
THvRawFilter->set_rate(fftw_sample_rate);//2.34
#if defined _LINUX_
is_pulse_a_in = true;//2.65 default pulse
hCapture = NULL;
is_little_endian = 0;
#endif
#if defined _LINUX_
//strncpy(rad_sound_state.dev_capt_name, "hw:0,0", SC_SIZE_L); //2.65 default pulse
strncpy(rad_sound_state.dev_capt_name, "pulse: default", SC_SIZE_L);
#endif
#if defined _WIN32_ //Primary Sound Capture Driver or "0"
strncpy(rad_sound_state.dev_capt_name, "Primary Sound Capture Driver", SC_SIZE_L);//
#endif
s_count_resample = 0;
rad_sound_state.latency_millisecs = 100;
rad_sound_state.data_poll_usec = 5000;
rad_sound_state.channel_I = 0;//0 //standart->1 X-Fi->0
rad_sound_state.channel_Q = 1;//1 //standart->0 X-Fi->1
rad_sound_state.read_error = 0;
rad_sound_state.write_error = 0;
rad_sound_state.underrun_error = 0;
rad_sound_state.interupts = 0;
FFT1 = FFT2 = ptWriteFft = NULL;
count_ftt_window = 0;
bool p_read_snd = true;
#if defined _WIN32_
is_select_sound_device = select_device(true);//v1.46
p_read_snd = is_select_sound_device;
if (p_read_snd) p_read_snd = start_sound();
#endif
#if defined _LINUX_
rad_open_sound();
#endif
QTimer *timer_ref_ = new QTimer();
connect(timer_ref_, SIGNAL(timeout()), this, SLOT(Refresh_t()));
timer_ref_->start(5);//5ms refresh time
timer_fr_sound = new QTimer();
connect(timer_fr_sound, SIGNAL(timeout()), this, SLOT(FastResetSoundCardIn_p()));
// SETUP APP FOR ALL MODES ///////////////////////////
fftw_sample_rate=(int)ORG_SAMPLE_RATE_12000;
record_app();//msk144
f_disp_v_h = true;
fftw_sample_rate=(int)ORG_SAMPLE_RATE_12000;
for (int i=1; i<10; i++)//1.51 10 9-speads //da se smeni na -> 6
{
s_vdisp_speed = i;
//SetupSettings_((QString)rad_sound_state.dev_capt_name,QString("%1").arg(in_sample_rate),rad_sound_state.latency_millisecs,
//rad_sound_state.data_poll_usec,rad_sound_state.channel_I,true);
record_app(); //jt65abc
}
f_disp_v_h = false;
s_vdisp_speed = 2;
fftw_sample_rate=(int)ORG_SAMPLE_RATE_11025;
record_app();//jtms to jt6m
// END SETUP APP FOR ALL MODES ///////////////////////////
usleep(2000);
//qDebug()<<((192000 * (( 1 * 16 ) / 8)) * 120 + 32);
//qDebug()<<sizeof(double);
g_read_snd = p_read_snd;//false;
//SetStr_Sto(false);
//qDebug()<<"CREATED";
}
MsCore::~MsCore()
{
delete THvRawFilter;
}
void MsCore::SetInLevel(int val)
{
//s_in_level = pow(10, ((double)(val - 50)/4)/20); // +- 12.5db
s_in_level = pow(10, ((double)(val - 50)/2.5)/20.0);// +- 20db 1.78
//qDebug()<<s_in_level;
}
void MsCore::close_sound()
{
if (ftci) return;//tci
#if defined _WIN32_
//qDebug()<<"TRAY StopSound";
if (lpdCaptureBuff)//from v1.46
{
stop_sound();
lpdCaptureBuff->Release();
lpdCapture->Release();
lpdCaptureBuff = NULL;//2.49 protection
//lpdCapture = NULL;
//if (lpdCaptureBuff) qDebug()<<"close lpdCaptureBuff true";
//else qDebug()<<"close lpdCaptureBuff false";
}
#endif
#if defined _LINUX_
rad_close_sound();
#endif
}
void MsCore::SetStr_Sto(bool flag)
{
g_read_snd = false;
sta_sto_flag = flag;
bool p_read_snd = true;
#if defined _WIN32_
if (!ftci)//tci
{
if (sta_sto_flag)
{
p_read_snd = select_device(false); //2.49 exception GUID is Changed
if (p_read_snd) p_read_snd = start_sound();
}
else
{
if (lpdCaptureBuff)//1.46
stop_sound();
//if (lpdCaptureBuff) qDebug()<<"stop lpdCaptureBuff true";
//else qDebug()<<"stop lpdCaptureBuff false";
}
}
#endif
g_read_snd = p_read_snd;
if (sta_sto_flag) // if app long time in stop fast reset sound card
{
FastResetSoundCardIn();
}
}
void MsCore::SetMode(int mod_iden)
{
s_mod_iden = mod_iden;
QString rate;
/*if (s_mod_iden == 0 || s_mod_iden == 7 || s_mod_iden == 8 || s_mod_iden == 9 ||
s_mod_iden == 10 || s_mod_iden == 11 || s_mod_iden == 12 || s_mod_iden == 13 ||
s_mod_iden == 14 || s_mod_iden == 15 || s_mod_iden == 16 || s_mod_iden == 17)//msk144 //jt65abc pi4 ft8 ft4 q65
rate = QString("%1").arg((int)IN_SAMPLE_RATE_48000);
else //if (s_mod_iden>0 && s_mod_iden<7)
rate = QString("%1").arg((int)IN_SAMPLE_RATE_44100);*/
if (s_mod_iden>0 && s_mod_iden<7) //2.65
rate = QString("%1").arg((int)IN_SAMPLE_RATE_44100);
else
rate = QString("%1").arg((int)IN_SAMPLE_RATE_48000);
if (s_mod_iden == 7 || s_mod_iden == 8 || s_mod_iden == 9 || s_mod_iden == 10 || s_mod_iden == 11 || s_mod_iden == 13 ||
s_mod_iden == 14 || s_mod_iden == 15 || s_mod_iden == 16 || s_mod_iden == 17)////jt65abc pi4 ft8 ft4 q65
f_disp_v_h = true;
else
f_disp_v_h = false;
SetupSettings_((QString)rad_sound_state.dev_capt_name,rate,rad_sound_state.latency_millisecs,
rad_sound_state.data_poll_usec,rad_sound_state.channel_I,true);
}
void MsCore::SetupSettings(QString dev_in_number,int latency,int card_buffer_polls,int channel)// QString,
{
//qDebug()<<"DN="<<dev_in_number<<in_sample_rate;
if ((QString)rad_sound_state.dev_capt_name == dev_in_number && /*rad_sound_state.sample_rate == rate.toInt() &&*/
rad_sound_state.latency_millisecs == latency && rad_sound_state.data_poll_usec == card_buffer_polls &&
rad_sound_state.channel_I == channel)
return;//za da ne garmi pod windows
SetupSettings_(dev_in_number,QString("%1").arg(in_sample_rate),latency,card_buffer_polls,channel,false);
}
void MsCore::record_app()
{
//qDebug()<<"Start record_app";
int i, j;
fftw_complex * pt;
fft_data * pt1, * pt2;
double graph_refresh;
//if (f_disp_v_h)
//graph_refresh = 100.0;
//else
graph_refresh = 100.0; //7 refresha na fft hv zavisi ot samplerate
/*(about 800 to 1200 pixels) times the fft_size_multiplier. You can make fft_size_multiplier
about 2 to 4, to make the FFT bins smaller if you have the processor power.*/
////HV spriano //////////////////////////////////////
//int fft_size_multiplier = 2;
//fft_size = GRAPHIC_HEIGHT * fft_size_multiplier;
//while (fft_size < (rad_sound_state.sample_rate * rad_sound_state.data_poll_usec / 1000000))
//fft_size += GRAPHIC_HEIGHT;
////HV spriano ////////////////////////////////////////
//fftw_sample_rate=ORG_SAMPLE_RATE_11025;
double scale_x_inc_pix;
if (f_disp_v_h) /// DATA_HEIGHT*2 -25 -19 -25<freq bara (- 10 malko ot dolnia disp)
scale_x_inc_pix = (double)(((double)(s_data_height*2 -25 - 10)/(double)s_vdisp_speed) /(double)STAT_FFTW_V60_TIME);
else
scale_x_inc_pix = (double)((double)s_data_width /(double)STAT_FFTW_H30_TIME);// prez kolko piksela za sekunta
fft_size = (int)((double)fftw_sample_rate /(double)scale_x_inc_pix); // fft_size za da upalni celia ekran
//qDebug()<<"fft_size="<<fft_size<<"fft_size_end="<<fft_size/4;
average_count = max(1, int((double)fftw_sample_rate / (double)fft_size / graph_refresh));
/*s_scale = 2.0 / (double)average_count / (double)fft_size; //add 1.37 Divide by sample count
s_scale /= pow(2.0, 31);//2.0, 31 //add 1.37 Normalize to max == 1*/
s_scale = 2.0 / (double)average_count / (double)fft_size; //add 1.37 Divide by sample count
if (f_disp_v_h)//v1.51 corr for 9-v speeds
{
/*double k_correct = 0.25*(double)(s_vdisp_speed*s_vdisp_speed);
s_scale = s_scale*((double)s_vdisp_speed*k_correct+(1.0-k_correct));
s_scale /= pow(2.0, 14)*1.2;//2.46 5)*1.6=half*/
double k_correct = 0.25; //old
s_scale = s_scale*((double)s_vdisp_speed*k_correct+(1.0-k_correct));
s_scale /= pow(2.0, 23); //*1.0
}
else
s_scale /= pow(2.0, 24)*1.2;//2.46 old pow(2.0, 31); //add 1.37 Normalize to max == 1
//qDebug()<<"fft_size="<<fft_size;//<<average_count<<s_scale;//<<average_countd;
strncpy (rad_sound_state.err_msg, CLOSED_TEXT, SC_SIZE_L);
count_fft = 0;
pt1 = FFT1;
pt2 = FFT2;
FFT1 = FFT2 = ptWriteFft = NULL; // The callback may be active!
// Create space for the fft
if (pt1)
{
fftw_destroy_plan(pt1->plan_dsp);
fftw_free(pt1->samples);
free(pt1);
}
pt1 = (fft_data *)malloc(sizeof(fft_data)); //qDebug()<<"sizeof(fft_data)"<<sizeof(fft_data);
pt1->status = EMPTY;
pt1->index = 0;
pt = pt1->samples = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * (fft_size+52));//2.45 +50
//qDebug()<<"pt1 1= creaate";
//FFTW_ESTIMATE ni barzo
//FFTW_ESTIMATE_PATIENT sredno
//FFTW_MEASURE bavi no result
//FFTW_PATIENT bavi mnogo
//FFTW_EXHAUSTIVE bavi mnogo
//org samo bavi
//pt1->plan_dsp = fftw_plan_dft_1d(fft_size, pt, pt, FFTW_FORWARD, FFTW_MEASURE);
pt1->plan_dsp = fftw_plan_dft_1d(fft_size, pt, pt, FFTW_FORWARD, FFTW_ESTIMATE_PATIENT);//1.35
//qDebug()<<"pt1 1=end";
// Create space to write samples while the first fft is in use
if (pt2)
{
fftw_destroy_plan(pt2->plan_dsp);
fftw_free(pt2->samples);
free(pt2);
}
pt2 = (fft_data *)malloc(sizeof(fft_data));
pt2->status = EMPTY;
pt2->index = 0;
pt = pt2->samples = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * (fft_size+52));//2.45 +50
//qDebug()<<"pt2 2= create";
//FFTW_ESTIMATE ni barzo
//FFTW_ESTIMATE_PATIENT sredno
//FFTW_MEASURE bavi no result
//FFTW_PATIENT bavi mnogo
//FFTW_EXHAUSTIVE bavi mnogo
//org samo bavi
//pt2->plan_dsp = fftw_plan_dft_1d(fft_size, pt, pt, FFTW_FORWARD, FFTW_MEASURE);
pt2->plan_dsp = fftw_plan_dft_1d(fft_size, pt, pt, FFTW_FORWARD, FFTW_ESTIMATE_PATIENT);//1.35
//qDebug()<<"pt2 2="<<s_vdisp_speed;
FFT1 = pt1;
FFT2 = pt2;
// Create space for the fft average and window
if (fft_avg)
free(fft_avg);
if (fft_window)
free(fft_window);
if (f_disp_v_h)
{
fft_avg = (double *) malloc(sizeof(double) * ((s_data_width)+50));////1.39 rem s_data_width/2 1.36 +20
for (i = 0; i < s_data_width; i++)//1.39 rem s_data_width/2
fft_avg[i] = 0;
//qDebug()<<"fft_avg-------------------"<<((s_data_width/2)+20);
}
else
{
fft_avg = (double *) malloc(sizeof(double) * (s_data_height+20));//1.36 +20
for (i = 0; i < s_data_height; i++)
fft_avg[i] = 0;
//qDebug()<<"fft_avg-------------------"<<s_data_height+20;
}
// same as nuttal_window but better
fft_window = (double *) malloc(sizeof(double) * (fft_size+50));//1.36 +50
for (i = 0, j = -fft_size / 2; i < fft_size; i++, j++)
{
if (0) // Hamming
fft_window[i] = 0.54 + 0.46 * cos(2.0 * M_PI * j / fft_size);
else // Hanning
fft_window[i] = 0.5 + 0.5 * cos(2.0 * M_PI * j / fft_size);
}
//qDebug()<<"Stop record_app";
}
void MsCore::SetDecBusy(bool f)
{
dec_busy = f;
}
void MsCore::FastResetSoundCardIn()
{
if (!timer_fr_sound->isActive()) timer_fr_sound->start(220);//2.47
}
void MsCore::FastResetSoundCardIn_p()// for pure sound cards
{
//1min=60, 2min=120, 15min=900 ,30min=1800, 1h=3600, 1:30h=5400, 2h=7200
unsigned int hh = QDateTime::currentDateTimeUtc().toTime_t();
if (hh < last_reset_sc_in + 1802)//1802=30:02 1800+2 2=seconds
{
//qDebug()<<"T Stop 1";
timer_fr_sound->stop();
return;
}
if (dec_busy)
{
//qDebug()<<"Decoder Busy";
return;
}
//qDebug()<<"T Stop 2";
timer_fr_sound->stop();
//qDebug()<<"Start FastReset====================================";
g_read_snd = false;//true; // stop reading
usleep(1000); //2.37 be6e 1000 1.33=no 20ms in sdr 1.34 // triabva da e mnogo pove4e otkolkoto e na loop
close_sound();
usleep(2000); //1.33=1000 1.34=2000 wait hardware to clear buffers
THvRawFilter->set_rate(fftw_sample_rate); //2.34
bool p_read_snd = true;
#if defined _WIN32_
if (!ftci) //tci
{
p_read_snd = select_device(true);
if (p_read_snd) p_read_snd = start_sound();
}
#endif
#if defined _LINUX_
if (!ftci) //tci
{
rad_open_sound();
}
#endif
record_app(); //fftw
usleep(2000); //1.33=no 1.34 wait fftw
last_reset_sc_in = hh;
g_read_snd = p_read_snd; // start reading
//qDebug()<<"End FastReset=================================="<<QDateTime::currentDateTimeUtc().toString("hh:mm:ss");
}
static int tci_read_ = 0; //2.58 0=stop 1=buff 2=read
void MsCore::SetupSettings_(QString dev_in_number, QString sample_rate, int latency, int card_buffer_polls,
int channel,bool imidiatly)
{
if (!imidiatly)
{
if ((QString)rad_sound_state.dev_capt_name == dev_in_number && in_sample_rate == sample_rate.toInt() &&
rad_sound_state.latency_millisecs == latency && rad_sound_state.data_poll_usec == card_buffer_polls &&
rad_sound_state.channel_I == channel)
return;//za da ne garmi pod windows
}
g_read_snd = false;//true; // stop reading
usleep(1000); //2.37 be6e=1000 1.33=no in sdr 20ms // 1.34
close_sound();
usleep(2000); //1.33=yes 1.34 wait hardware to clear buffers
//msk144 //jt65abc pi4 ft8 ft4 q65
/*if (s_mod_iden == 0 || s_mod_iden == 7 || s_mod_iden == 8 || s_mod_iden == 9 || s_mod_iden == 10 ||
s_mod_iden == 11 || s_mod_iden == 12 || s_mod_iden == 13 ||
s_mod_iden == 14 || s_mod_iden == 15 || s_mod_iden == 16 || s_mod_iden == 17)
{
fftw_sample_rate = (int)ORG_SAMPLE_RATE_12000;
in_sample_rate = sample_rate.toInt();
koef_resample = (int)((in_sample_rate/(int)ORG_SAMPLE_RATE_12000)-1);
}
else //if (s_mod_iden>0 && s_mod_iden<7)
{
fftw_sample_rate = (int)ORG_SAMPLE_RATE_11025;
in_sample_rate = sample_rate.toInt();
koef_resample = (int)((in_sample_rate/(int)ORG_SAMPLE_RATE_11025)-1);
}*/
if (s_mod_iden>0 && s_mod_iden<7) //2.65
{
fftw_sample_rate = (int)ORG_SAMPLE_RATE_11025;
in_sample_rate = sample_rate.toInt();
koef_resample = (int)((in_sample_rate/(int)ORG_SAMPLE_RATE_11025)-1);
}
else
{
fftw_sample_rate = (int)ORG_SAMPLE_RATE_12000;
in_sample_rate = sample_rate.toInt();
koef_resample = (int)((in_sample_rate/(int)ORG_SAMPLE_RATE_12000)-1);
}
//for pulse audio max is 512 ???
strncpy(rad_sound_state.dev_capt_name,dev_in_number.toUtf8(),127); //127 2.37 be6e SC_SIZE_L
//if ((QString)rad_sound_state.dev_capt_name==dev_in_number)
//qDebug()<<"mscore="<<(QString)rad_sound_state.dev_capt_name<<dev_in_number;
QString str_device_name = (QString)rad_sound_state.dev_capt_name;
if (str_device_name=="TCI Client Input") ftci = true;
else ftci = false;
tci_read_ = 0; //2.58
rad_sound_state.latency_millisecs = latency;//50 be6e hv 50-300
rad_sound_state.data_poll_usec = card_buffer_polls;
if (channel == 0)
{
rad_sound_state.channel_I = 0;
//rad_sound_state.channel_Q = 1;
}
else
{
rad_sound_state.channel_I = 1;
//rad_sound_state.channel_Q = 0;
}
THvRawFilter->set_rate(fftw_sample_rate);//2.34
bool p_read_snd = true;
#if defined _WIN32_
if (!ftci) //tci
{
p_read_snd = select_device(true);
if (p_read_snd) p_read_snd = start_sound();
}
#endif
#if defined _LINUX_
if (str_device_name.mid(0,7)=="pulse: ") is_pulse_a_in = true;
else is_pulse_a_in = false;
if (!ftci) //tci
{
rad_open_sound();
int c_retry = 0;
if (!is_pulse_a_in && !hCapture)
{
while (!hCapture)
{
usleep(100000);
rad_open_sound();
c_retry++;
if (c_retry>120) break;
}
}
}
#endif
record_app(); // fftw
usleep(2000); //1.33=yes 1.34 wait fftw
last_reset_sc_in = QDateTime::currentDateTimeUtc().toTime_t();// reset time for fast reset
g_read_snd = p_read_snd;//false; // start reading
//qDebug()<<"GrandReset";
}
#define TCIBUFRX_LIM 385024 //=8sec =385024
#define TCIBUFRX TCIBUFRX_LIM + 16450 //sample is 4096 max from network +=16384
static short tci_raw2_0[TCIBUFRX]; //mono
static int tci_cr2_0 = 0;
int _GetRxAudioReadTci_()
{
return tci_read_;
}
void _SetRxAudioTci_(short *raw2,int cr2) //sample is 4096
{
//qDebug()<<"tci_cr2_0"<<tci_cr2_0;
if (tci_cr2_0 < TCIBUFRX_LIM)
{
for (int i = 0; i < cr2; ++i) tci_raw2_0[i+tci_cr2_0] = raw2[i];
tci_cr2_0 += cr2;
}
tci_read_ = 2;
}
void MsCore::ReadTci()
{
tci_read_ = 1;
static short tci_raw2_1[TCIBUFRX];
int count = 0;
for (int i = 0; i < tci_cr2_0; ++i)
{
tci_raw2_1[count] = tci_raw2_0[i];
count++;
}
tci_cr2_0 = 0; // frre input buffer
ResampleAndFilter(tci_raw2_1,count); //2.57
}
void MsCore::ResampleAndFilter(short *rawm,int crawm) //2.57
{
static short dat_tt[130000]; //12000*10=120000 max=10sec 120000+12000=132000
int limit = 120000*(koef_resample+1);
if (crawm > limit) crawm = limit;
int k = 0;
for (int i = 0; i < crawm; ++i)
{
if (s_count_resample==koef_resample)
{
double data_l = THvRawFilter->band_l((double)rawm[i]);
dat_tt[k]=(short int)(data_l*s_in_level);
s_count_resample = 0;
k++;
}
else
s_count_resample++;
}
ReciveData(dat_tt,k,false);
//if (k>1024) qDebug()<<"FREEZE="<<k;
//if (k>1024) qDebug()<<k<<crawm<<limit<<TCIBUFRX_LIM<<TCIBUFRX;
//if (k>1024) printf("12KHz=%d, 48KHz=%d, limit48KHz=%d,\n",k,crawm,limit);
}
void MsCore::ReciveData(short *dat,int count,bool ffopen)
{
emit Set_Raw(dat,count,ffopen); //1.27 psk rep fopen bool true false no file open
for (int i = 0; i < count; ++i)
{
short in_dat = dat[i];
audiobuffer[count_ftt_window] = in_dat;//*fac;
if (count_ftt_window >= fft_size-1)// i < fft_size 1.29 for this -1
{
decode_fft_size_samples(audiobuffer, fft_size); // i < fft_size 1.29
//qDebug()<<"count="<<fft_size;
count_ftt_window = 0;
}
else
count_ftt_window++;
buf_samp_sm[count_rfesh_sm] = in_dat;
if (count_rfesh_sm >= 450-1)// max 500 v1.36
{
count_rfesh_sm = 0;
double sum(0);
//double val;
int smiter = 0;
for (int x = 0; x < 450; ++x)
{
double val = fabs(buf_samp_sm[x]);
sum += val;
}
sum /= 450.0;
double log0 = sqrt(sum);
if (log0<1.0) log0=1.0; //2.58
smiter = abs(int(log(log0)*20.0)); //qDebug()<<"count="<<sum<<log0<<log(log0);
emit Sed_SMeter(smiter);// zaradi bavnoto na jt65abc
}
else
count_rfesh_sm++;
}
}
//max fft_size= 24452 to 1.54
void MsCore::decode_fft_size_samples(short *data_mono, int count)
{
//inportant hv -> count==fft_size
//double sum(0);
//double val;
//int smiter = 0;
//qDebug()<<count;
//qDebug()<<SAMP_BUFFER_PRE_BUFF;
//HV VNIMANIE ako iskam s razli4ni samplerate triabva da se saobrazia s whodnite
//GRAPHIC_WIDTH, period_time_sec, sample_rate i sled towa revord_app()
static int playSilence = 0;
fft_data * ptFft;
//qDebug()<<count;
/* check for space, then put samples into the fft input array */
if (! ptWriteFft)
{ // wait for an empty fft to become available
if (FFT1 && FFT1->status == EMPTY)
{
FFT1->status = FILLING;
FFT1->index = 0;
ptWriteFft = FFT1;
}
else if (FFT2 && FFT2->status == EMPTY)
{
FFT2->status = FILLING;
FFT2->index = 0;
ptWriteFft = FFT2;
}
}
if (!playSilence && ptWriteFft)
{ // write samples to fft data array
double sum(0);
int smiter = 0;
for (int i = 0; i < count; ++i)
{
//part of smiter
if (!f_disp_v_h)
{
double val = fabs(data_mono[i]);
sum += val;
}
ptWriteFft->samples[ptWriteFft->index] = ((double)data_mono[i]*0.01);//2.46
//if (ptWriteFft->index >= fft_size-1)
//qDebug()<<"ptWriteFft->index"<<ptWriteFft->index;
if (++(ptWriteFft->index) >= fft_size)
{ // check sample count
ptWriteFft->status = READY; // ready to run fft
if (ptWriteFft == FFT1)
{ // switch to other fft
ptFft = FFT2;
}
else
{
ptFft = FFT1;
}
if (ptFft->status == EMPTY)
{ // continue writing samples
ptFft->status = FILLING;
ptFft->index = 0;
ptWriteFft = ptFft;
}
else
{ // no place to write samples
ptWriteFft = NULL;
fft_error++;
break;
}
}
}
//part of smiter
if (count==0) count=1;
sum /= count;
double log0 = sqrt(sum);
if (log0<1.0) log0=1.0;//2.58
smiter = abs(int(log(log0)*20.0));
Get_Graph(smiter);
// qDebug()<<"period_time_sec";
}
}
void MsCore::SetVDispSpeed(int speed)
{
s_vdisp_speed = (10-speed);//1.51 10 9-speeds, 6
//s_vdisp_speed = speed;
SetupSettings_((QString)rad_sound_state.dev_capt_name,QString("%1").arg(in_sample_rate),rad_sound_state.latency_millisecs,
rad_sound_state.data_poll_usec,rad_sound_state.channel_I,true);
}
void MsCore::setVDFftwStartStopFreq(int beg,int end)
{
s_freq_beg = beg;
s_freq_end = end;
}
void MsCore::Get_Graph(int smiter)
{
int i, j, k, n;
fft_data * ptFft;
double y_scale[DATA_WIDTH+50];////1.39 rem s_data_width/2 1.37 max val
double d2;
/// double *no_data = NULL;
//qDebug()<<DATA_WIDTH;
//if (!PyArg_ParseTuple (args, ""))
//return NULL;
// Look for an fft ready to run. Throw the other away if there are two.
if (FFT1 && FFT1->status == READY)
{
ptFft = FFT1;
if (FFT2 && FFT2->status == READY)
FFT2->status = EMPTY;
}
else if (FFT2 && FFT2->status == READY)
{
ptFft = FFT2;
if (FFT1 && FFT1->status == READY)
FFT1->status = EMPTY;
}
else
{ // No data yet
//Py_INCREF(Py_None);
return;
}
for (i = 0; i < fft_size; ++i) // multiply by window
ptFft->samples[i] *= fft_window[i];
//ptFft->samples[i] = ptFft->samples[i]*fft_window[i];
fftw_execute(ptFft->plan_dsp); // Calculate FFT
// Average the fft data into the graph width
//double kavg = 0.0;//2.46
if (f_disp_v_h)
{
//int s_freq_end = 2200; //2150hz
//int s_freq_beg = 200; //200hz 1.0 koef
double size_6000 = fft_size/2.0;
int beg_size = ((double)s_freq_beg*size_6000)/((double)fftw_sample_rate/2.0);
int end_size = ((double)s_freq_end*size_6000)/((double)fftw_sample_rate/2.0);
double d_koef = (double)(end_size-beg_size)/(double)((double)s_data_width);//1.39 rem s_data_width/2
bool retry = false;
for (i = 0, k = 0; k < s_data_width; k++)//1.39 rem s_data_width/2
{
int c_kk = 1;
c6:
if (!retry)//2.45
{
fft_avg[k] += cabs(ptFft->samples[i+beg_size]);
//kavg += fft_avg[k];//2.46
}
else
{
retry = false;
double p0 = cabs(ptFft->samples[i+beg_size]);
double p1 = cabs(ptFft->samples[i+beg_size+1]);
fft_avg[k] = (p0+p1)/2.0;
//kavg += fft_avg[k];//2.46
}
if ((double)i>(double)k*d_koef)// tova pri nedostig
{
retry = true;
continue;
}
i++;
if ((double)i<(double)k*d_koef)// towa kogato ima mnogo
{
c_kk++;
goto c6;
}
fft_avg[k]=(fft_avg[k]/(double)c_kk);
}
}
else
{
n = fft_size / s_data_height /2 ; //HV za positie and negative bez -> / 2
if ( n == 0 )//HV za da risuva i pod 20 seconds ina4e n = 0 stava
n=1;
for (i = 0, k = 0; k < s_data_height; ++k)
for (j = 0; j < n; ++j)
fft_avg[k] += cabs(ptFft->samples[i++]);
}
//qDebug()<<"fft_avg="<<k;
ptFft->status = EMPTY;
if (++count_fft < average_count)
{
//Py_INCREF(Py_None); // No data yet
return;
}
// We have averaged enough fft's to return the graph data
count_fft = 0;
//tuple2 = PyTuple_New(DATA_WIDTH);
i = 0;
if (f_disp_v_h)
i=(s_data_width)-1;//DATA_DSP_HEIGHT-0; //1.39 rem s_data_width/2
else
i=s_data_dsp_height-1;//DATA_DSP_HEIGHT-0;
//i=(150-46)-1;
if (f_disp_v_h)
{
//kavg /= s_data_width; //qDebug()<<kavg;//qoter avg
//if (kavg < 0.001) kavg = 0.001; // //2.46
//double avg_alcvd = 0.0;
for (k = 0; k < s_data_width; ++k)//1.39 rem s_data_width/2
{
d2 = log10(fft_avg[k] * s_scale); //d2 = log(fft_avg[k] * (s_scale))*0.5;
//avg_alcvd += fabs(d2);
if (d2 < -10)
d2 = -10;
fft_avg[k] = 0;
y_scale[i] = (50.0 * d2);
if (i>0)//1.36 i>0 pazi ot -1
i--;
}
//avg_alcvd /= (double)s_data_width;
//RefrAlcVD(avg_alcvd);
}
else
{
//for (k = FFT_CUT_LOW_FRQ; k < FFT_END_FRQ; k++/*, i--*/)//34
for (k = s_fft_cut_low_frq; k < s_fft_end_frq; ++k/*, i--*/)
{
d2 = log10(fft_avg[k] * s_scale);
if (d2 < -10)
d2 = -10;
fft_avg[k] = 0;
y_scale[i] = (50.0 * d2);// 50.0 <- max display is 501
if (i>0)//1.36 i>0 pazi ot -1
i--;
}
}
//qDebug()<<"mmmmmmmmmmmmmmmmmmmmmmmmmmm";
emit Set_Graph(y_scale, smiter);
//delete y_scale;//rem 1.37
}
void MsCore::Refresh_t()
{
if (sta_sto_flag && g_read_snd)
{
if (ftci)//tci
{
if (tci_read_ == 0)
{
tci_cr2_0 = 0;
tci_read_ = 1;
}
if (tci_read_ == 2) ReadTci();
}
else
{
#if defined _WIN32_
ReadData();
#endif
#if defined _LINUX_
alsa_read_sound();
#endif
}
}
else
tci_read_ = 0;
emit Refresh_time();
}

View File

@ -0,0 +1,299 @@
/* MSHV
*
* By Hrisimir Hristov - LZ2HV
* May be used under the terms of the GNU General Public License (GPL)
*/
#ifndef MSCORE_H
#define MSCORE_H
#include "../config.h"
//#include <QtGui>
#include <QObject>
#include <math.h> //los
//#include <stdlib.h> //abs
//#include <unistd.h>
//#include <iostream>
#include <unistd.h>//usleep x86_64
//using namespace std;
#include <QTimer>
//#include "../../../DirectX90c/include/dsound.h"
#if defined _WIN32_
#include "../Hv_Lib_DirectX90c/dsound.h"
#endif
#if defined _LINUX_
#include <alsa/asoundlib.h>
#include <pthread.h> // pthread_create, pthread_mutex_unlock
#endif
#define SC_SIZE_L 128
#define CLOSED_TEXT "The sound device is closed."
//#include <complex.h> // hv ima na dolu deklaracii / Use native C99 complex type for fftw3
#define SAMP_BUFFER_SIZE 80000 //Linux size of arrays used to capture samples
#define CLIP32 2147483647
#define CLIP16 32767
#define MAXDSBUFERTIME_W 10 //2.49 =10sec old=7 seconds buffer time
#define CHANNELS_W 2 //2 kamala
#define BITPERSAMPLE_W 16 // 16bit
// (192000 * (( CHANNELS_W * BITPERSAMPLE_W ) / 8)) * MAXDSBUFERTIME_W;
#define SAMP_BUFFER_SIZE_WIN ((96000 * (( CHANNELS_W * BITPERSAMPLE_W ) / 8)) * MAXDSBUFERTIME_W + 32) // 5376000 za 192000hz i 7 sec MAXDSBUFERTIME ->vista e vinovna
#define SAMP_BUFFER_PRE_BUFF (12000 * 15) //samplerate * seconds
#define RMS_BUF_SIZE 20 // triabwa da e po goliamo ot max rms_points v TSettingsGeoRad
//otide v config.h #define POINTS_IN1_SCAN 620//384 //i v graphdisprad.cpp saved_points_in_1scan = 384;
//vazno->POINTS_IN1_SCAN = 384 ot geocore; i time_1scan = 26.81 ot graphdisprad->se glasi to4nostta
//vazno->dannite sa ot hardware
// kolko to4ki ima w edin skan s prodalzitelnost 8.7ms na 44100HZ sample rate;
#include <complex.h> // gnu++11 c++11
#define complex _Complex
#include "../Hv_Lib_fftw/fftw3.h"
#include "../HvMsPlayer/libsound/HvRawFilter/hvrawfilter.h" //hv
//#include "msplayerhv.h"
/*
#include <QThread>
#include <QMutex>
#include <QMutexLocker>
class ThreadRefr : public QThread
{
Q_OBJECT
signals:
void refresh();
private:
//QMutex m_mutex;
void run()
{
while (1)
{
//QMutexLocker locker(&m_mutex);
msleep(5);
refresh();
//usleep(10);
}
}
};
*/
extern int _GetRxAudioReadTci_();
extern void _SetRxAudioTci_(short *,int);
class MsCore : public QObject
{
Q_OBJECT
public:
MsCore();
~MsCore();
//static void SetTxAudioTci(short *,int);
bool is_select_sound_device;
bool GetSta_Sto()
{
return sta_sto_flag;
};
void SetStr_Sto(bool);
void close_sound();
void SetupSettings(QString,int,int,int);//QString,
void SetMode(int mod_iden);
void setVDFftwStartStopFreq(int beg,int end);
void SetDecBusy(bool);
void SetVDispSpeed(int);
//void SetAdleDisplay_VD(bool);
public slots:
void ReciveData(short*, int, bool); //1.27 psk rep fopen bool true false no file open
void SetInLevel(int);
void FastResetSoundCardIn();
//void SetVDispSpeed(int);
//void SetDecBusy(bool);
signals:
void Sed_SMeter(int);
void Set_Graph(double*,int);
void Set_Raw(short*,int,bool); //1.27 psk rep fopen bool true false no file open
void Refresh_time();
private slots:
void Refresh_t();
void FastResetSoundCardIn_p();
private:
void ResampleAndFilter(short *,int);
bool ftci;//tci
void ReadTci();//tci
bool dec_busy;
QTimer *timer_fr_sound;
int s_data_dsp_height;
int s_fft_end_frq;
int s_data_width;
int s_data_height;
int s_fft_cut_low_frq;
int count_rfesh_sm;
short buf_samp_sm[500];
int s_vdisp_speed;
int s_freq_end; //2150hz
int s_freq_beg;
bool f_disp_v_h;
unsigned int last_reset_sc_in;
//void FastResetSound();
//void setPeriodTime(int);
void SetupSettings_(QString,QString,int,int,int,bool);
int s_mod_iden;
void Get_Graph(int);
void record_app();
bool sta_sto_flag;
bool g_read_snd;
void decode_fft_size_samples(short*,int);
bool draw_flag;
//double rms_point[RMS_BUF_SIZE];
//double sinh_point[RMS_BUF_SIZE];
int y_count;
int saved_sinh_val;
int compare_sinh_val;
int sinh_sleep;
int koef_sinh_sleep;
//int save_rms_points;
enum fft_status
{
EMPTY, // fft_data is currently unused
FILLING, // now writing samples to this fft
READY
}
; // ready to perform fft
typedef struct
{
fftw_complex * samples; // complex data for fft
fftw_plan plan_dsp; // fft plan for fftW
int index; // position of next fft sample
enum fft_status status; // whether the fft is busy
}
fft_data;
fft_data * FFT1, * FFT2; // data for two fft's
fft_data * ptWriteFft; // Write the current samples to this fft
double * fft_avg; // Array to average the FFT
double * fft_window; // Window for FFT data
int count_fft; // how many fft's have occurred (for average)
int fft_size; // size of fft, e.g. 1024
int average_count; // Number of FFT's to average for graph
int fft_error; // fft error count
double s_scale;
int count_ftt_window;
short audiobuffer[SAMP_BUFFER_PRE_BUFF];
int fftw_sample_rate;
int koef_resample;
int in_sample_rate;
struct sound_conf
{
char dev_capt_name[SC_SIZE_L];
char err_msg[SC_SIZE_L];
int bad_device;
unsigned int rate_min;
unsigned int rate_max;
unsigned int chan_min;
unsigned int chan_max;
//int sample_rate;
int channel_I;
int channel_Q;
int data_poll_usec;
int latency_millisecs;
char msg1[128];
int read_error;
int write_error;
int underrun_error;
int interupts;
} ;
struct sound_conf rad_sound_state;
short all_data[SAMP_BUFFER_SIZE_WIN];
short cSamples_mono[SAMP_BUFFER_SIZE_WIN/2];
//double cSamples_r[SAMP_BUFFER_SIZE_WIN/2];
#if defined _WIN32_
bool start_sound();
bool stop_sound();
bool select_device(bool immediately);//2.49
bool ReadData();
//bool ReadData_1();
DWORD CapturePosition; // capture position in the capture buffer
DWORD ReadPosition; // read position in the capture buffer
//DWORD PreviousReadPosition;
WAVEFORMATEX wf; // .wav format description structure
DSCBUFFERDESC dscbd; // DirectSoundCaptureBuffer description structure
LPDIRECTSOUNDCAPTURE lpdCapture; // Pointer to IDirectSoundCapture8 object
LPDIRECTSOUNDCAPTUREBUFFER lpdCaptureBuff; // Holds DirectSoundCaptureBuffer object
DSCBCAPS dscbcaps; // DirectSoundCapture Buffer capabilities
#endif
#if defined _LINUX_
///alsa_sound
enum
{ // Method of converting sample bytes to an int
ThreeLittle2Little, // Three little endian bytes to little endian int
ThreeLittle2Big
} // Three little endian bytes to big endian int
convert_sample_bytes;
int alsa_read_sound();
void open_alsa_capture();
snd_pcm_t *hCapture; // handle for alsa soundcard capture or NULL
//snd_pcm_t *hPlayback; // handle for alsa soundcard playback
snd_pcm_format_t check_formats(snd_pcm_t *h, snd_pcm_hw_params_t *hware);
int channel_I;
int channel_Q;
int chan_capt, chan_play;
int latency_frames; // desired latency in audio play samples
//int play_buffer_size; // Size of play buffer in samples
int sample_bytes; // Size of one channel sample in bytes, either 2 or 4
int is_little_endian;
void rad_close_sound();
void rad_open_sound();
int read_alsa();
short buffer2[SAMP_BUFFER_SIZE]; // Buffer for 2-byte samples from sound
int quisk_overrange; // count of ADC overrange (clip)
unsigned char buffer3[3 * SAMP_BUFFER_SIZE]; // Buffer for 3-byte samples from sound
int buffer4[SAMP_BUFFER_SIZE]; // Buffer for 4-byte samples from sound
int cSamples_l[SAMP_BUFFER_SIZE];
int cSamples_r[SAMP_BUFFER_SIZE];
bool is_pulse_a_in;
//void loop_read_in();
//pthread_mutex_t _e9k8_start_loop;
#endif
int s_count_resample;
///int period_time_sec;
double s_in_level;
HvRawFilter *THvRawFilter;
/*double raw_1[RAW_BUFFER_SIZE];
int raw_1_count;
double raw_2[RAW_BUFFER_SIZE];
int raw_2_count;*/
//int mute_c;
};
#endif

View File

@ -0,0 +1,232 @@
/* MSHV MsCore part of win sound in
* Copyright 2015 Hrisimir Hristov, LZ2HV
* May be used under the terms of the GNU General Public License (GPL)
*/
#include "mscore.h"
#if defined _WIN32_
//#include <QtGui>
QString ConvertToStr_tin(LPCTSTR name)
{
QString s;
for (unsigned int i=0; i<wcslen(name); ++i)
s.push_back(name[i]);
//s.append(" Микрофон 128 で簡単に作れますが"); //for test coding utf-8
return s.toUtf8();
}
static bool _infirst_ = false;
static LPGUID _inguid_;
static QString _inname_;//LPCTSTR=lpszDesc LPCTSTR=lpszDrvName=*.dll LPVOID=pContext
BOOL CALLBACK DSEnumProc_t_in(LPGUID lpGUID,LPCTSTR lpszDesc,LPCTSTR,LPVOID)
{
if (!_infirst_)
{
if (_inname_ == ConvertToStr_tin(lpszDesc))
{
_infirst_ = true;
_inguid_ = lpGUID; //qDebug()<<"Find In="<<_inname_<<_inguid_;
}
}
return true;
}
bool MsCore::ReadData()
{
// check to see if this is the first time data was requested from buffer
if ( ( CapturePosition == (DWORD)-1 ) && ( ReadPosition == (DWORD)-1 ) )
{
lpdCaptureBuff->GetCurrentPosition( &CapturePosition, &ReadPosition );
//PreviousReadPosition = ReadPosition;
//qDebug()<<"FIRST RESET lpdCaptureBuff->GetCurrentPosition"<<CapturePosition<<ReadPosition;
return false;
}
// Get former read and capture positions and acquire new ones
//DWORD PreviousCapturePosition;
//PreviousCapturePosition = CapturePosition;
DWORD PreviousReadPosition = ReadPosition;
//DWORD temp_PreviousReadPosition = ReadPosition;
//PreviousReadPosition = ReadPosition;
//if( FAILED( hr = g_pDSBCapture->GetCurrentPosition( &dwCapturePos, &dwReadPos ) ) )
// return hr;
if ( FAILED(lpdCaptureBuff->GetCurrentPosition( &CapturePosition, &ReadPosition ) ) )
{
//qDebug()<<"********* FAILED lpdCaptureBuff->GetCurrentPosition";
//ReadPosition = temp_PreviousReadPosition;
return false;
}
//lpdCaptureBuff->GetCurrentPosition( &CapturePosition, &ReadPosition );
LPVOID CBAddress1, CBAddress2;
DWORD CBLength1, CBLength2;
DWORD LockSize;
if ( ReadPosition < PreviousReadPosition )
LockSize = ( dscbd.dwBufferBytes - PreviousReadPosition ) + ReadPosition;
else
LockSize = ReadPosition - PreviousReadPosition;
if ( LockSize != 0 )
{
if ( FAILED( lpdCaptureBuff->Lock(
PreviousReadPosition, // Offset at which to start lock.
LockSize, // Size of lock.
&CBAddress1, // Gets address of first part of lock.
&CBLength1, // Gets size of first part of lock.
&CBAddress2, // Address of wraparound.
&CBLength2, // Size of wraparound.
0 ) ) ) // Flag.
return false;
memcpy((char*)all_data,CBAddress1,CBLength1);//2.56 (char*)
if (CBAddress2) // if new data wraps around the capture buffer
memcpy(((char*)all_data + CBLength1),CBAddress2,CBLength2);//2.56 (char*)
//if( CBAddress2 )
//qDebug()<<"1Lock, CBLength1, CBLength2"<<LockSize<<CBLength1<<CBLength2<<CBLength1+CBLength2;
//if ( CBAddress2 != NULL )
//qDebug()<<"2Lock, CBLength1, CBLength2"<<LockSize<<CBLength1<<CBLength2<<CBLength1+CBLength2;
if (LockSize <= 0) return false;
int count = 0; //qDebug()<<LockSize;
for (int i = 0; i < (int)LockSize/2; i+=2)
{
//double data_l = THvRawFilter->band_l((double)all_data[i+rad_sound_state.channel_I]);
//cSamples_mono[count] = (short int)data_l;
cSamples_mono[count] = all_data[i+rad_sound_state.channel_I];
count++;
}
ResampleAndFilter(cSamples_mono,count); //2.57
/*short *dat_tt = new short[count+6];
int k = 0;
for (int i = 0; i < count; ++i)
{
if (s_count_resample==koef_resample)
{
double data_l = THvRawFilter->band_l((double)cSamples_mono[i]);
dat_tt[k]=(short int)(data_l*s_in_level);
s_count_resample = 0;
k++;
}
else
s_count_resample++;
}
ReciveData(dat_tt,k,false); //1.27 psk rep fopen bool true false no file open
delete [] dat_tt;*/
if ( FAILED( lpdCaptureBuff->Unlock(
CBAddress1, // Gets address of first part of lock.
CBLength1, // Gets size of first part of lock.
CBAddress2, // Address of wraparound not needed.
CBLength2 ) ) ) // Size of wraparound not needed.
return false;
//ReciveData(dat_tt,k,false);
//delete dat_tt;
}
return true;
}
bool MsCore::stop_sound()
{
if (FAILED(lpdCaptureBuff->Stop()))
return false;
CapturePosition = (DWORD)-1; // reset capture position
ReadPosition = (DWORD)-1; // reset read position
//PreviousReadPosition = (DWORD)-1;
return true;
}
bool MsCore::start_sound()
{
if (FAILED(lpdCaptureBuff->Start(DSCBSTART_LOOPING)))
return false;
return true;
}
bool MsCore::select_device(bool immediately)
{
///return false; //for test error
//qDebug() << "--------------------------------";
static LPGUID prev_inguid = (LPGUID)-1;//2.50 protect at start no primary sound driver =(-1)
DWORD pv; // Can be any 32-bit type.
_infirst_ = false;
_inguid_ = (LPGUID)0;
_inname_ = (QString)rad_sound_state.dev_capt_name;
if ( DS_OK != DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)DSEnumProc_t_in, (VOID*)&pv))
{
//qDebug()<<"EROR DirectSoundCaptureEnumerate";
return false;
}
if (!immediately)
{
if (prev_inguid != _inguid_) //2.49 exception GUID is Changed
{
//g_read_snd = false;//true;
close_sound(); //qDebug()<<"GUID Changed Close---->";
usleep(2000);
//g_read_snd = true;//false;
}
else
{
//qDebug()<<"GUID No Changed Return";
return true;
}
} //else qDebug()<<"RESET immediately";
//prev_inguid = _inguid_;//2.50 stop
CapturePosition = (DWORD)-1; // reset capture position
ReadPosition = (DWORD)-1; // reset read position
// Set up wave format structure.
ZeroMemory( &wf, sizeof( wf ) );
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.nChannels = CHANNELS_W;
wf.wBitsPerSample = BITPERSAMPLE_W;
wf.nSamplesPerSec = in_sample_rate;//rad_sound_state.sample_rate;
wf.nBlockAlign = ( wf.nChannels * wf.wBitsPerSample ) / 8; // ( nChannels * wBitsPerSample ) / 8 bits per byte
wf.nAvgBytesPerSec = ( wf.nSamplesPerSec * wf.nBlockAlign );
//qDebug() << "wf.nAvgBytesPerSec"<<wf.nAvgBytesPerSec;
// Set up DSBUFFERDESC structure: Buffer Control Options
ZeroMemory(&dscbd, sizeof( dscbd ) );
dscbd.dwSize = sizeof( DSCBUFFERDESC );
dscbd.dwFlags = 0;
dscbd.dwBufferBytes = wf.nAvgBytesPerSec * MAXDSBUFERTIME_W; //max->3840000 buffer for 192000 ->5 second buffer
dscbd.dwReserved = 0;
dscbd.lpwfxFormat = &wf;
dscbd.dwFXCount = 0;
dscbd.lpDSCFXDesc = NULL;
//qDebug() << "dscbd.dwBufferBytes"<<dscbd.dwBufferBytes;
lpdCapture = NULL;
if (FAILED( DirectSoundCaptureCreate(_inguid_,&lpdCapture,NULL)))
{
//qDebug()<<"EROR DirectSoundCaptureCreate"; // insert error handling
return false;
}
lpdCaptureBuff = NULL;
if (FAILED(lpdCapture->CreateCaptureBuffer(&dscbd,&lpdCaptureBuff,NULL)))
{
//qDebug()<<"EROR CreateCaptureBuffer"; //here is problem if not any device ON
return false;
}
prev_inguid = _inguid_;//2.50 need to be here if setup is ok save->prev_inguid
// Set up DSBCAPS structure: Buffer Capabilities
ZeroMemory( &dscbcaps, sizeof( dscbcaps ) );
dscbcaps.dwSize = sizeof( DSCBCAPS );
// Find the maximum playback offset position
lpdCaptureBuff->GetCaps( &dscbcaps );
//qDebug()<<dscbcaps.dwBufferBytes;
return true;
}
#endif