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:
Andreas Eversberg 2016-06-17 07:28:45 +02:00
parent 4e0e13cb2d
commit 7d5d3da8d3
9 changed files with 223 additions and 101 deletions

View File

@ -21,5 +21,6 @@ libcommon_a_SOURCES = \
../common/emphasis.c \
../common/compander.c \
../common/sender.c \
../common/display_wave.c \
../common/main_common.c

View File

@ -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. */

View File

@ -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);

99
src/common/display_wave.c Normal file
View File

@ -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;
}

12
src/common/display_wave.h Normal file
View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);