added option '-H' to write wave Header for rtl_sdr and rtl_fm

* option is only used when output is to file - not with stdout
* using multiple frequencies with rtl_fm ..,
 will only write 1st frequency into wave header

Signed-off-by: hayati ayguen <h_ayguen@web.de>
development
hayati ayguen 2019-03-10 20:11:18 +00:00
parent 8719f28cf9
commit b8126663ab
5 changed files with 207 additions and 3 deletions

View File

@ -70,7 +70,7 @@ if(RTL_STATIC_BUILD)
# Special MINGW stuff here
# see https://cmake.org/pipermail/cmake/2012-September/051970.html
# see http://stackoverflow.com/questions/13768515/how-to-do-static-linking-of-libwinpthread-1-dll-in-mingw
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc -static")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -static-libgcc -s")
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS} -static-libgcc -static-libstdc++ -s")

View File

@ -23,9 +23,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <assert.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#else
#include <windows.h>
#include <fcntl.h>
@ -397,4 +400,151 @@ void executeInBackground( char * file, char * args, char * searchStr[], char * r
#endif
#pragma pack(push)
#pragma pack(1)
typedef struct {
uint16_t wYear; /* 1601 through 30827 */
uint16_t wMonth; /* 1..12 */
uint16_t wDayOfWeek; /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */
uint16_t wDay; /* 1 .. 31 */
uint16_t wHour; /* 0 .. 23 */
uint16_t wMinute; /* 0 .. 59 */
uint16_t wSecond; /* 0 .. 59 */
uint16_t wMilliseconds; /* 0 .. 999 */
} Wind_SystemTime;
typedef struct
{
/* RIFF header */
char riffID[4]; /* "RIFF" string */
uint32_t riffSize; /* full filesize - 8 bytes (maybe with some byte missing...) */
char waveID[4]; /* "WAVE" string */
/* FMT header */
char fmtID[4]; /* = "FMT " */
uint32_t fmtSize;
int16_t wFormatTag;
int16_t nChannels;
int32_t nSamplesPerSec;
int32_t nAvgBytesPerSec;
int16_t nBlockAlign;
int16_t nBitsPerSample;
/* auxi header - used by SpectraVue / rfspace / HDSDR / .. */
char auxiID[4]; /* ="auxi" (chunk rfspace) */
uint32_t auxiSize;
Wind_SystemTime StartTime;
Wind_SystemTime StopTime;
uint32_t centerFreq; /* receiver center frequency */
uint32_t ADsamplerate; /* A/D sample frequency before downsampling */
uint32_t IFFrequency; /* IF freq if an external down converter is used */
uint32_t Bandwidth; /* displayable BW if you want to limit the display to less than Nyquist band */
int32_t IQOffset; /* DC offset of the I and Q channels in 1/1000's of a count */
int32_t Unused2;
int32_t Unused3;
int32_t Unused4;
int32_t Unused5;
/* DATA header */
char dataID[4];
uint32_t dataSize;
} waveFileHeader;
static waveFileHeader waveHdr;
#pragma pack(pop)
uint32_t waveDataSize = 0;
static int waveHdrStarted = 0;
void waveSetTime(Wind_SystemTime *p)
{
struct timeval tv;
struct tm t;
gettimeofday(&tv, NULL);
p->wMilliseconds = tv.tv_usec / 1000;
#ifdef _WIN32
t = *gmtime(&tv.tv_sec);
#else
gmtime_r(&tv.tv_sec, &t);
#endif
p->wYear = t.tm_year + 1900; /* 1601 through 30827 */
p->wMonth = t.tm_mon + 1; /* 1..12 */
p->wDayOfWeek = t.tm_wday; /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */
p->wDay = t.tm_mday; /* 1 .. 31 */
p->wHour = t.tm_hour; /* 0 .. 23 */
p->wMinute = t.tm_min; /* 0 .. 59 */
p->wSecond = t.tm_sec; /* 0 .. 59 */
}
void wavePrepareHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels)
{
int bytesPerSample = bitsPerSample / 8;
int bytesPerFrame = bytesPerSample * numChannels;
strncpy( waveHdr.riffID, "RIFF", 4 );
waveHdr.riffSize = sizeof(waveFileHeader) - 8; /* to fix */
strncpy( waveHdr.waveID, "WAVE", 4 );
strncpy( waveHdr.fmtID, "fmt ", 4 );
waveHdr.fmtSize = 16;
waveHdr.wFormatTag = 1; /* PCM */
waveHdr.nChannels = numChannels; /* I and Q channels */
waveHdr.nSamplesPerSec = samplerate;
waveHdr.nAvgBytesPerSec = samplerate * bytesPerFrame;
waveHdr.nBlockAlign = waveHdr.nChannels;
waveHdr.nBitsPerSample = bitsPerSample;
strncpy( waveHdr.auxiID, "auxi", 4 );
waveHdr.auxiSize = 2 * sizeof(Wind_SystemTime) + 9 * sizeof(int32_t); /* = 2 * 16 + 9 * 4 = 68 */
waveSetTime( &waveHdr.StartTime );
waveHdr.StopTime = waveHdr.StartTime; /* to fix */
waveHdr.centerFreq = freq;
waveHdr.ADsamplerate = samplerate;
waveHdr.IFFrequency = 0;
waveHdr.Bandwidth = 0;
waveHdr.IQOffset = 0;
waveHdr.Unused2 = 0;
waveHdr.Unused3 = 0;
waveHdr.Unused4 = 0;
waveHdr.Unused5 = 0;
strncpy( waveHdr.dataID, "data", 4 );
waveHdr.dataSize = 0; /* to fix later */
waveDataSize = 0;
}
void waveWriteHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels, FILE * f)
{
if (f != stdout) {
assert( !waveHdrStarted );
wavePrepareHeader(samplerate, freq, bitsPerSample, numChannels);
fwrite(&waveHdr, sizeof(waveFileHeader), 1, f);
waveHdrStarted = 1;
}
}
void waveFinalizeHeader(FILE * f)
{
if (f != stdout) {
assert( waveHdrStarted );
waveSetTime( &waveHdr.StopTime );
waveHdr.dataSize = waveDataSize;
waveHdr.riffSize += waveDataSize;
fseek(f, 0, SEEK_SET);
fwrite(&waveHdr, sizeof(waveFileHeader), 1, f);
waveHdrStarted = 0;
}
}
// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab

View File

@ -17,6 +17,8 @@
#ifndef __CONVENIENCE_H
#define __CONVENIENCE_H
#include <stdint.h>
/* a collection of user friendly tools */
@ -157,4 +159,21 @@ int verbose_device_search(char *s);
void executeInBackground( char * file, char * args, char * searchStr[], char * replaceStr[] );
/*!
* helper functions to write and finalize wave headers
* with compatibility to some SDR programs - showing frequency:
* raw sample data still have to be written by caller to FILE*.
* call waveWriteHeader() before writing anything to to file
* and call waveFinalizeHeader() afterwards,
* AND count/increment the written raw size in variable 'waveDataSize'.
* stdout/stdout can't be used, because seek to begin isn't possible.
*
*/
extern uint32_t waveDataSize;
void waveWriteHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels, FILE * f);
void waveFinalizeHeader();
#endif /*__CONVENIENCE_H*/

View File

@ -293,6 +293,8 @@ void usage(void)
"\t dagc=<rtl_agc>:ds=<direct_sampling_mode>:T=<bias_tee>\n"
"\t[-q dc_avg_factor for option rdc (default: 9)]\n"
"\t[-n disables demodulation output to stdout/file]\n"
"\t[-H write wave Header to file (default: off)]\n"
"\t limitation: only 1st tuned frequency will be written into the header!\n"
"\tfilename ('-' means stdout)\n"
"\t omitting the filename also uses stdout\n\n"
"Experimental options:\n"
@ -1390,6 +1392,7 @@ static void *output_thread_fn(void *arg)
safe_cond_wait(&s->ready, &s->ready_m);
pthread_rwlock_rdlock(&s->rw);
fwrite(s->result, 2, s->result_len, s->file);
waveDataSize += 2 * s->result_len;
pthread_rwlock_unlock(&s->rw);
}
return 0;
@ -1695,6 +1698,7 @@ int main(int argc, char **argv)
#endif
int r, opt;
int dev_given = 0;
int writeWav = 0;
int custom_ppm = 0;
int enable_biastee = 0;
const char * rtlOpts = NULL;
@ -1708,7 +1712,7 @@ int main(int argc, char **argv)
controller_init(&controller);
cmd_init(&cmd);
while ((opt = getopt(argc, argv, "d:f:g:s:b:l:o:t:r:p:E:O:F:A:M:hTC:B:m:L:q:c:w:W:D:nv")) != -1) {
while ((opt = getopt(argc, argv, "d:f:g:s:b:l:o:t:r:p:E:O:F:A:M:hTC:B:m:L:q:c:w:W:D:nHv")) != -1) {
switch (opt) {
case 'd':
dongle.dev_index = verbose_device_search(optarg);
@ -1847,6 +1851,9 @@ int main(int argc, char **argv)
else
ds_threshold = ds_temp;
break;
case 'H':
writeWav = 1;
break;
case 'v':
++verbosity;
break;
@ -1972,7 +1979,15 @@ int main(int argc, char **argv)
exit(1);
}
else
{
fprintf(stderr, "Open %s for write\n", output.filename);
if (writeWav) {
int nChan = (demod.mode_demod == &raw_demod) ? 2 : 1;
int srate = (demod.rate_out2 > 0) ? demod.rate_out2 : demod.rate_out;
uint32_t f = controller.freqs[0]; /* only 1st frequency!!! */
waveWriteHeader(srate, f, 16, nChan, output.file);
}
}
}
//r = rtlsdr_set_testmode(dongle.dev, 1);
@ -2019,6 +2034,9 @@ int main(int argc, char **argv)
}
if (output.file != stdout) {
if (writeWav) {
waveFinalizeHeader(output.file);
}
fclose(output.file);}
rtlsdr_close(dongle.dev);

View File

@ -60,6 +60,7 @@ void usage(void)
"\t[-b output_block_size (default: 16 * 16384)]\n"
"\t[-n number of samples to read (default: 0, infinite)]\n"
"\t[-S force sync output (default: async)]\n"
"\t[-H write wave Header to file (default: off)]\n"
"\tfilename (a '-' dumps samples to stdout)\n\n");
exit(1);
}
@ -101,6 +102,10 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
fprintf(stderr, "Short write, samples lost, exiting!\n");
rtlsdr_cancel_async(dev);
}
else
{
waveDataSize += len;
}
if (bytes_to_read > 0)
bytes_to_read -= len;
@ -123,13 +128,14 @@ int main(int argc, char **argv)
const char * rtlOpts = NULL;
int dev_index = 0;
int dev_given = 0;
int writeWav = 0;
uint32_t frequency = 100000000;
uint32_t bandwidth = DEFAULT_BANDWIDTH;
uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
int verbosity = 0;
while ((opt = getopt(argc, argv, "d:f:g:s:w:b:n:p:O:Sv")) != -1) {
while ((opt = getopt(argc, argv, "d:f:g:s:w:b:n:p:O:SHv")) != -1) {
switch (opt) {
case 'd':
dev_index = verbose_device_search(optarg);
@ -162,6 +168,9 @@ int main(int argc, char **argv)
case 'S':
sync_mode = 1;
break;
case 'H':
writeWav = 1;
break;
case 'v':
++verbosity;
break;
@ -249,6 +258,9 @@ int main(int argc, char **argv)
fprintf(stderr, "Failed to open %s\n", filename);
goto out;
}
if (writeWav) {
waveWriteHeader(samp_rate, frequency, 8, 2, file);
}
}
/* Reset endpoint before we start reading from it (mandatory) */
@ -272,6 +284,7 @@ int main(int argc, char **argv)
fprintf(stderr, "Short write, samples lost, exiting!\n");
break;
}
waveDataSize += n_read;
if ((uint32_t)n_read < out_block_size) {
fprintf(stderr, "Short read, samples lost, exiting!\n");
@ -287,6 +300,10 @@ int main(int argc, char **argv)
0, out_block_size);
}
if (writeWav) {
waveFinalizeHeader(file);
}
if (do_exit)
fprintf(stderr, "\nUser cancel, exiting...\n");
else