Add function to display wave form from input/loop
Use 'w' to toggle display. Move terminal input processing and main loop to main_common.c
This commit is contained in:
parent
4e0e13cb2d
commit
7d5d3da8d3
|
@ -21,5 +21,6 @@ libcommon_a_SOURCES = \
|
|||
../common/emphasis.c \
|
||||
../common/compander.c \
|
||||
../common/sender.c \
|
||||
../common/display_wave.c \
|
||||
../common/main_common.c
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <termios.h>
|
||||
#include "../common/debug.h"
|
||||
#include "../common/sender.h"
|
||||
#include "cause.h"
|
||||
|
@ -331,25 +330,13 @@ static void get_process_patterns(process_t *process, int16_t *samples, int lengt
|
|||
process->audio_pos = pos;
|
||||
}
|
||||
|
||||
static struct termios term_orig;
|
||||
|
||||
int call_init(const char *station_id, const char *sounddev, int samplerate, int latency, int dial_digits, int loopback)
|
||||
{
|
||||
struct termios term;
|
||||
int rc = 0;
|
||||
|
||||
if (use_mncc_sock)
|
||||
return 0;
|
||||
|
||||
if (!loopback) {
|
||||
tcgetattr(0, &term_orig);
|
||||
term = term_orig;
|
||||
term.c_lflag &= ~(ISIG|ICANON|ECHO);
|
||||
term.c_cc[VMIN]=1;
|
||||
term.c_cc[VTIME]=2;
|
||||
tcsetattr(0, TCSANOW, &term);
|
||||
}
|
||||
|
||||
memset(&call, 0, sizeof(call));
|
||||
strncpy(call.station_id, station_id, sizeof(call.station_id) - 1);
|
||||
call.latspl = latency * samplerate / 1000;
|
||||
|
@ -391,8 +378,6 @@ void call_cleanup(void)
|
|||
{
|
||||
if (use_mncc_sock)
|
||||
return;
|
||||
if (!call.loopback)
|
||||
tcsetattr(0, TCSANOW, &term_orig);
|
||||
|
||||
/* close sound devoice */
|
||||
if (call.sound)
|
||||
|
@ -405,33 +390,8 @@ void call_cleanup(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int get_char()
|
||||
static void process_ui(int c)
|
||||
{
|
||||
struct timeval tv = {0, 0};
|
||||
fd_set fds;
|
||||
char c = 0;
|
||||
int __attribute__((__unused__)) rc;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(0, &fds);
|
||||
select(0+1, &fds, NULL, NULL, &tv);
|
||||
if (FD_ISSET(0, &fds)) {
|
||||
rc = read(0, &c, 1);
|
||||
return c;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int process_ui(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = get_char();
|
||||
|
||||
/* break */
|
||||
if (c == 3)
|
||||
return 1;
|
||||
|
||||
switch (call.state) {
|
||||
case CALL_IDLE:
|
||||
if (c > 0) {
|
||||
|
@ -493,26 +453,22 @@ dial_after_hangup:
|
|||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get keys from keyboad to control call via console
|
||||
* returns 1 on exit (ctrl+c) */
|
||||
int process_call(void)
|
||||
void process_call(int c)
|
||||
{
|
||||
if (use_mncc_sock) {
|
||||
mncc_handle();
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!call.loopback) {
|
||||
if (process_ui())
|
||||
return 1;
|
||||
}
|
||||
if (!call.loopback)
|
||||
process_ui(c);
|
||||
|
||||
if (!call.sound)
|
||||
return 0;
|
||||
return;
|
||||
/* handle audio, if sound device is used */
|
||||
|
||||
int16_t samples[call.latspl];
|
||||
|
@ -524,7 +480,7 @@ int process_call(void)
|
|||
PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count);
|
||||
if (count == -EPIPE)
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
if (count < call.latspl) {
|
||||
int16_t up[count + 10];
|
||||
|
@ -552,7 +508,7 @@ int process_call(void)
|
|||
PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to sound device (rc = %d)\n", rc);
|
||||
if (rc == -EPIPE)
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
count = sound_read(call.sound, samples, samples, call.latspl);
|
||||
|
@ -560,7 +516,7 @@ int process_call(void)
|
|||
PDEBUG(DSENDER, DEBUG_ERROR, "Failed to read from sound device (rc = %d)!\n", count);
|
||||
if (count == -EPIPE)
|
||||
PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
if (count) {
|
||||
int16_t down[count]; /* more than enough */
|
||||
|
@ -570,8 +526,6 @@ int process_call(void)
|
|||
count = samplerate_downsample(&call.srstate, samples, count, down);
|
||||
call_rx_audio(call.callref, down, count);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Setup is received from transceiver. */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
int call_init(const char *station_id, const char *sounddev, int samplerate, int latency, int dial_digits, int loopback);
|
||||
void call_cleanup(void);
|
||||
int process_call(void);
|
||||
void process_call(int c);
|
||||
|
||||
/* received messages */
|
||||
int call_in_setup(int callref, const char *callerid, const char *dialing);
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/* display wave form functions
|
||||
*
|
||||
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "sender.h"
|
||||
|
||||
#define DISPLAY_INTERVAL 0.04
|
||||
|
||||
#define WIDTH 80
|
||||
#define HEIGHT 10
|
||||
|
||||
static char screen[HEIGHT][WIDTH+1];
|
||||
static int wave_on = 0;
|
||||
|
||||
void display_wave_init(sender_t *sender, int samplerate)
|
||||
{
|
||||
dispwav_t *disp = &sender->dispwav;
|
||||
|
||||
memset(disp, 0, sizeof(*disp));
|
||||
disp->interval_max = (double)samplerate * DISPLAY_INTERVAL + 0.5;
|
||||
}
|
||||
|
||||
void display_wave_on(int on)
|
||||
{
|
||||
int j;
|
||||
|
||||
if (on < 0)
|
||||
wave_on = 1 - wave_on;
|
||||
else
|
||||
wave_on = on;
|
||||
|
||||
memset(&screen, ' ', sizeof(screen));
|
||||
printf("\0337\033[H");
|
||||
for (j = 0; j < HEIGHT; j++) {
|
||||
screen[j][WIDTH] = '\0';
|
||||
puts(screen[j]);
|
||||
}
|
||||
printf("\0338"); fflush(stdout);
|
||||
}
|
||||
|
||||
void display_wave(sender_t *sender, int16_t *samples, int length)
|
||||
{
|
||||
dispwav_t *disp = &sender->dispwav;
|
||||
int pos, max;
|
||||
int16_t *buffer;
|
||||
int i, j, y;
|
||||
|
||||
if (!wave_on)
|
||||
return;
|
||||
|
||||
pos = disp->interval_pos;
|
||||
max = disp->interval_max;
|
||||
buffer = disp->buffer;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (pos >= WIDTH) {
|
||||
if (++pos == max)
|
||||
pos = 0;
|
||||
continue;
|
||||
}
|
||||
buffer[pos++] = samples[i];
|
||||
if (pos == WIDTH) {
|
||||
memset(&screen, ' ', sizeof(screen));
|
||||
for (j = 0; j < WIDTH; j++) {
|
||||
/* must divide by 65536, because we may never reach HEIGHT*2! */
|
||||
y = (32767 - (int)buffer[j]) * HEIGHT * 2 / 65536;
|
||||
screen[y >> 1][j] = (y & 1) ? '_' : '-';
|
||||
}
|
||||
printf("\0337\033[H");
|
||||
for (j = 0; j < HEIGHT; j++) {
|
||||
screen[j][WIDTH] = '\0';
|
||||
puts(screen[j]);
|
||||
}
|
||||
printf("\0338"); fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
disp->interval_pos = pos;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
typedef struct sender sender_t;
|
||||
|
||||
typedef struct display_wave {
|
||||
int interval_pos;
|
||||
int interval_max;
|
||||
int16_t buffer[256];
|
||||
} dispwav_t;
|
||||
|
||||
void display_wave_init(sender_t *sender, int samplerate);
|
||||
void display_wave_on(int on);
|
||||
void display_wave(sender_t *sender, int16_t *samples, int length);
|
||||
|
|
@ -35,3 +35,6 @@ void opt_switch_common(int c, char *arg0, int *skip_args);
|
|||
|
||||
extern int quit;
|
||||
void sighandler(int sigset);
|
||||
|
||||
void main_loop(int *quit, int latency);
|
||||
|
||||
|
|
|
@ -23,10 +23,14 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <termios.h>
|
||||
#include "main.h"
|
||||
#include "debug.h"
|
||||
#include "../common/sender.h"
|
||||
#include "sender.h"
|
||||
#include "timer.h"
|
||||
#include "call.h"
|
||||
|
||||
/* common settings */
|
||||
int num_kanal = 0;
|
||||
|
@ -241,3 +245,83 @@ void sighandler(int sigset)
|
|||
quit = 1;
|
||||
}
|
||||
|
||||
static int get_char()
|
||||
{
|
||||
struct timeval tv = {0, 0};
|
||||
fd_set fds;
|
||||
char c = 0;
|
||||
int __attribute__((__unused__)) rc;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(0, &fds);
|
||||
select(0+1, &fds, NULL, NULL, &tv);
|
||||
if (FD_ISSET(0, &fds)) {
|
||||
rc = read(0, &c, 1);
|
||||
return c;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Loop through all transceiver instances of one network. */
|
||||
void main_loop(int *quit, int latency)
|
||||
{
|
||||
int latspl;
|
||||
sender_t *sender;
|
||||
double last_time = 0, now;
|
||||
struct termios term, term_orig;
|
||||
int c;
|
||||
|
||||
/* prepare terminal */
|
||||
tcgetattr(0, &term_orig);
|
||||
term = term_orig;
|
||||
term.c_lflag &= ~(ISIG|ICANON|ECHO);
|
||||
term.c_cc[VMIN]=1;
|
||||
term.c_cc[VTIME]=2;
|
||||
tcsetattr(0, TCSANOW, &term);
|
||||
|
||||
while(!(*quit)) {
|
||||
/* process sound of all transceivers */
|
||||
for (sender = sender_head; sender; sender = sender->next) {
|
||||
/* do not process audio for an audio slave, since it is done by audio master */
|
||||
if (sender->master) /* if master is set, we are an audio slave */
|
||||
continue;
|
||||
latspl = sender->samplerate * latency / 1000;
|
||||
process_sender_audio(sender, quit, latspl);
|
||||
}
|
||||
|
||||
/* process timers */
|
||||
process_timer();
|
||||
|
||||
/* process audio for mncc call instances */
|
||||
now = get_time();
|
||||
if (now - last_time >= 0.1)
|
||||
last_time = now;
|
||||
if (now - last_time >= 0.020) {
|
||||
last_time += 0.020;
|
||||
/* call clock every 20ms */
|
||||
call_mncc_clock();
|
||||
}
|
||||
|
||||
c = get_char();
|
||||
switch (c) {
|
||||
case 3:
|
||||
/* quit */
|
||||
*quit = 1;
|
||||
break;
|
||||
case 'w':
|
||||
/* toggle display */
|
||||
display_wave_on(-1);
|
||||
break;
|
||||
default:
|
||||
/* process audio of built-in call control */
|
||||
process_call(c);
|
||||
}
|
||||
|
||||
/* sleep a while */
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
/* reset terminal */
|
||||
tcsetattr(0, TCSANOW, &term_orig);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,13 +23,10 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
#include "sender.h"
|
||||
#include "timer.h"
|
||||
#include "call.h"
|
||||
|
||||
sender_t *sender_head = NULL;
|
||||
static sender_t **sender_tailp = &sender_head;
|
||||
|
@ -138,6 +135,9 @@ int sender_create(sender_t *sender, int kanal, const char *sounddev, int sampler
|
|||
*sender_tailp = sender;
|
||||
sender_tailp = &sender->next;
|
||||
|
||||
if (sender == sender_head)
|
||||
display_wave_init(sender, samplerate);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
sender_destroy(sender);
|
||||
|
@ -209,7 +209,7 @@ static void gain_samples(int16_t *samples, int length, double gain)
|
|||
}
|
||||
|
||||
/* Handle audio streaming of one transceiver. */
|
||||
static void process_sender_audio(sender_t *sender, int *quit, int latspl)
|
||||
void process_sender_audio(sender_t *sender, int *quit, int latspl)
|
||||
{
|
||||
sender_t *slave = sender->slave;
|
||||
int16_t samples[latspl], pilot[latspl], slave_samples[latspl];
|
||||
|
@ -245,6 +245,8 @@ cant_recover:
|
|||
#ifndef WAVE_WRITE_TX
|
||||
if (sender->wave_rec.fp)
|
||||
wave_write(&sender->wave_rec, samples, count);
|
||||
if (sender == sender_head)
|
||||
display_wave(sender, samples, count);
|
||||
sender_receive(sender, samples, count);
|
||||
#endif
|
||||
}
|
||||
|
@ -362,6 +364,8 @@ cant_recover:
|
|||
if (sender->wave_rec.fp)
|
||||
wave_write(&sender->wave_rec, samples, count);
|
||||
#endif
|
||||
if (sender == sender_head)
|
||||
display_wave(sender, samples, count);
|
||||
sender_receive(sender, samples, count);
|
||||
}
|
||||
if (sender->loopback == 3)
|
||||
|
@ -387,42 +391,3 @@ cant_recover:
|
|||
}
|
||||
}
|
||||
|
||||
/* Loop through all transceiver instances of one network. */
|
||||
void main_loop(int *quit, int latency)
|
||||
{
|
||||
int latspl;
|
||||
sender_t *sender;
|
||||
double last_time = 0, now;
|
||||
|
||||
while(!(*quit)) {
|
||||
/* process sound of all transceivers */
|
||||
for (sender = sender_head; sender; sender = sender->next) {
|
||||
/* do not process audio for an audio slave, since it is done by audio master */
|
||||
if (sender->master) /* if master is set, we are an audio slave */
|
||||
continue;
|
||||
latspl = sender->samplerate * latency / 1000;
|
||||
process_sender_audio(sender, quit, latspl);
|
||||
}
|
||||
|
||||
/* process timers */
|
||||
process_timer();
|
||||
|
||||
/* process audio for mncc call instances */
|
||||
now = get_time();
|
||||
if (now - last_time >= 0.1)
|
||||
last_time = now;
|
||||
if (now - last_time >= 0.020) {
|
||||
last_time += 0.020;
|
||||
/* call clock every 20ms */
|
||||
call_mncc_clock();
|
||||
}
|
||||
|
||||
/* process audio of built-in call control */
|
||||
if (process_call())
|
||||
break;
|
||||
|
||||
/* sleep a while */
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "jitter.h"
|
||||
#include "loss.h"
|
||||
#include "emphasis.h"
|
||||
#include "display_wave.h"
|
||||
|
||||
#define MAX_SENDER 16
|
||||
|
||||
|
@ -53,6 +54,9 @@ typedef struct sender {
|
|||
int pilot_on; /* 1 or 0 for on or off */
|
||||
double pilotton_phaseshift; /* phase to shift every sample */
|
||||
double pilotton_phase; /* current phase */
|
||||
|
||||
/* display wave */
|
||||
dispwav_t dispwav; /* display wave form */
|
||||
} sender_t;
|
||||
|
||||
/* list of all senders */
|
||||
|
@ -61,7 +65,7 @@ extern int cant_recover;
|
|||
|
||||
int sender_create(sender_t *sender, int kanal, const char *sounddev, int samplerate, int cross_channels, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_wave, const char *read_wave, int loopback, double loss_volume, int use_pilot_signal);
|
||||
void sender_destroy(sender_t *sender);
|
||||
void process_sender_audio(sender_t *sender, int *quit, int latspl);
|
||||
void sender_send(sender_t *sender, int16_t *samples, int count);
|
||||
void sender_receive(sender_t *sender, int16_t *samples, int count);
|
||||
void main_loop(int *quit, int latency);
|
||||
|
||||
|
|
Loading…
Reference in New Issue