SSB_HighSpeed_Modem/hsmodem/fifo.cpp

392 lines
8.9 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.
*
* fifo.c ... thread safe buffer for audio I/O
*
*
*/
#include "hsmodem.h"
/*
#ifdef _WIN32_
CRITICAL_SECTION io_cap_crit_sec;
CRITICAL_SECTION io_pb_crit_sec;
#define IO_CAP_LOCK EnterCriticalSection(&io_cap_crit_sec)
#define IO_PB_LOCK EnterCriticalSection(&io_pb_crit_sec)
void IO_CAP_UNLOCK()
{
if (&io_cap_crit_sec != NULL)
LeaveCriticalSection(&io_cap_crit_sec);
}
void IO_PB_UNLOCK()
{
if (&io_pb_crit_sec != NULL)
LeaveCriticalSection(&io_pb_crit_sec);
}
#endif
#ifdef _LINUX_
pthread_mutex_t io_cap_crit_sec;
pthread_mutex_t io_pb_crit_sec;
#define IO_CAP_LOCK pthread_mutex_lock(&io_cap_crit_sec)
void IO_CAP_UNLOCK() { pthread_mutex_unlock(&io_cap_crit_sec); }
#define IO_PB_LOCK pthread_mutex_lock(&io_pb_crit_sec)
void IO_PB_UNLOCK() { pthread_mutex_unlock(&io_pb_crit_sec); }
#endif
#define AUDIO_PLAYBACK_BUFLEN (48000 * 15) // space for 10 seconds of samples
#define AUDIO_CAPTURE_BUFLEN (10000) //48000)// * 10) // space for 10 seconds of samples
int io_cap_wridx = 0;
int io_cap_rdidx = 0;
float io_cap_buffer[AUDIO_CAPTURE_BUFLEN];
int io_pb_wridx = 0;
int io_pb_rdidx = 0;
float io_pb_buffer[AUDIO_PLAYBACK_BUFLEN];
void io_init_pipes()
{
#ifdef _WIN32_
if (&io_cap_crit_sec != NULL) DeleteCriticalSection(&io_cap_crit_sec);
InitializeCriticalSection(&io_cap_crit_sec);
if (&io_pb_crit_sec != NULL) DeleteCriticalSection(&io_pb_crit_sec);
InitializeCriticalSection(&io_pb_crit_sec);
io_clear_audio_fifos();
#endif
io_voice_init_pipes();
rtty_init_pipes();
}
// write one sample into the fifo
// overwrite old data if the fifo is full
void io_cap_write_fifo(float sample)
{
if (((io_cap_wridx + 1) % AUDIO_CAPTURE_BUFLEN) == io_cap_rdidx)
{
//printf("cap fifo full\n");
return;
}
IO_CAP_LOCK;
io_cap_buffer[io_cap_wridx] = sample;
if (++io_cap_wridx >= AUDIO_CAPTURE_BUFLEN) io_cap_wridx = 0;
IO_CAP_UNLOCK();
}
int io_cap_read_fifo(float* data)
{
IO_CAP_LOCK;
if (io_cap_rdidx == io_cap_wridx)
{
// Fifo empty, no data available
IO_CAP_UNLOCK();
return 0;
}
*data = io_cap_buffer[io_cap_rdidx];
if (++io_cap_rdidx >= AUDIO_CAPTURE_BUFLEN) io_cap_rdidx = 0;
IO_CAP_UNLOCK();
return 1;
}
void io_cap_write_fifo_clear()
{
io_cap_wridx = io_cap_rdidx = 0;
}
int io_cap_fifo_freespace()
{
int freebuf = 0;
IO_CAP_LOCK;
int elemInFifo = (io_cap_wridx + AUDIO_CAPTURE_BUFLEN - io_cap_rdidx) % AUDIO_CAPTURE_BUFLEN;
freebuf = AUDIO_CAPTURE_BUFLEN - elemInFifo;
IO_CAP_UNLOCK();
return freebuf;
}
int io_cap_fifo_usedPercent()
{
int fs = io_cap_fifo_freespace();
int used = AUDIO_CAPTURE_BUFLEN - fs;
used = (used * 100) / AUDIO_CAPTURE_BUFLEN;
return used;
}
void io_pb_write_fifo(float sample)
{
IO_PB_LOCK;
// check if there is free space in fifo
if (io_pb_fifo_freespace(1) == 0)
{
IO_PB_UNLOCK();
printf("************* pb fifo full\n");
return;
}
io_pb_buffer[io_pb_wridx] = sample;
if (++io_pb_wridx >= AUDIO_PLAYBACK_BUFLEN) io_pb_wridx = 0;
IO_PB_UNLOCK();
//printf("write: pbw:%d pbr:%d\n",io_pb_wridx,io_pb_rdidx);
}
void io_pb_write_fifo_clear()
{
io_pb_wridx = io_pb_rdidx = 0;
}
int io_pb_fifo_usedBlocks()
{
int fs = io_pb_fifo_freespace(0);
int used = AUDIO_PLAYBACK_BUFLEN - fs;
used /= (txinterpolfactor * UDPBLOCKLEN * 8 / bitsPerSymbol);
return used;
}
int io_pb_fifo_freespace(int nolock)
{
int freebuf = 0;
if (nolock == 0) IO_PB_LOCK;
int elemInFifo = (io_pb_wridx + AUDIO_PLAYBACK_BUFLEN - io_pb_rdidx) % AUDIO_PLAYBACK_BUFLEN;
freebuf = AUDIO_PLAYBACK_BUFLEN - elemInFifo;
if (nolock == 0) IO_PB_UNLOCK();
//printf("fifolen:%d check: pbw:%d pbr:%d freebuf:%d\n",AUDIO_PLAYBACK_BUFLEN,io_pb_wridx,io_pb_rdidx,freebuf);
return freebuf;
}
int io_pb_fifo_usedspace()
{
IO_PB_LOCK;
int elemInFifo = (io_pb_wridx + AUDIO_PLAYBACK_BUFLEN - io_pb_rdidx) % AUDIO_PLAYBACK_BUFLEN;
IO_PB_UNLOCK();
return elemInFifo;
}
// read num elements
// if num elems not avail, return all what fifo has stored
int io_pb_read_fifo_num(float* data, int num)
{
IO_PB_LOCK;
int elemInFifo = (io_pb_wridx + AUDIO_PLAYBACK_BUFLEN - io_pb_rdidx) % AUDIO_PLAYBACK_BUFLEN;
if (elemInFifo == 0)
{
// Fifo empty, no data available
//printf("only %d elements available\n", elemInFifo);
IO_PB_UNLOCK();
return 0;
}
if (num > elemInFifo)
num = elemInFifo;
for (int i = 0; i < num; i++)
{
*data++ = io_pb_buffer[io_pb_rdidx];
if (++io_pb_rdidx >= AUDIO_PLAYBACK_BUFLEN) io_pb_rdidx = 0;
}
IO_PB_UNLOCK();
return num;
}
void io_clear_audio_fifos()
{
io_pb_write_fifo_clear();
io_cap_write_fifo_clear();
}
*/
// ================== RTTY FIFO ===================
void clear_rtty_fifos();
#ifdef _WIN32_
CRITICAL_SECTION rtty_tx_crit_sec;
CRITICAL_SECTION rtty_rx_crit_sec;
#define RTTY_TX_LOCK EnterCriticalSection(&rtty_tx_crit_sec)
#define RTTY_RX_LOCK EnterCriticalSection(&rtty_rx_crit_sec)
void RTTY_TX_UNLOCK()
{
if (&rtty_tx_crit_sec != NULL)
LeaveCriticalSection(&rtty_tx_crit_sec);
}
void RTTY_RX_UNLOCK()
{
if (&rtty_rx_crit_sec != NULL)
LeaveCriticalSection(&rtty_rx_crit_sec);
}
#endif
#ifdef _LINUX_
pthread_mutex_t rtty_tx_crit_sec;
pthread_mutex_t rtty_rx_crit_sec;
#define RTTY_TX_LOCK pthread_mutex_lock(&rtty_tx_crit_sec)
void RTTY_TX_UNLOCK() { pthread_mutex_unlock(&rtty_tx_crit_sec); }
#define RTTY_RX_LOCK pthread_mutex_lock(&rtty_rx_crit_sec)
void RTTY_RX_UNLOCK() { pthread_mutex_unlock(&rtty_rx_crit_sec); }
#endif
void rtty_init_pipes()
{
#ifdef _WIN32_
static int f = 1;
if (f)
{
f = 0;
if (&rtty_tx_crit_sec != NULL) DeleteCriticalSection(&rtty_tx_crit_sec);
InitializeCriticalSection(&rtty_tx_crit_sec);
if (&rtty_rx_crit_sec != NULL) DeleteCriticalSection(&rtty_rx_crit_sec);
InitializeCriticalSection(&rtty_rx_crit_sec);
}
#endif
clear_rtty_fifos();
}
#define RTTY_FIFOLEN 200
int rtty_tx_wridx = 0;
int rtty_tx_rdidx = 0;
char rtty_tx_buffer[RTTY_FIFOLEN];
int rtty_rx_wridx = 0;
int rtty_rx_rdidx = 0;
char rtty_rx_buffer[RTTY_FIFOLEN];
// TX char from GUI to RTTY TX thread
void clear_rtty_fifos()
{
rtty_tx_wridx = rtty_tx_rdidx = 0;
rtty_rx_wridx = rtty_rx_rdidx = 0;
}
int rtty_tx_fifo_freespace()
{
int elemInFifo = (rtty_tx_wridx + RTTY_FIFOLEN - rtty_tx_rdidx) % RTTY_FIFOLEN;
return RTTY_FIFOLEN - elemInFifo;
}
void clear_rtty_txfifo()
{
RTTY_TX_LOCK;
rtty_tx_wridx = rtty_tx_rdidx = 0;
RTTY_TX_UNLOCK();
}
void rtty_tx_write_fifo(char c)
{
RTTY_TX_LOCK;
// check if there is free space in fifo
if (rtty_tx_fifo_freespace() == 0)
{
RTTY_TX_UNLOCK();
return;
}
rtty_tx_buffer[rtty_tx_wridx] = c;
if (++rtty_tx_wridx >= RTTY_FIFOLEN) rtty_tx_wridx = 0;
RTTY_TX_UNLOCK();
}
int rtty_tx_read_fifo(char *pc)
{
RTTY_TX_LOCK;
if (rtty_tx_rdidx == rtty_tx_wridx)
{
// Fifo empty, no data available
RTTY_TX_UNLOCK();
return 0;
}
*pc = rtty_tx_buffer[rtty_tx_rdidx];
if (++rtty_tx_rdidx >= RTTY_FIFOLEN) rtty_tx_rdidx = 0;
RTTY_TX_UNLOCK();
return 1;
}
int rtty_rx_fifo_freespace()
{
int elemInFifo = (rtty_rx_wridx + RTTY_FIFOLEN - rtty_rx_rdidx) % RTTY_FIFOLEN;
return RTTY_FIFOLEN - elemInFifo;
}
void rtty_rx_write_fifo(char c)
{
RTTY_RX_LOCK;
// check if there is free space in fifo
if (rtty_rx_fifo_freespace() == 0)
{
RTTY_RX_UNLOCK();
return;
}
rtty_rx_buffer[rtty_rx_wridx] = c;
if (++rtty_rx_wridx >= RTTY_FIFOLEN) rtty_rx_wridx = 0;
RTTY_RX_UNLOCK();
}
int rtty_rx_read_fifo(char* pc)
{
RTTY_RX_LOCK;
if (rtty_rx_rdidx == rtty_rx_wridx)
{
// Fifo empty, no data available
RTTY_RX_UNLOCK();
return 0;
}
*pc = rtty_rx_buffer[rtty_rx_rdidx];
if (++rtty_rx_rdidx >= RTTY_FIFOLEN) rtty_rx_rdidx = 0;
RTTY_RX_UNLOCK();
return 1;
}