SSB_HighSpeed_Modem/hsmodem/announcement.cpp

246 lines
6.7 KiB
C++
Executable File

/*
* 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.
*
* announcement.c ... sends the *.pcm files to the playback device
*
*
*/
#include "hsmodem.h"
const int h_len = 57;
float h[h_len];
firfilt_crcf qfilt = NULL;
float ratio;
msresamp_crcf anndecim = NULL;
void create_a()
{
close_a();
// audio filter to reduce Audio BW for the 2k7 SSB channel
float fc = 0.055f; // cut off freq. normalized to 48000 (= 1.0)
liquid_firdes_kaiser(h_len, fc, 60.0f, 0.0f, h);
qfilt = firfilt_crcf_create(h, h_len);
// create arbitrary pre decimator
// if Audio SR is 48000 but caprate is 44100
ratio = (float)((float)caprate / 48000.0);
#ifdef _WIN32_
/*
* only Windows needs this special resampling ratio
* maybe it has to do with the VAC, I don't know why we have
* to resample twice 48k -> 44.1k
* maybe this will not work on another PC
*/
/*
if(caprate == 44100)
ratio = (float)(40526.0f / 48000.0);
else
ratio = (float)(44100.0f / 48000.0);
*/
if (caprate == 48000)
ratio = (float)(48000.0f / 44100.0);
else
ratio = 1.0f;
#endif
anndecim = msresamp_crcf_create(ratio, 40.0f);
}
void close_a()
{
if(qfilt) firfilt_crcf_destroy(qfilt);
qfilt = NULL;
if (anndecim) msresamp_crcf_destroy(anndecim);
anndecim = NULL;
}
float lowpass(float f)
{
if (qfilt == NULL)
{
printf("low pass filter not initialized\n");
return f;
}
liquid_float_complex inp, outp;
inp.real = f;
inp.imag = 0;
firfilt_crcf_push(qfilt, inp); // push input sample
firfilt_crcf_execute(qfilt, &outp); // compute output
return outp.real;
}
int measureLevel(char* fn)
{
int max = 0;
FILE* fp = fopen(fn, "rb");
if (fp)
{
int len = 0;
int16_t v;
while ((len = fread(&v, sizeof(int16_t), 1, fp)))
{
if (v > max) max = v;
}
fclose(fp);
}
return max;
}
// destination: 1=transceiver, 2=loudspeaker, 3=both
void playAudioPCM(char* fn, int destination)
{
int len;
int16_t d[100];
printf("play:%s, caprate:%d\n", fn,caprate);
int max = measureLevel(fn);
float ampl = 32767.0f / (float)max;
//printf("max:%d ampl:%f\n", max, ampl);
FILE* fp = fopen(fn, "rb");
const float ann_volume = 0.1f; // volume reduction for announcement
if (fp)
{
while ((len = fread(d, sizeof(int16_t), 100, fp)))
{
for (int i = 0; i < len; i++)
{
float f = (float)d[i]; // 16-bit values
f /= 32768; // float values 0..1
f *= ampl; // normalize volume
f *= ann_volume; // reduce volume
// local playback at 48k, no filtering, no interpolation
if ((destination & 2) == 2)
{
int to = 4000;
int res;
while ((res = io_fifo_usedspace(voice_pbidx)) > 10000)
{
if (--to == 0)
{
printf("timed out waiting for LS fifo. Res:%d\n",res);
fclose(fp);
return;
}
sleep_ms(1);
}
kmaudio_playsamples(voice_pbidx, &f, 1, lsvol);
}
// resample if required (PCM files are always 48000)
unsigned int num_written = 1;
liquid_float_complex out[10];
out[0].real = f; // value, if no resampling
#ifdef _LINUX_
if (caprate == 44100)
#endif
{
liquid_float_complex in;
in.real = f;
in.imag = 0;
msresamp_crcf_execute(anndecim, &in, 1, out, &num_written);
}
for (unsigned int n = 0; n < num_written; n++)
{
f = out[n].real;
f = lowpass(f);
if ((destination & 1) == 1)
{
int to = 4000;
while (io_fifo_usedspace(io_pbidx) > 10000)
{
if (--to == 0)
{
printf("timed out waiting for PB fifo\n");
fclose(fp);
return;
}
sleep_ms(1);
}
kmaudio_playsamples(io_pbidx, &f, 1, pbvol);
}
}
}
if (len != 100) break;
}
fclose(fp);
printf("finished playing audio file\n");
}
else
printf("audio file not found\n");
}
int ann_running = 0;
int transmissions = 10000;
void sendAnnouncement()
{
if (announcement == 0) return;
if (++transmissions >= announcement)
{
create_a();
ann_running = 1;
transmissions = 0;
if (sendIntro == 1)
{
char fn[500];
snprintf(fn, 499, "%s/oscardata/intro/intro.pcm", homepath);
fn[499] = 0;
playAudioPCM(fn, 1);
}
playAudioPCM("audio/amsat.pcm",1);
if (bitsPerSymbol == 1) playAudioPCM("audio/bpsk.pcm",1);
else if (bitsPerSymbol == 2) playAudioPCM("audio/qpsk.pcm",1);
else playAudioPCM("audio/psk8.pcm",1);
char s[100];
sprintf(s,"audio/%d.pcm", linespeed);
playAudioPCM(s,1);
playAudioPCM("audio/kbps.pcm",1);
ann_running = 0;
close_a();
}
}
void playIntro()
{
char fn[500];
snprintf(fn, 499, "%s/oscardata/intro/intro.pcm", homepath);
fn[499] = 0;
io_fifo_clear(voice_pbidx);
io_fifo_clear(voice_capidx);
create_a();
playAudioPCM(fn, 3);
close_a();
}