From 97a7e35d60a0cf1fb2ac340c3607dbcbdcf9b624 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 13 Jan 2017 07:31:15 +0100 Subject: Wave recording and playback now uses multi channels --- src/common/main_common.c | 42 ++++++++++++++++++++---- src/common/sdr.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++- src/common/sdr.h | 2 +- src/common/sender.c | 64 ++++++++++++++++++++----------------- src/common/sender.h | 3 ++ src/common/wave.c | 62 ++++++++++++++++++++++-------------- src/common/wave.h | 10 +++--- 7 files changed, 200 insertions(+), 66 deletions(-) diff --git a/src/common/main_common.c b/src/common/main_common.c index 399a6eb..48e3eb4 100644 --- a/src/common/main_common.c +++ b/src/common/main_common.c @@ -60,7 +60,9 @@ const char *write_tx_wave = NULL; const char *read_rx_wave = NULL; static const char *sdr_args = ""; double sdr_rx_gain = 0, sdr_tx_gain = 0; - +const char *write_iq_rx_wave = NULL; +const char *write_iq_tx_wave = NULL; +const char *read_iq_rx_wave = NULL; void print_help_common(const char *arg0, const char *ext_usage) { printf("Usage: %s -k %s[options] [station-id]\n", arg0, ext_usage); @@ -111,18 +113,25 @@ void print_help_common(const char *arg0, const char *ext_usage) printf(" -r --realtime \n"); printf(" Set prio: 0 to diable, 99 for maximum (default = %d)\n", rt_prio); printf(" --write-rx-wave \n"); - printf(" Write received audio to given wav audio file.\n"); + printf(" Write received audio to given wave file.\n"); printf(" --write-tx-wave \n"); - printf(" Write transmitted audio to given wav audio file.\n"); + printf(" Write transmitted audio to given wave file.\n"); printf(" --read-rx-wave \n"); - printf(" Replace received audio by given wav audio file.\n"); + printf(" Replace received audio by given wave file.\n"); #ifdef HAVE_SDR + printf("\nSDR options:\n"); printf(" --sdr-args \n"); printf(" Optional SDR device arguments\n"); printf(" --sdr-rx-gain \n"); printf(" SDR device's RX gain in dB (default = %.1f)\n", sdr_rx_gain); printf(" --sdr-tx-gain \n"); printf(" SDR device's TX gain in dB (default = %.1f)\n", sdr_tx_gain); + printf(" --write-iq-rx-wave \n"); + printf(" Write received IQ data to given wave file.\n"); + printf(" --write-iq-tx-wave \n"); + printf(" Write transmitted IQ data to given wave file.\n"); + printf(" --read-iq-rx-wave \n"); + printf(" Replace received IQ data by given wave file.\n"); #endif } @@ -138,9 +147,13 @@ void print_hotkeys_common(void) #define OPT_WRITE_RX_WAVE 1001 #define OPT_WRITE_TX_WAVE 1002 #define OPT_READ_RX_WAVE 1003 -#define OPT_SDR_ARGS 1004 -#define OPT_SDR_RX_GAIN 1005 -#define OPT_SDR_TX_GAIN 1006 + +#define OPT_SDR_ARGS 1100 +#define OPT_SDR_RX_GAIN 1101 +#define OPT_SDR_TX_GAIN 1102 +#define OPT_WRITE_IQ_RX_WAVE 1103 +#define OPT_WRITE_IQ_TX_WAVE 1104 +#define OPT_READ_IQ_RX_WAVE 1105 static struct option long_options_common[] = { {"help", 0, 0, 'h'}, @@ -165,6 +178,9 @@ static struct option long_options_common[] = { {"sdr-args", 1, 0, OPT_SDR_ARGS}, {"sdr-rx-gain", 1, 0, OPT_SDR_RX_GAIN}, {"sdr-tx-gain", 1, 0, OPT_SDR_TX_GAIN}, + {"write-iq-rx-wave", 1, 0, OPT_WRITE_IQ_RX_WAVE}, + {"write-iq-tx-wave", 1, 0, OPT_WRITE_IQ_TX_WAVE}, + {"read-iq-rx-wave", 1, 0, OPT_READ_IQ_RX_WAVE}, {0, 0, 0, 0} }; @@ -316,6 +332,18 @@ void opt_switch_common(int c, char *arg0, int *skip_args) sdr_tx_gain = atof(optarg); *skip_args += 2; break; + case OPT_WRITE_IQ_RX_WAVE: + write_iq_rx_wave = strdup(optarg); + *skip_args += 2; + break; + case OPT_WRITE_IQ_TX_WAVE: + write_iq_tx_wave = strdup(optarg); + *skip_args += 2; + break; + case OPT_READ_IQ_RX_WAVE: + read_iq_rx_wave = strdup(optarg); + *skip_args += 2; + break; default: exit (0); } diff --git a/src/common/sdr.c b/src/common/sdr.c index 60ac610..2644968 100644 --- a/src/common/sdr.c +++ b/src/common/sdr.c @@ -50,16 +50,20 @@ typedef struct sdr { int channels; /* number of frequencies */ double samplerate; /* IQ rate */ double amplitude; /* amplitude of each carrier */ + wave_rec_t wave_rx_rec; + wave_rec_t wave_tx_rec; + wave_play_t wave_rx_play; } sdr_t; static const char *sdr_device_args; static double sdr_rx_gain, sdr_tx_gain; +const char *sdr_write_iq_rx_wave, *sdr_write_iq_tx_wave, *sdr_read_iq_rx_wave; #ifdef FAST_SINE static float sdr_sine[256]; #endif -int sdr_init(const char *device_args, double rx_gain, double tx_gain) +int sdr_init(const char *device_args, double rx_gain, double tx_gain, const char *write_iq_rx_wave, const char *write_iq_tx_wave, const char *read_iq_rx_wave) { #ifdef FAST_SINE int i; @@ -72,6 +76,9 @@ int sdr_init(const char *device_args, double rx_gain, double tx_gain) sdr_device_args = strdup(device_args); sdr_rx_gain = rx_gain; sdr_tx_gain = tx_gain; + sdr_write_iq_rx_wave = write_iq_rx_wave; + sdr_write_iq_tx_wave = write_iq_tx_wave; + sdr_read_iq_rx_wave = read_iq_rx_wave; return 0; } @@ -181,6 +188,28 @@ void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_freq } PDEBUG(DSDR, DEBUG_INFO, "Using gain: TX %.1f dB, RX %.1f dB\n", sdr_tx_gain, sdr_rx_gain); + if (sdr_write_iq_rx_wave) { + rc = wave_create_record(&sdr->wave_rx_rec, sdr_write_iq_rx_wave, sdr->samplerate, 2); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); + goto error; + } + } + if (sdr_write_iq_tx_wave) { + rc = wave_create_record(&sdr->wave_tx_rec, sdr_write_iq_tx_wave, sdr->samplerate, 2); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); + goto error; + } + } + if (sdr_read_iq_rx_wave) { + rc = wave_create_playback(&sdr->wave_rx_play, sdr_read_iq_rx_wave, sdr->samplerate, 2); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE playback instance!\n"); + goto error; + } + } + #ifdef HAVE_UHD rc = uhd_open(sdr_device_args, tx_center_frequency, rx_center_frequency, sdr->samplerate, sdr_rx_gain, sdr_tx_gain); if (rc) @@ -203,6 +232,9 @@ void sdr_close(void *inst) #endif if (sdr) { + wave_destroy_record(&sdr->wave_rx_rec); + wave_destroy_record(&sdr->wave_tx_rec); + wave_destroy_playback(&sdr->wave_rx_play); free(sdr->chan); free(sdr); sdr = NULL; @@ -258,6 +290,27 @@ int sdr_write(void *inst, int16_t **samples, int num, enum paging_signal __attri sdr->chan[c].tx_phase = phase; } + if (sdr->wave_tx_rec.fp) { + int16_t spl[2][num], *spl_list[2] = { spl[0], spl[1] }; + for (s = 0, ss = 0; s < num; s++) { + if (buff[ss] >= 1.0) + spl[0][s] = 32767; + else if (buff[ss] <= -1.0) + spl[0][s] = -32767; + else + spl[0][s] = 32767.0 * buff[ss]; + ss++; + if (buff[ss] >= 1.0) + spl[1][s] = 32767; + else if (buff[ss] <= -1.0) + spl[1][s] = -32767; + else + spl[1][s] = 32767.0 * buff[ss]; + ss++; + } + wave_write(&sdr->wave_tx_rec, spl_list, num); + } + #ifdef HAVE_UHD sent = uhd_send(buff, num); #endif @@ -284,6 +337,34 @@ int sdr_read(void *inst, int16_t **samples, int num, int channels) if (count <= 0) return count; + if (sdr->wave_rx_rec.fp) { + int16_t spl[2][count], *spl_list[2] = { spl[0], spl[1] }; + for (s = 0, ss = 0; s < count; s++) { + if (buff[ss] >= 1.0) + spl[0][s] = 32767; + else if (buff[ss] <= -1.0) + spl[0][s] = -32767; + else + spl[0][s] = 32767.0 * buff[ss]; + ss++; + if (buff[ss] >= 1.0) + spl[1][s] = 32767; + else if (buff[ss] <= -1.0) + spl[1][s] = -32767; + else + spl[1][s] = 32767.0 * buff[ss]; + ss++; + } + wave_write(&sdr->wave_rx_rec, spl_list, count); + } + if (sdr->wave_rx_play.fp) { + int16_t spl[2][count], *spl_list[2] = { spl[0], spl[1] }; + wave_read(&sdr->wave_rx_play, spl_list, count); + for (s = 0, ss = 0; s < count; s++) { + buff[ss++] = (double)spl[0][s] / 32767.0; + buff[ss++] = (double)spl[1][s] / 32767.0; + } + } display_iq(buff, count); for (c = 0; c < channels; c++) { diff --git a/src/common/sdr.h b/src/common/sdr.h index ecbcbe4..8ccd56a 100644 --- a/src/common/sdr.h +++ b/src/common/sdr.h @@ -1,5 +1,5 @@ -int sdr_init(const char *device_args, double rx_gain, double tx_gain); +int sdr_init(const char *device_args, double rx_gain, double tx_gain, const char *write_iq_rx_wave, const char *write_iq_tx_wave, const char *read_iq_rx_wave); void *sdr_open(const char *audiodev, double *tx_frequency, double *rx_frequency, int channels, double paging_frequency, int samplerate, double bandwidth, double sample_deviation); void sdr_close(void *inst); int sdr_write(void *inst, int16_t **samples, int num, enum paging_signal *paging_signal, int *on, int channels); diff --git a/src/common/sender.c b/src/common/sender.c index f610dbc..d636974 100644 --- a/src/common/sender.c +++ b/src/common/sender.c @@ -50,6 +50,9 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf sender->loopback = loopback; sender->loss_volume = loss_volume; sender->paging_signal = paging_signal; + sender->write_rx_wave = write_rx_wave; + sender->write_tx_wave = write_tx_wave; + sender->read_rx_wave = read_rx_wave; PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Creating 'Sender' instance\n"); @@ -118,28 +121,6 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf goto error; } - if (write_rx_wave) { - rc = wave_create_record(&sender->wave_rx_rec, write_rx_wave, samplerate); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); - goto error; - } - } - if (write_tx_wave) { - rc = wave_create_record(&sender->wave_tx_rec, write_tx_wave, samplerate); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); - goto error; - } - } - if (read_rx_wave) { - rc = wave_create_playback(&sender->wave_rx_play, read_rx_wave, samplerate); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE playback instance!\n"); - goto error; - } - } - rc = init_emphasis(&sender->estate, samplerate, CUT_OFF_EMPHASIS_DEFAULT); if (rc < 0) goto error; @@ -162,6 +143,7 @@ int sender_open_audio(void) int channels; double paging_frequency = 0.0; int i; + int rc; for (master = sender_head; master; master = master->next) { /* skip audio slaves */ @@ -184,6 +166,28 @@ int sender_open_audio(void) paging_frequency = inst->ruffrequenz; } + if (master->write_rx_wave) { + rc = wave_create_record(&master->wave_rx_rec, master->write_rx_wave, master->samplerate, channels); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); + return rc; + } + } + if (master->write_tx_wave) { + rc = wave_create_record(&master->wave_tx_rec, master->write_tx_wave, master->samplerate, channels); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); + return rc; + } + } + if (master->read_rx_wave) { + rc = wave_create_playback(&master->wave_rx_play, master->read_rx_wave, master->samplerate, channels); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE playback instance!\n"); + return rc; + } + } + /* open device */ master->audio = master->audio_open(master->audiodev, tx_f, rx_f, channels, paging_frequency, master->samplerate, master->bandwidth, master->sample_deviation); if (!master->audio) { @@ -278,12 +282,8 @@ cant_recover: jitter_load(&inst->dejitter, samples[i], count); else sender_send(inst, samples[i], count); - if (inst->wave_tx_rec.fp) - wave_write(&inst->wave_tx_rec, samples[i], count); /* internal loopback: loop back TX audio to RX */ if (inst->loopback == 1) { - if (inst->wave_rx_rec.fp) - wave_write(&inst->wave_rx_rec, samples[i], count); display_wave(inst, samples[i], count); sender_receive(inst, samples[i], count); } @@ -295,6 +295,9 @@ cant_recover: on[i] = sender->paging_on; } + if (sender->wave_tx_rec.fp) + wave_write(&sender->wave_tx_rec, samples, count); + rc = sender->audio_write(sender->audio, samples, count, paging_signal, on, num_chan); if (rc < 0) { PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc); @@ -324,6 +327,11 @@ transmit_later: return; } if (count) { + if (sender->wave_rx_rec.fp) + wave_write(&sender->wave_rx_rec, samples, count); + if (sender->wave_rx_play.fp) + wave_read(&sender->wave_rx_play, samples, count); + /* loop through all channels */ for (i = 0, inst = sender; inst; i++, inst = inst->slave) { /* rx gain */ @@ -332,11 +340,7 @@ transmit_later: /* do de emphasis from radio (then write_wave/wave_read), receive audio, process echo test */ if (inst->de_emphasis) de_emphasis(&inst->estate, samples[i], count); - if (inst->wave_rx_play.fp) - wave_read(&inst->wave_rx_play, samples[i], count); if (inst->loopback != 1) { - if (inst->wave_rx_rec.fp) - wave_write(&inst->wave_rx_rec, samples[i], count); display_wave(inst, samples[i], count); sender_receive(inst, samples[i], count); } diff --git a/src/common/sender.h b/src/common/sender.h index 61302f1..12f30ab 100644 --- a/src/common/sender.h +++ b/src/common/sender.h @@ -53,6 +53,9 @@ typedef struct sender { int loopback; /* 0 = off, 1 = internal, 2 = external */ /* record and playback */ + const char *write_rx_wave; /* file name pointers */ + const char *write_tx_wave; + const char *read_rx_wave; wave_rec_t wave_rx_rec; /* wave recording (from rx) */ wave_rec_t wave_tx_rec; /* wave recording (from tx) */ wave_play_t wave_rx_play; /* wave playback (as rx) */ diff --git a/src/common/wave.c b/src/common/wave.c index 2365078..e18dfb4 100644 --- a/src/common/wave.c +++ b/src/common/wave.c @@ -33,7 +33,7 @@ struct fmt { uint16_t bits_sample; /* bits per sample (one channel) */ }; -int wave_create_record(wave_rec_t *rec, const char *filename, int samplerate) +int wave_create_record(wave_rec_t *rec, const char *filename, int samplerate, int channels) { /* RIFFxxxxWAVEfmt xxxx(fmt size)dataxxxx... */ char dummyheader[4 + 4 + 4 + 4 + 4 + sizeof(struct fmt) + 4 + 4]; @@ -41,6 +41,7 @@ int wave_create_record(wave_rec_t *rec, const char *filename, int samplerate) memset(rec, 0, sizeof(*rec)); rec->samplerate = samplerate; + rec->channels = channels; rec->fp = fopen(filename, "w"); if (!rec->fp) { @@ -56,7 +57,7 @@ int wave_create_record(wave_rec_t *rec, const char *filename, int samplerate) return 0; } -int wave_create_playback(wave_play_t *play, const char *filename, int samplerate) +int wave_create_playback(wave_play_t *play, const char *filename, int samplerate, int channels) { uint8_t buffer[256]; struct fmt fmt; @@ -65,6 +66,7 @@ int wave_create_playback(wave_play_t *play, const char *filename, int samplerate int rc = -EINVAL; memset(play, 0, sizeof(*play)); + play->channels = channels; play->fp = fopen(filename, "r"); if (!play->fp) { @@ -153,8 +155,8 @@ int wave_create_playback(wave_play_t *play, const char *filename, int samplerate rc = -EINVAL; goto error; } - if (fmt.channels != 1) { - fprintf(stderr, "WAVE error: We support only mono files!\n"); + if (fmt.channels !=channels) { + fprintf(stderr, "WAVE error: We expect %d cannel(s), but wave file only has %d channel(s)\n", channels, fmt.channels); rc = -EINVAL; goto error; } @@ -163,13 +165,23 @@ int wave_create_playback(wave_play_t *play, const char *filename, int samplerate rc = -EINVAL; goto error; } + if ((int)fmt.data_rate != 2 * channels * samplerate) { + fprintf(stderr, "WAVE error: The WAVE file's data rate is only %d bytes per second, but we expect %d bytes per second (2 bytes per sample * channels * samplerate)!\n", fmt.data_rate, 2 * channels * samplerate); + rc = -EINVAL; + goto error; + } + if (fmt.bytes_sample != 2 * channels) { + fprintf(stderr, "WAVE error: The WAVE file's bytes per sample is only %d, but we expect %d bytes sample (2 bytes per sample * channels)!\n", fmt.bytes_sample, 2 * channels); + rc = -EINVAL; + goto error; + } if (fmt.bits_sample != 16) { fprintf(stderr, "WAVE error: We support only 16 bit files!\n"); rc = -EINVAL; goto error; } - play->left = chunk >> 1; + play->left = chunk / 2 / channels; printf("*** Replacing received audio by %s.\n", filename); @@ -181,14 +193,15 @@ error: return rc; } -int wave_read(wave_play_t *play, int16_t *samples, int length) +int wave_read(wave_play_t *play, int16_t **samples, int length) { - uint8_t *buffer = (uint8_t *)samples; + uint8_t buff[2 * length * play->channels]; int __attribute__((__unused__)) len; - int i; + int i, j, c; if (length > (int)play->left) { - memset(samples, 0, length << 1); + for (c = 0; c < play->channels; c++) + memset(samples[c], 0, 2 * length); length = play->left; } if (!length) @@ -199,28 +212,31 @@ int wave_read(wave_play_t *play, int16_t *samples, int length) printf("*** Finished reading WAVE file.\n"); /* read and correct endiness */ - len = fread(samples, 1, length << 1, play->fp); - for (i = 0; i < length; i++) { - *samples++ = buffer[0] + (buffer[1] << 8); - buffer += 2; + len = fread(buff, 1, 2 * length * play->channels, play->fp); + for (i = 0, j = 0; i < length; i++) { + for (c = 0; c < play->channels; c++) { + samples[c][i] = buff[j] + (buff[j + 1] << 8); + j += 2; + } } return length; } -int wave_write(wave_rec_t *rec, int16_t *samples, int length) +int wave_write(wave_rec_t *rec, int16_t **samples, int length) { - uint8_t buffer[length << 1]; + uint8_t buff[2 * length * rec->channels]; int __attribute__((__unused__)) len; - int i, j; + int i, j, c; /* write and correct endiness */ for (i = 0, j = 0; i < length; i++) { - buffer[j++] = *samples; - buffer[j++] = (*samples) >> 8; - samples++; + for (c = 0; c < rec->channels; c++) { + buff[j++] = samples[c][i]; + buff[j++] = samples[c][i] >> 8; + } } - len = fwrite(buffer, 1, length << 1, rec->fp); + len = fwrite(buff, 1, 2 * length * rec->channels, rec->fp); rec->written += length; return length; @@ -257,10 +273,10 @@ void wave_destroy_record(wave_rec_t *rec) /* fmt */ fprintf(rec->fp, "fmt %c%c%c%c", (uint8_t)sizeof(fmt), 0, 0, 0); fmt.format = 1; - fmt.channels = 1; + fmt.channels = rec->channels; fmt.sample_rate = rec->samplerate; /* samples/sec */ - fmt.data_rate = rec->samplerate * 2; /* full data rate */ - fmt.bytes_sample = 2; /* all channels */ + fmt.data_rate = rec->samplerate * 2 * rec->channels; /* full data rate */ + fmt.bytes_sample = 2 * rec->channels; /* all channels */ fmt.bits_sample = 16; /* one channel */ buffer[0] = fmt.format; buffer[1] = fmt.format >> 8; diff --git a/src/common/wave.h b/src/common/wave.h index b9575d6..3c7aa48 100644 --- a/src/common/wave.h +++ b/src/common/wave.h @@ -1,19 +1,21 @@ typedef struct wave_rec { FILE *fp; + int channels; int samplerate; uint32_t written; /* how much samples written */ } wave_rec_t; typedef struct wave_play { FILE *fp; + int channels; uint32_t left; /* how much samples left */ } wave_play_t; -int wave_create_record(wave_rec_t *rec, const char *filename, int samplerate); -int wave_create_playback(wave_play_t *play, const char *filename, int samplerate); -int wave_read(wave_play_t *play, int16_t *samples, int length); -int wave_write(wave_rec_t *rec, int16_t *samples, int length); +int wave_create_record(wave_rec_t *rec, const char *filename, int samplerate, int channels); +int wave_create_playback(wave_play_t *play, const char *filename, int samplerate, int channels); +int wave_read(wave_play_t *play, int16_t **samples, int length); +int wave_write(wave_rec_t *rec, int16_t **samples, int length); void wave_destroy_record(wave_rec_t *rec); void wave_destroy_playback(wave_play_t *play); -- cgit v1.2.3