// // This file is part of Dire Wolf, an amateur radio packet TNC. // // Copyright (C) 2011, 2012, 2013, 2014, 2015 John Langner, WB2OSZ // // 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, see . // /*------------------------------------------------------------------- * * Name: atest.c * * Purpose: Test fixture for the AFSK demodulator. * * Inputs: Takes audio from a .WAV file insted of the audio device. * * Description: This can be used to test the AFSK demodulator under * controlled and reproducable conditions for tweaking. * * For example * * (1) Download WA8LMF's TNC Test CD image file from * http://wa8lmf.net/TNCtest/index.htm * * (2) Burn a physical CD. * * (3) "Rip" the desired tracks with Windows Media Player. * Select .WAV file format. * * "Track 2" is used for most tests because that is more * realistic for most people using the speaker output. * * * Without ONE_CHAN defined: * * Notice that the number of packets decoded, as reported by * this test program, will be twice the number expected because * we are decoding the left and right audio channels separately. * * * With ONE_CHAN defined: * * Only process one channel. * *--------------------------------------------------------------------*/ // #define X 1 #include #include #include #include #include #include #include #define ATEST_C 1 #include "audio.h" #include "demod.h" #include "multi_modem.h" #include "textcolor.h" #include "ax25_pad.h" #include "hdlc_rec2.h" #include "dlq.h" #include "ptt.h" #if 0 /* Typical but not flexible enough. */ struct wav_header { /* .WAV file header. */ char riff[4]; /* "RIFF" */ int filesize; /* file length - 8 */ char wave[4]; /* "WAVE" */ char fmt[4]; /* "fmt " */ int fmtsize; /* 16. */ short wformattag; /* 1 for PCM. */ short nchannels; /* 1 for mono, 2 for stereo. */ int nsamplespersec; /* sampling freq, Hz. */ int navgbytespersec; /* = nblockalign*nsamplespersec. */ short nblockalign; /* = wbitspersample/8 * nchannels. */ short wbitspersample; /* 16 or 8. */ char data[4]; /* "data" */ int datasize; /* number of bytes following. */ } ; #endif /* 8 bit samples are unsigned bytes */ /* in range of 0 .. 255. */ /* 16 bit samples are signed short */ /* in range of -32768 .. +32767. */ static struct { char riff[4]; /* "RIFF" */ int filesize; /* file length - 8 */ char wave[4]; /* "WAVE" */ } header; static struct { char id[4]; /* "LIST" or "fmt " */ int datasize; } chunk; static struct { short wformattag; /* 1 for PCM. */ short nchannels; /* 1 for mono, 2 for stereo. */ int nsamplespersec; /* sampling freq, Hz. */ int navgbytespersec; /* = nblockalign*nsamplespersec. */ short nblockalign; /* = wbitspersample/8 * nchannels. */ short wbitspersample; /* 16 or 8. */ char extras[4]; } format; static struct { char data[4]; /* "data" */ int datasize; } wav_data; static FILE *fp; static int e_o_f; static int packets_decoded = 0; static int decimate = 0; /* Reduce that sampling rate if set. */ /* 1 = normal, 2 = half, etc. */ static struct audio_s my_audio_config; static int error_if_less_than = 0; /* Exit with error status if this minimum not reached. */ //#define EXPERIMENT_G 1 //#define EXPERIMENT_H 1 #if defined(EXPERIMENT_G) || defined(EXPERIMENT_H) static int count[MAX_SUBCHANS]; #if EXPERIMENT_H extern float space_gain[MAX_SUBCHANS]; #endif #endif static void usage (void); int main (int argc, char *argv[]) { int err; int c; int channel; time_t start_time; #if defined(EXPERIMENT_G) || defined(EXPERIMENT_H) int j; for (j=0; j 10000) { text_color_set(DW_COLOR_ERROR); dw_printf ("Use a more reasonable bit rate in range of 100 - 10000.\n"); exit (EXIT_FAILURE); } if (my_audio_config.achan[0].baud < 600) { my_audio_config.achan[0].modem_type = MODEM_AFSK; my_audio_config.achan[0].mark_freq = 1600; my_audio_config.achan[0].space_freq = 1800; strcpy (my_audio_config.achan[0].profiles, "D"); } else if (my_audio_config.achan[0].baud > 2400) { my_audio_config.achan[0].modem_type = MODEM_SCRAMBLE; my_audio_config.achan[0].mark_freq = 0; my_audio_config.achan[0].space_freq = 0; strcpy (my_audio_config.achan[0].profiles, " "); // avoid getting default later. dw_printf ("Using scrambled baseband signal rather than AFSK.\n"); } else { my_audio_config.achan[0].modem_type = MODEM_AFSK; my_audio_config.achan[0].mark_freq = 1200; my_audio_config.achan[0].space_freq = 2200; } break; case 'P': /* -P for modem profile. */ dw_printf ("Demodulator profile set to \"%s\"\n", optarg); strcpy (my_audio_config.achan[0].profiles, optarg); break; case 'D': /* -D reduce sampling rate for lower CPU usage. */ decimate = atoi(optarg); dw_printf ("Divide audio sample rate by %d\n", decimate); if (decimate < 1 || decimate > 8) { text_color_set(DW_COLOR_ERROR); dw_printf ("Unreasonable value for -D.\n"); exit (1); } dw_printf ("Divide audio sample rate by %d\n", decimate); my_audio_config.achan[0].decimate = decimate; break; case 'F': /* -D set "fix bits" level. */ my_audio_config.achan[0].fix_bits = atoi(optarg); if (my_audio_config.achan[0].fix_bits < RETRY_NONE || my_audio_config.achan[0].fix_bits >= RETRY_MAX) { text_color_set(DW_COLOR_ERROR); dw_printf ("Invalid Fix Bits level.\n"); exit (1); } break; case 'e': /* -e error if less than this number decoded. */ error_if_less_than = atoi(optarg); break; case '?': /* Unknown option message was already printed. */ usage (); break; default: /* Should not be here. */ text_color_set(DW_COLOR_ERROR); dw_printf("?? getopt returned character code 0%o ??\n", c); usage (); } } if (optind >= argc) { text_color_set(DW_COLOR_ERROR); dw_printf ("Specify .WAV file name on command line.\n"); usage (); } fp = fopen(argv[optind], "rb"); if (fp == NULL) { text_color_set(DW_COLOR_ERROR); dw_printf ("Couldn't open file for read: %s\n", argv[optind]); //perror ("more info?"); exit (1); } start_time = time(NULL); /* * Read the file header. * Doesn't handle all possible cases but good enough for our purposes. */ err= fread (&header, (size_t)12, (size_t)1, fp); if (strncmp(header.riff, "RIFF", 4) != 0 || strncmp(header.wave, "WAVE", 4) != 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("This is not a .WAV format file.\n"); exit (EXIT_FAILURE); } err = fread (&chunk, (size_t)8, (size_t)1, fp); if (strncmp(chunk.id, "LIST", 4) == 0) { err = fseek (fp, (long)chunk.datasize, SEEK_CUR); err = fread (&chunk, (size_t)8, (size_t)1, fp); } if (strncmp(chunk.id, "fmt ", 4) != 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("WAV file error: Found \"%4.4s\" where \"fmt \" was expected.\n", chunk.id); exit(1); } if (chunk.datasize != 16 && chunk.datasize != 18) { text_color_set(DW_COLOR_ERROR); dw_printf ("WAV file error: Need fmt chunk datasize of 16 or 18. Found %d.\n", chunk.datasize); exit(1); } err = fread (&format, (size_t)chunk.datasize, (size_t)1, fp); err = fread (&wav_data, (size_t)8, (size_t)1, fp); if (strncmp(wav_data.data, "data", 4) != 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("WAV file error: Found \"%4.4s\" where \"data\" was expected.\n", wav_data.data); exit(1); } assert (format.nchannels == 1 || format.nchannels == 2); assert (format.wbitspersample == 8 || format.wbitspersample == 16); my_audio_config.adev[0].samples_per_sec = format.nsamplespersec; my_audio_config.adev[0].bits_per_sample = format.wbitspersample; my_audio_config.adev[0].num_channels = format.nchannels; my_audio_config.achan[0].valid = 1; if (format.nchannels == 2) my_audio_config.achan[1].valid = 1; text_color_set(DW_COLOR_INFO); dw_printf ("%d samples per second\n", my_audio_config.adev[0].samples_per_sec); dw_printf ("%d bits per sample\n", my_audio_config.adev[0].bits_per_sample); dw_printf ("%d audio channels\n", my_audio_config.adev[0].num_channels); dw_printf ("%d audio bytes in file\n", (int)(wav_data.datasize)); dw_printf ("Fix Bits level = %d\n", my_audio_config.achan[0].fix_bits); /* * Initialize the AFSK demodulator and HDLC decoder. */ multi_modem_init (&my_audio_config); e_o_f = 0; while ( ! e_o_f) { int audio_sample; int c; for (c=0; c= 256 * 256) e_o_f = 1; #define ONE_CHAN 1 /* only use one audio channel. */ #if ONE_CHAN if (c != 0) continue; #endif multi_modem_process_sample(c,audio_sample); } /* When a complete frame is accumulated, */ /* process_rec_frame, below, is called. */ } text_color_set(DW_COLOR_INFO); dw_printf ("\n\n"); #if EXPERIMENT_G for (j=0; j