Skip to content

Commit

Permalink
sndfile: add support for raw audio input
Browse files Browse the repository at this point in the history
This partly addresses TLeconte#109
until a proper raw IQ input is added, and replaces
TLeconte#110 as a more generic
implementation

use '--sndfile <file>' as previously for all containers supported by
libsndfile.
use '--sndfile <file>,subtype=<N>' for raw audio processing with <N>
being a supported subtype value as specified in sndfile.h. Optionally,
'channels=<M>,endian=<end>' can be added to decode <M> channels (default
1 if not specified) using <end> endianness, where <end> is one of 'big',
'little' or 'cpu' (default 'cpu' if not specified).
  • Loading branch information
f00b4r0 committed Sep 3, 2024
1 parent 57e1e63 commit 1283155
Showing 1 changed file with 91 additions and 4 deletions.
95 changes: 91 additions & 4 deletions soundfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <sndfile.h>
#include "acarsdec.h"
#include "msk.h"
Expand All @@ -30,15 +31,101 @@

static SNDFILE *insnd;

static int usage(void)
{
fprintf(stderr,
"sndfile input accepts as parameter:\n"
" - either a filename, for any file format supported by libsndfile\n"
" - or to process raw audio, a filename (optionally prefixed by 'file=') followed by a coma,\n"
" and any of the following coma-separated extra arguments:\n"
" 'subtype=', 'channels=', 'endian='; where\n"
" 'subtype=' is followed by a number matching a supported libsndfile subtype (required);\n"
" 'channels=' is followed by a number representing the number of channels in the stream (default: 1);\n"
" 'endian=' is one of 'big', 'little', 'cpu' (default: cpu).\n"
"examples:\n"
" 'file=data.raw,subtype=0x6' to process a single-channel, 32-bit cpu-endian float data\n"
" 'data.raw,subtype=2,channels=2,endian=little' to process a 2-channel, 16-bit little-endian PCM data\n"
);

return 1;
}

int initSoundfile(char *optarg)
{
SF_INFO infsnd;
char *stype = NULL, *chans = NULL, *endian = NULL, *fname = NULL;
struct params_s soundp[] = {
{ .name = "subtype", .valp = &stype, },
{ .name = "channels", .valp = &chans, },
{ .name = "endian", .valp = &endian, },
{ .name = "file", .valp = &fname, },
};
char *retp, *sep;
SF_INFO infsnd = {0};
unsigned int n;

infsnd.format = 0;
insnd = sf_open(optarg, SFM_READ, &infsnd);
do {
retp = parse_params(&optarg, soundp, ARRAY_SIZE(soundp));
if (retp) {
sep = strchr(retp, '=');
// backward compat: if we find a lone token, assume it's the filename if not already set
if (!sep && !fname)
fname = retp;
else {
fprintf(stderr, ERRPFX "invalid parameter '%s'\n", retp);
return -1;

}
}
} while (retp);

if (!fname) {
fprintf(stderr, ERRPFX "missing filename\n");
return -1;
}

if (!strcmp("help", fname))
return usage();

// if we have a subtype, assume we're dealing with raw input
if (stype) {
unsigned long sub = strtoul(stype, &stype, 0);
if ('\0' != *stype) {
fprintf(stderr, ERRPFX "invalid subtype value '%s'\n", stype);
return -1;
}

unsigned long nchs = 1;
if (chans) {
nchs = strtoul(chans, &chans, 0);
if ('\0' != *chans) {
fprintf(stderr, ERRPFX "invalid channels value '%s'\n", chans);
return -1;
}
}
infsnd.channels = (int)nchs;
infsnd.samplerate = INTRATE;

unsigned long end = SF_ENDIAN_CPU;
if (endian) {
if (!strcmp("little", endian))
end = SF_ENDIAN_LITTLE;
else if (!strcmp("big", endian))
end = SF_ENDIAN_BIG;
else if (!strcmp("cpu", endian))
end = SF_ENDIAN_CPU;
else {
fprintf(stderr, ERRPFX "invalid endian value '%s'\n", endian);
return -1;
}
}
infsnd.format = SF_FORMAT_RAW|(sub & SF_FORMAT_SUBMASK)|end;
}
else
infsnd.format = 0;

insnd = sf_open(fname, SFM_READ, &infsnd);
if (insnd == NULL) {
fprintf(stderr, ERRPFX "could not open '%s'\n", optarg);
fprintf(stderr, ERRPFX "could not open '%s'\n", fname);
return (1);
}

Expand Down

0 comments on commit 1283155

Please sign in to comment.