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
|
||||
# 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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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*/
|
||||
|
|
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[-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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue