mirror of https://github.com/drowe67/librtlsdr.git
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
parent
8719f28cf9
commit
b8126663ab
|
@ -70,7 +70,7 @@ if(RTL_STATIC_BUILD)
|
||||||
# Special MINGW stuff here
|
# Special MINGW stuff here
|
||||||
# see https://cmake.org/pipermail/cmake/2012-September/051970.html
|
# 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
|
# 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_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_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")
|
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS} -static-libgcc -static-libstdc++ -s")
|
||||||
|
|
|
@ -23,9 +23,12 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#else
|
#else
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -397,4 +400,151 @@ void executeInBackground( char * file, char * args, char * searchStr[], char * r
|
||||||
|
|
||||||
#endif
|
#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
|
// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#ifndef __CONVENIENCE_H
|
#ifndef __CONVENIENCE_H
|
||||||
#define __CONVENIENCE_H
|
#define __CONVENIENCE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
/* a collection of user friendly tools */
|
/* 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[] );
|
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*/
|
#endif /*__CONVENIENCE_H*/
|
||||||
|
|
20
src/rtl_fm.c
20
src/rtl_fm.c
|
@ -293,6 +293,8 @@ void usage(void)
|
||||||
"\t dagc=<rtl_agc>:ds=<direct_sampling_mode>:T=<bias_tee>\n"
|
"\t dagc=<rtl_agc>:ds=<direct_sampling_mode>:T=<bias_tee>\n"
|
||||||
"\t[-q dc_avg_factor for option rdc (default: 9)]\n"
|
"\t[-q dc_avg_factor for option rdc (default: 9)]\n"
|
||||||
"\t[-n disables demodulation output to stdout/file]\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"
|
"\tfilename ('-' means stdout)\n"
|
||||||
"\t omitting the filename also uses stdout\n\n"
|
"\t omitting the filename also uses stdout\n\n"
|
||||||
"Experimental options:\n"
|
"Experimental options:\n"
|
||||||
|
@ -1390,6 +1392,7 @@ static void *output_thread_fn(void *arg)
|
||||||
safe_cond_wait(&s->ready, &s->ready_m);
|
safe_cond_wait(&s->ready, &s->ready_m);
|
||||||
pthread_rwlock_rdlock(&s->rw);
|
pthread_rwlock_rdlock(&s->rw);
|
||||||
fwrite(s->result, 2, s->result_len, s->file);
|
fwrite(s->result, 2, s->result_len, s->file);
|
||||||
|
waveDataSize += 2 * s->result_len;
|
||||||
pthread_rwlock_unlock(&s->rw);
|
pthread_rwlock_unlock(&s->rw);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1695,6 +1698,7 @@ int main(int argc, char **argv)
|
||||||
#endif
|
#endif
|
||||||
int r, opt;
|
int r, opt;
|
||||||
int dev_given = 0;
|
int dev_given = 0;
|
||||||
|
int writeWav = 0;
|
||||||
int custom_ppm = 0;
|
int custom_ppm = 0;
|
||||||
int enable_biastee = 0;
|
int enable_biastee = 0;
|
||||||
const char * rtlOpts = NULL;
|
const char * rtlOpts = NULL;
|
||||||
|
@ -1708,7 +1712,7 @@ int main(int argc, char **argv)
|
||||||
controller_init(&controller);
|
controller_init(&controller);
|
||||||
cmd_init(&cmd);
|
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) {
|
switch (opt) {
|
||||||
case 'd':
|
case 'd':
|
||||||
dongle.dev_index = verbose_device_search(optarg);
|
dongle.dev_index = verbose_device_search(optarg);
|
||||||
|
@ -1847,6 +1851,9 @@ int main(int argc, char **argv)
|
||||||
else
|
else
|
||||||
ds_threshold = ds_temp;
|
ds_threshold = ds_temp;
|
||||||
break;
|
break;
|
||||||
|
case 'H':
|
||||||
|
writeWav = 1;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
++verbosity;
|
++verbosity;
|
||||||
break;
|
break;
|
||||||
|
@ -1972,7 +1979,15 @@ int main(int argc, char **argv)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
fprintf(stderr, "Open %s for write\n", output.filename);
|
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);
|
//r = rtlsdr_set_testmode(dongle.dev, 1);
|
||||||
|
@ -2019,6 +2034,9 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output.file != stdout) {
|
if (output.file != stdout) {
|
||||||
|
if (writeWav) {
|
||||||
|
waveFinalizeHeader(output.file);
|
||||||
|
}
|
||||||
fclose(output.file);}
|
fclose(output.file);}
|
||||||
|
|
||||||
rtlsdr_close(dongle.dev);
|
rtlsdr_close(dongle.dev);
|
||||||
|
|
|
@ -60,6 +60,7 @@ void usage(void)
|
||||||
"\t[-b output_block_size (default: 16 * 16384)]\n"
|
"\t[-b output_block_size (default: 16 * 16384)]\n"
|
||||||
"\t[-n number of samples to read (default: 0, infinite)]\n"
|
"\t[-n number of samples to read (default: 0, infinite)]\n"
|
||||||
"\t[-S force sync output (default: async)]\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");
|
"\tfilename (a '-' dumps samples to stdout)\n\n");
|
||||||
exit(1);
|
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");
|
fprintf(stderr, "Short write, samples lost, exiting!\n");
|
||||||
rtlsdr_cancel_async(dev);
|
rtlsdr_cancel_async(dev);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
waveDataSize += len;
|
||||||
|
}
|
||||||
|
|
||||||
if (bytes_to_read > 0)
|
if (bytes_to_read > 0)
|
||||||
bytes_to_read -= len;
|
bytes_to_read -= len;
|
||||||
|
@ -123,13 +128,14 @@ int main(int argc, char **argv)
|
||||||
const char * rtlOpts = NULL;
|
const char * rtlOpts = NULL;
|
||||||
int dev_index = 0;
|
int dev_index = 0;
|
||||||
int dev_given = 0;
|
int dev_given = 0;
|
||||||
|
int writeWav = 0;
|
||||||
uint32_t frequency = 100000000;
|
uint32_t frequency = 100000000;
|
||||||
uint32_t bandwidth = DEFAULT_BANDWIDTH;
|
uint32_t bandwidth = DEFAULT_BANDWIDTH;
|
||||||
uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
|
uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
|
||||||
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
|
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
|
||||||
int verbosity = 0;
|
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) {
|
switch (opt) {
|
||||||
case 'd':
|
case 'd':
|
||||||
dev_index = verbose_device_search(optarg);
|
dev_index = verbose_device_search(optarg);
|
||||||
|
@ -162,6 +168,9 @@ int main(int argc, char **argv)
|
||||||
case 'S':
|
case 'S':
|
||||||
sync_mode = 1;
|
sync_mode = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'H':
|
||||||
|
writeWav = 1;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
++verbosity;
|
++verbosity;
|
||||||
break;
|
break;
|
||||||
|
@ -249,6 +258,9 @@ int main(int argc, char **argv)
|
||||||
fprintf(stderr, "Failed to open %s\n", filename);
|
fprintf(stderr, "Failed to open %s\n", filename);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (writeWav) {
|
||||||
|
waveWriteHeader(samp_rate, frequency, 8, 2, file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset endpoint before we start reading from it (mandatory) */
|
/* 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");
|
fprintf(stderr, "Short write, samples lost, exiting!\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
waveDataSize += n_read;
|
||||||
|
|
||||||
if ((uint32_t)n_read < out_block_size) {
|
if ((uint32_t)n_read < out_block_size) {
|
||||||
fprintf(stderr, "Short read, samples lost, exiting!\n");
|
fprintf(stderr, "Short read, samples lost, exiting!\n");
|
||||||
|
@ -287,6 +300,10 @@ int main(int argc, char **argv)
|
||||||
0, out_block_size);
|
0, out_block_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (writeWav) {
|
||||||
|
waveFinalizeHeader(file);
|
||||||
|
}
|
||||||
|
|
||||||
if (do_exit)
|
if (do_exit)
|
||||||
fprintf(stderr, "\nUser cancel, exiting...\n");
|
fprintf(stderr, "\nUser cancel, exiting...\n");
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue