added rtl_wavestream

* minor fix(es) in waveread and rtl_wavestat

Signed-off-by: hayati ayguen <h_ayguen@web.de>
development
hayati ayguen 2019-10-27 19:45:20 +01:00
parent d3e2e5225b
commit ffdf40af34
5 changed files with 340 additions and 9 deletions

View File

@ -129,12 +129,13 @@ add_executable(rtl_adsb rtl_adsb.c)
add_executable(rtl_power rtl_power.c)
add_executable(rtl_raw2wav rtl_raw2wav.c convenience/convenience.c convenience/wavewrite.c)
add_executable(rtl_wavestat rtl_wavestat.c convenience/convenience.c convenience/waveread.c)
add_executable(rtl_wavestream rtl_wavestream.c convenience/convenience.c convenience/waveread.c)
if (WITH_RPC)
add_executable(rtl_rpcd rtl_rpcd.c rtlsdr_rpc_msg.c)
set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_udp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power rtl_raw2wav rtl_wavestat rtl_rpcd)
set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_udp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power rtl_raw2wav rtl_wavestat rtl_wavestream rtl_rpcd)
else()
set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_udp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power rtl_raw2wav rtl_wavestat)
set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_udp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power rtl_raw2wav rtl_wavestat rtl_wavestream)
endif()
target_link_libraries(rtl_sdr ${RTLSDR_TOOL_LIB} convenience_static
@ -187,6 +188,7 @@ if(UNIX)
target_link_libraries(rtl_power m)
target_link_libraries(rtl_raw2wav m)
target_link_libraries(rtl_wavestat m)
target_link_libraries(rtl_wavestream m)
if(APPLE)
target_link_libraries(rtl_test m)
else()
@ -206,6 +208,7 @@ if(WIN32)
target_link_libraries(rtl_power libgetopt_static)
target_link_libraries(rtl_raw2wav libgetopt_static m)
target_link_libraries(rtl_wavestat libgetopt_static m)
target_link_libraries(rtl_wavestream libgetopt_static m)
set_property(TARGET rtl_sdr APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_tcp APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_udp APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
@ -217,6 +220,7 @@ if(WIN32)
set_property(TARGET rtl_power APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_raw2wav APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_wavestat APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
set_property(TARGET rtl_wavestream APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
if (WITH_RPC)
target_link_libraries(rtl_rpcd ws2_32 libgetopt_static)
set_property(TARGET rtl_rpcd APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )

View File

@ -149,14 +149,23 @@ int waveReadHeader(FILE * f, uint32_t *srate, uint32_t *freq, int *bitsPerSampl
if ( memcmp(waveHdr.d.hdr.ID, "data", 4 ) )
return 41;
smpSize = *numChannels * (*bitsPerSample + 7) / 8;
smpSize = (*bitsPerSample + 7) / 8; /* round up to next byte */
smpSize *= *numChannels;
*nFrames = waveHdr.d.hdr.size / smpSize;
#if 0
fprintf(stderr, "riffSize = %lu\n", (unsigned long)waveHdr.r.hdr.size );
fprintf(stderr, "dataSize = %lu\n", (unsigned long)waveHdr.d.hdr.size);
fprintf(stderr, "nBlockAlign = %d\n", (int)waveHdr.f.nBlockAlign);
fprintf(stderr, "smpSize = %d\n", (int)smpSize);
fprintf(stderr, "*nFrames = %lu\n", (unsigned long)(*nFrames) );
#endif
return 0;
}
int waveReadSamples(FILE* f, void * vpData, size_t numSamples, int needCleanData)
int waveReadSamples(FILE* f, void * vpData, size_t numSamples, int needCleanData, size_t *numRead)
{
size_t nw;
switch (waveHdr.f.nBitsPerSample)
@ -167,6 +176,7 @@ int waveReadSamples(FILE* f, void * vpData, size_t numSamples, int needCleanDa
case 8:
/* no endian conversion needed for single bytes */
nw = fread(vpData, sizeof(uint8_t), numSamples, f);
*numRead = nw;
return (nw == numSamples) ? 0 : 1;
case 16:
/* TODO: endian conversion needed */
@ -175,11 +185,12 @@ int waveReadSamples(FILE* f, void * vpData, size_t numSamples, int needCleanDa
{
/* TODO: convert back endianness */
}
*numRead = nw;
return (nw == numSamples) ? 0 : 1;
}
}
int waveReadFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData)
int waveReadFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData, size_t *numRead)
{
size_t nw;
switch (waveHdr.f.nBitsPerSample)
@ -190,6 +201,7 @@ int waveReadFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData
case 8:
/* no endian conversion needed for single bytes */
nw = fread(vpData, waveHdr.f.nChannels * sizeof(uint8_t), numFrames, f);
*numRead = nw;
return (nw == numFrames) ? 0 : 1;
case 16:
/* TODO: endian conversion needed */
@ -198,6 +210,7 @@ int waveReadFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData
{
/* TODO: convert back endianness */
}
*numRead = nw;
return (nw == numFrames) ? 0 : 1;
}
}

View File

@ -28,8 +28,8 @@ extern "C" {
int waveReadHeader(FILE * f, uint32_t *samplerate, uint32_t *freq, int *bitsPerSample, int *numChannels
, uint32_t *nFrames, int16_t *formatTag);
int waveReadFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData);
int waveReadSamples(FILE* f, void * vpData, size_t numSamples, int needCleanData); /* returns 0, when no errors occured */
int waveReadFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData, size_t *numRead);
int waveReadSamples(FILE* f, void * vpData, size_t numSamples, int needCleanData, size_t *numRead); /* returns 0, when no errors occured */
void waveGetStartTime(time_t *tim, double *fraction);
void waveGetStopTime(time_t *tim, double *fraction);

View File

@ -71,6 +71,7 @@ void usage(void)
"\t-t print start time in localtime: 'yyy-mm-ddThh:mm:dd.zzz'\n"
"\t-d print file duration in frames (= num samples per channel)\n"
"\t-D print file duration in seconds\n"
"\t-w input file\n"
"\t-v verbose output\n" );
}
@ -251,12 +252,12 @@ int main(int argc, char **argv)
}
if ( printAll || printDurationSmp ) {
if ( printFieldName )
fprintf(stdout, "duration/smp:\t");
fprintf(stdout, "duration/frames:\t");
fprintf(stdout, "%lu\n", (unsigned long)numFrames);
}
if ( printAll || printDurationTim ) {
if ( printFieldName )
fprintf(stdout, "duration/sec:\t");
fprintf(stdout, "duration/secs:\t");
fprintf(stdout, "%f\n", (double)numFrames/(double)srate);
}

View File

@ -0,0 +1,313 @@
/*
* rtl-wavestream, stream raw data (in specified sample format)
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#else
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "getopt/getopt.h"
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define snprintf _snprintf
#endif
#endif
#include "convenience/convenience.h"
#include "convenience/waveread.h"
#include "rtl_app_ver.h"
static volatile int do_exit = 0;
static int verbosity = 0;
#define BLOCKLEN 65536
/* read up to 64K samples */
static uint8_t inpBuffer[BLOCKLEN * sizeof(int32_t)];
/* output is max 4 times bigger: uint8_t -> int32_t */
static uint8_t outBuffer[BLOCKLEN * sizeof(int32_t) * sizeof(int32_t)];
void usage(void)
{
fprintf(stderr, "rtl_wavestream, stream raw data (in specified format)\n");
fprintf(stderr, "rtl_wavestream version %u.%u %s (%s)\n",
APP_VER_MAJOR, APP_VER_MINOR,
APP_VER_ID, __DATE__ );
fprintf(stderr,
"Use:\trtl_wavestream [-options] <input_wave_filename>\n"
"\t-f <fmt> sample format for output. default = input format\n"
"\t-w input file\n"
"\t-v verbose output\n" );
}
#ifdef _WIN32
BOOL WINAPI
sighandler(int signum)
{
if (CTRL_C_EVENT == signum) {
fprintf(stderr, "Signal caught, exiting!\n");
do_exit = 1;
return TRUE;
}
return FALSE;
}
#else
static void sighandler(int signum)
{
fprintf(stderr, "Signal caught, exiting!\n");
do_exit = 1;
}
#endif
int main(int argc, char **argv)
{
#ifndef _WIN32
struct sigaction sigact;
#endif
int r, opt;
const char * wavfilename = NULL;
const char * targetFmtStr = "pcm16";
FILE * inpfile = NULL;
uint32_t freq = 0;
uint32_t srate = 0;
int nChan = 0;
int nBits = 0;
int targetFmt = 0; /* PCM16 = 0, FLOAT32 = 1 */
int inputFmt = 0; /* PCM16 = 0, FLOAT32 = 1 */
int16_t formatTag;
uint32_t numFrames;
time_t tim = 0;
double fraction = 0.0;
struct tm *ptm = NULL;
while ((opt = getopt(argc, argv, "f:w:vh")) != -1) {
switch (opt) {
case 'f': targetFmtStr = optarg; break;
case 'w': wavfilename = optarg; break;
case 'v': ++verbosity; break;
case 'h':
case '?':
default:
usage();
exit(1);
break;
}
}
if (verbosity)
fprintf(stderr, "verbosity set to %d\n", verbosity);
if (optind < argc) {
wavfilename = argv[optind];
}
if ( !strcmp(targetFmtStr, "pcm") || !strcmp(targetFmtStr, "pcm16")
|| !strcmp(targetFmtStr, "PCM") || !strcmp(targetFmtStr, "PCM16") )
{
targetFmt = 0; /* PCM16 = 0, FLOAT32 = 1 */
if (verbosity)
fprintf(stderr, "target sample format: PCM16\n");
}
else if ( !strcmp(targetFmtStr, "flt32") || !strcmp(targetFmtStr, "float32") || !strcmp(targetFmtStr, "float")
|| !strcmp(targetFmtStr, "FLT32") || !strcmp(targetFmtStr, "FLOAT32") || !strcmp(targetFmtStr, "FLOAT") )
{
targetFmt = 1; /* PCM16 = 0, FLOAT32 = 1 */
if (verbosity)
fprintf(stderr, "target sample format: FLOAT32\n");
}
else
{
fprintf(stderr, "Error: unsupported target format. accepting 'PCM16'/'PCM' or 'FLOAT32'/'FLOAT'\n");
exit(1);
}
#ifndef _WIN32
sigact.sa_handler = sighandler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGQUIT, &sigact, NULL);
sigaction(SIGPIPE, &sigact, NULL);
#else
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
#endif
#ifdef _WIN32
_setmode(_fileno(stdout), _O_BINARY);
#endif
if (!wavfilename) {
fprintf(stderr, "Error: No input file specified!\n");
exit(1);
} else {
if (verbosity >= 2)
fprintf(stderr, "Opening input '%s'\n", wavfilename);
inpfile = fopen(wavfilename, "rb");
if (!inpfile) {
fprintf(stderr, "Error: Failed to open input %s\n", wavfilename);
exit(1);
}
if (verbosity)
fprintf(stderr, "Opened '%s' for input\n", wavfilename);
}
r = waveReadHeader(inpfile, &srate, &freq, &nBits, &nChan, &numFrames, &formatTag);
if ( r ) {
fprintf(stderr, "Error %d reading/evaluating wave file header\n", r);
} else if ( verbosity >= 2 ) {
fprintf(stderr, "Success reading/evaluating wave file header\n");
}
if ( verbosity ) {
fprintf(stderr, "frequency/Hz:\t%lu\n", (unsigned long)freq);
fprintf(stderr, "samplerate/Hz:\t%lu\n", (unsigned long)srate);
fprintf(stderr, "num_channels:\t%d\n", nChan);
fprintf(stderr, "bits_per_sample:\t%d\n", nBits);
if (formatTag == 0x0001)
fprintf(stderr, "sample_format:\t0x%04X\tPCM\n", (unsigned)formatTag);
else if (formatTag == 0x0003)
fprintf(stderr, "sample_format:\t0x%04X\tIEEE_FLOAT\n", (unsigned)formatTag);
else
fprintf(stderr, "sample_format:\t0x%04X\n", (unsigned)formatTag);
fprintf(stderr, "duration/frames:\t%lu\t0x%lX\n", (unsigned long)numFrames, (unsigned long)numFrames);
fprintf(stderr, "duration/secs:\t%f\n", (double)numFrames/(double)srate);
}
if ( formatTag == 0x0001 && nBits == 16 ) {
inputFmt = 0;
if (verbosity)
fprintf(stderr, "input sample format: PCM16\n");
}
else if ( formatTag == 0x0003 && nBits == 32 ) {
inputFmt = 1;
if (verbosity)
fprintf(stderr, "input sample format: FLOAT32\n");
}
else
{
fprintf(stderr, "Error: unsupported input format. only 'PCM16' and 'FLOAT32' supported.\n");
exit(1);
}
{
void * pvInp = &inpBuffer[0];
void * pvOut = &outBuffer[0];
const size_t numFramesPerRead = BLOCKLEN / nChan;
const size_t numSmpPerRead = numFramesPerRead * nChan;
const size_t inpSmpSize = (inputFmt == 0) ? sizeof(int16_t) : sizeof(float);
const size_t outSmpSize = (targetFmt == 0) ? sizeof(int16_t) : sizeof(float);
size_t numSamples = numFrames * nChan;
size_t readTotal = 0;
size_t numRead;
if ( verbosity )
{
fprintf(stderr, "input sample size = %u\n", (unsigned)inpSmpSize);
fprintf(stderr, "output sample size = %u\n", (unsigned)outSmpSize);
fprintf(stderr, "samples per read = %u smp\n", (unsigned)numSmpPerRead);
}
while ( !do_exit )
{
const size_t numToRead = numSmpPerRead;
const size_t readErr = waveReadSamples(inpfile, pvInp, numToRead, 0, &numRead);
if ( numRead != numToRead )
fprintf(stderr, "Error: reading %lu delivered %lu smp after %lu smp - left %lu frames\n"
, (unsigned long)numToRead, (unsigned long)numRead
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );
if ( readErr )
{
fprintf(stderr, "Error reading samples after %lu smp - left %lu frames\n"
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );
}
else if ( verbosity >= 2 )
fprintf(stderr, "read %lu samples: left frames: %lu\n"
, (unsigned long)numToRead, (unsigned long)numSamples);
if ( !numRead )
break;
if ( inputFmt == targetFmt ) {
size_t w = fwrite(pvInp, inpSmpSize, numRead, stdout);
if ( w != numRead ) {
fprintf(stderr, "Error writing read samples after %lu smp - left %lu frames\n"
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );
break;
}
}
else if ( inputFmt == 0 && targetFmt == 1 ) {
const int16_t *ai = (const int16_t*)pvInp;
float * ao = (float*)pvOut;
size_t w;
for ( size_t k = 0; k < numRead; ++k )
ao[k] = ai[k] * (1.0F / 32768.0F);
w = fwrite(pvOut, outSmpSize, numRead, stdout);
if ( w != numRead ) {
fprintf(stderr, "Error writing converted samples after %lu smp - left %lu frames\n"
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );
break;
}
}
else if ( inputFmt == 1 && targetFmt == 0 ) {
const float *ai = (const float*)pvInp;
int16_t * ao = (int16_t*)pvOut;
size_t w;
for ( size_t k = 0; k < numRead; ++k )
ao[k] = (int16_t)( ai[k] * 32768.0F );
w = fwrite(pvOut, outSmpSize, numRead, stdout);
if ( w != numRead ) {
fprintf(stderr, "Error writing converted samples after %lu smp - left %lu frames\n"
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );
break;
}
}
numSamples -= numRead;
readTotal += numRead;
}
if ( verbosity )
{
fprintf(stderr, "Written %lu samples in total - left %lu of %lu frames\n"
, (unsigned long)readTotal, (unsigned long)(numSamples / nChan), (unsigned long)(numFrames * nChan) );
}
}
fclose(inpfile);
return 0;
}
/* vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab */