Commit 9024acca authored by Mans Rullgard's avatar Mans Rullgard

Initial revision

parents
*.a
*.d
*.o
mqadec
mqarender
mqascan
mqbgen
mqbscan
ARCH ?= $(shell uname -m)
-include $(or $(CONFIG),$(ARCH)).mk
MAKEFLAGS += -r
O ?= $(ARCH)
override O := $(O:%=$(O:%/=%)/)
SYSROOT = $(addprefix --sysroot=,$(ROOT))
CC = $(CROSS_COMPILE)gcc $(SYSROOT)
AR = $(CROSS_COMPILE)ar
LDLIBS-$(HAVE_BLUOS_SSC) += -lbluos_ssc
CPPFLAGS += -MMD
CFLAGS = -O2 -g -Wall $(CPUFLAGS)
LDFLAGS += -Wl,--as-needed
LDLIBS += -lsndfile $(LDLIBS-y)
ALL = mqascan mqbgen mqbscan
ALL-$(HAVE_BLUOS_SSC) += mqadec mqarender
ALL += $(ALL-y)
ALL := $(ALL:%=$(O)%)
all: $(ALL)
LIBOBJ = bits.o mqa-common.o mqbcrc.o sfbits.o
LIBOBJ := $(LIBOBJ:%=$(O)%)
LIB = $(O)libmqa.a
$(LIB): $(LIBOBJ)
$(RM) $@
$(AR) rcs $@ $^
$(ALL): $(LIB)
$(O)%.o: %.c | $(O)
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
$(O)%: $(O)%.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
$(O):
@mkdir -p $@
.PHONY: all
.SECONDARY:
-include $(ALL:%=%.d) $(OBJ:.o=.d)
/*
Copyright (c) 2017, Mans Rullgard <mans@mansr.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdarg.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#include <ctype.h>
#include "bits.h"
#define array_size(a) (sizeof(a) / sizeof(a[0]))
#define min(a, b) ((a) < (b) ? (a) : (b))
static void fill_bits(struct bitreader *b, int n)
{
if (b->bitpos) {
int s = b->bitpos >> 5;
memmove(b->bitbuf, &b->bitbuf[s],
4 * (array_size(b->bitbuf) - s));
b->bitpos -= 32 * s;
b->bitend -= 32 * s;
}
b->fill_bits(b, n);
}
uint32_t peek_bits(struct bitreader *b, unsigned n, unsigned offs)
{
unsigned end = offs + n;
unsigned shift = 32 - n;
uint32_t bits;
int w, s;
if (b->bitend < b->bitpos + end)
fill_bits(b, end);
if (b->bitend < b->bitpos + end) {
if (b->eof_cb)
b->eof_cb();
return 0;
}
w = (b->bitpos + offs) >> 5;
s = (b->bitpos + offs) & 31;
if (b->msb) {
bits = b->bitbuf[w] << s;
if (s)
bits |= b->bitbuf[w + 1] >> (32 - s);
return bits >> shift;
}
bits = b->bitbuf[w] >> s;
if (s)
bits |= b->bitbuf[w + 1] << (32 - s);
return bits << shift >> shift;
}
uint64_t peek_bits64(struct bitreader *b, unsigned n, unsigned offs)
{
uint64_t bits;
if (n <= 32)
return peek_bits(b, n, offs);
if (b->msb) {
bits = (uint64_t)peek_bits(b, n - 32, offs) << 32;
bits |= peek_bits(b, 32, offs + n - 32);
} else {
bits = peek_bits(b, 32, offs);
bits |= (uint64_t)peek_bits(b, n - 32, offs + 32) << 32;
}
return bits;
}
uint64_t get_ubits(struct bitreader *b, int n)
{
uint64_t bits = peek_bits64(b, n, 0);
b->bitpos += n;
if (b->get_bits_cb)
b->get_bits_cb(bits, n);
return bits;
}
int64_t get_sbits(struct bitreader *b, int n)
{
int64_t v = get_ubits(b, n);
int s = 64 - n;
return v << s >> s;
}
int find_sync(struct bitreader *b, uint64_t magic, int len)
{
while (peek_bits64(b, len, 0) != magic)
get_ubits(b, 1);
return 0;
}
void init_bits(struct bitreader *b)
{
memset(b, 0, sizeof(*b));
}
static int verbosity = 1;
static int need_nl;
int print_verbosity(int v)
{
int old = verbosity;
verbosity = v;
return old;
}
int print_verbose(int v, const char *fmt, ...)
{
va_list ap;
int ret;
if (verbosity < v)
return 0;
va_start(ap, fmt);
ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
void print_data(struct bitreader *b, int size, int flags, const char *name,
uint8_t *out)
{
int n = (size + 7) >> 3;
int w;
int i;
if (!size)
return;
if (flags & BF_CHAR)
w = 31;
else
w = 15;
print_verbose(1, "%10s%-24s%4d: ", "", name, size);
if (verbosity == 1)
printf("[skipped]\n");
else if (verbosity)
printf("\n");
for (i = 0; i < n; i++) {
int s, v;
s = min(size, 8);
v = get_ubits(b, s);
size -= s;
if (out)
*out++ = v;
if (verbosity < 2)
continue;
if (!(i & w)) {
printf("%14s%08x:", "", 8 * i);
if (flags & BF_CHAR)
printf(" |");
need_nl = 1;
}
if (!(flags & BF_CHAR) && !(i & w >> 1))
printf(" ");
if (flags & BF_CHAR)
printf("%c", isprint(v)? v : '.');
else
printf(" %02x", v);
if ((i & w) == w) {
if (flags & BF_CHAR)
printf("|");
printf("\n");
need_nl = 0;
}
}
if (need_nl) {
printf("\n");
need_nl = 0;
}
}
uint64_t print_field(struct bitreader *b, int size, int flags,
const char *name, const char **values)
{
uint64_t v;
if (flags & BF_DATA) {
print_data(b, size, flags, name, NULL);
return 0;
}
if (flags & BF_SIGNED)
v = get_sbits(b, size);
else
v = get_ubits(b, size);
if (verbosity < 1)
return v;
printf("%10s%-24s%4d: ", "", name, size);
if (flags & BF_HEX)
printf("0x%0*"PRIx64, (size + 3) >> 2, v);
else if (flags & BF_SIGNED)
printf("%"PRId64, v);
else if (flags & BF_CHAR)
printf("0x%02x '%c'", (unsigned)v, (unsigned)v);
else
printf("%"PRIu64, v);
if (values && values[v])
printf(" [%s]", values[v]);
printf("\n");
return v;
}
uint64_t print_fields(struct bitreader *b, const struct bitfield *bf,
uint64_t *out)
{
uint64_t val[16];
uint64_t ret = 0;
uint64_t v;
int i = 0;
while (bf->name) {
int size;
if (bf->flags & BF_SIZE)
size = val[bf->size & 15];
else
size = bf->size;
v = print_field(b, size, bf->flags, bf->name, bf->values);
val[i++ & 15] = v;
if (bf->flags & BF_RET) {
if (out)
*out++ = v;
ret = v;
}
bf++;
}
return ret;
}
uint64_t print_frame(struct bitreader *b, const struct frame *f,
int type, uint64_t pos)
{
uint64_t ret = 0;
if (verbosity)
printf("%08"PRIx64": [%x] %s\n", pos,
type, f->name ? f->name : "unknown type");
if (f->handler) {
ret = f->handler(b, type);
} else if (f->fields) {
ret = print_fields(b, f->fields, NULL);
}
return ret;
}
void print_end(void)
{
if (need_nl)
printf("\n");
need_nl = 0;
}
/*
Copyright (c) 2017, Mans Rullgard <mans@mansr.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BITS_H
#define BITS_H
#include <stdint.h>
struct bitreader {
uint32_t bitbuf[32];
unsigned bitpos;
unsigned bitend;
unsigned msb;
void (*fill_bits)(struct bitreader *, int n);
void (*get_bits_cb)(uint64_t bits, int n);
void (*eof_cb)(void);
};
void init_bits(struct bitreader *b);
int find_sync(struct bitreader *b, uint64_t magic, int len);
uint64_t get_ubits(struct bitreader *b, int n);
int64_t get_sbits(struct bitreader *b, int n);
uint32_t peek_bits(struct bitreader *b, unsigned n, unsigned offs);
uint64_t peek_bits64(struct bitreader *b, unsigned n, unsigned offs);
struct bitfield {
int size;
int flags;
const char *name;
const char **values;
};
#define BF_SIGNED (1 << 0)
#define BF_HEX (1 << 1)
#define BF_CHAR (1 << 2)
#define BF_DATA (1 << 3)
#define BF_RET (1 << 4)
#define BF_SIZE (1 << 5)
struct frame {
const char *name;
const struct bitfield *fields;
int (*handler)(struct bitreader *b, unsigned type);
};
int print_verbosity(int v);
int print_verbose(int v, const char *fmt, ...);
void print_data(struct bitreader *b, int size, int flags, const char *name,
uint8_t *out);
uint64_t print_field(struct bitreader *b, int size, int flags,
const char *name, const char **values);
uint64_t print_fields(struct bitreader *b, const struct bitfield *bf,
uint64_t *out);
uint64_t print_frame(struct bitreader *b, const struct frame *f,
int type, uint64_t pos);
void print_end(void);
#endif
#ifndef BLUOS_SSC_H
#define BLUOS_SSC_H
#include <stdint.h>
#include <alsa/asoundlib.h>
#include <alsa/pcm_rate.h>
enum mqa_options {
MQA_48K = 1 << 0,
MQA_NO_RENDER_RESAMP = 1 << 1,
MQA_LOW_POWER = 1 << 2,
MQA_DECODE_ONLY = 1 << 3,
};
struct ssc_decode;
typedef int (*get_samples_fn)(int frame_size, uint8_t **buf, int eof, int *end);
typedef void (*consume_fn)(int len);
typedef size_t (*write_samples_fn)(void *, void *buf, size_t len);
typedef int (*write_size_fn)(void *);
struct ssc_decode *ssc_decode_open(int *channels, int *rate1,
int *bits, int rate2,
get_samples_fn, consume_fn,
write_samples_fn, write_size_fn,
int *fd, void **cb_data, int options,
const char *device);
int ssc_decode_read(struct ssc_decode *);
const char *ssc_decode_status(struct ssc_decode *);
void ssc_decode_close(struct ssc_decode *);
struct ssc_render;
int ssc_render_init(struct ssc_render **rend,
const snd_pcm_rate_info_t *info);
void ssc_render(struct ssc_render *rend,
const snd_pcm_channel_area_t *dst_areas,
int dst_offset, int dst_frames,
const snd_pcm_channel_area_t *src_areas,
int src_offset, int src_frames,
int mute, unsigned int channels, snd_pcm_format_t format);
void ssc_render_free(struct ssc_render *rend);
void ssc_render_close(struct ssc_render *rend);
#endif
/*
Copyright (c) 2017, Mans Rullgard <mans@mansr.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "mqa-common.h"
const char *mqa_rates[32] = {
"44.1 kHz",
"88.1 KHz",
"176.4 kHz",
"352.8 kHz",
"705.6 kHz",
"1.4112 MHz",
"2.8224 MHz",
"5.6448 MHz",
"48 kHz",
"96 kHz",
"192 kHz",
"384 kHz",
"768 kHz",
"1.536 MHz",
"3.072 MHz",
"6.144 MHz",
"64 kHz",
"128 kHz",
"256 kHz",
"512 kHz",
"1.024 MHz",
"2.048 MHz",
"4.096 MHz",
"8.192 MHz",
};
/*
Copyright (c) 2017, Mans Rullgard <mans@mansr.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MQA_COMMON_H
#define MQA_COMMON_H
extern const char *mqa_rates[32];
#endif
/*
Copyright (c) 2017, Mans Rullgard <mans@mansr.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sndfile.h>
#include "bluos_ssc.h"
#define BUF_SIZE 4096
static SNDFILE *infile;
static uint8_t buf[BUF_SIZE];
static int buf_pos;
static int buf_end;
static SNDFILE *outfile;
static int get_samples(int frame_size, uint8_t **samples, int eof, int *end)
{
int size;
if (buf_pos > 0) {
size = buf_end - buf_pos;
memmove(buf, buf + buf_pos, size);
buf_pos = 0;
buf_end = size;
}
if (infile && buf_end < BUF_SIZE) {
int frames = (BUF_SIZE - buf_end) / frame_size;
frames = sf_readf_int(infile, (int *)&buf[buf_end], frames);
if (!frames) {
sf_close(infile);
infile = NULL;
}
buf_end += frames * frame_size;
}
size = buf_end - buf_pos;
size -= size % frame_size;
if (end) {
if (!size) {
*end = 1;
return 0;
}
*end = 0;
}
*samples = &buf[buf_pos];
return size;
}
static void consume(int len)
{
buf_pos += len;
}
static size_t write_samples(void *p, void *buf, size_t len)
{
int32_t *s = buf;
int i;
len &= ~7;
for (i = 0; i < len / 4; i++)
s[i] <<= 8;
return sf_writef_int(outfile, s, len / 8) * 8;
}
static int write_size(void *p)
{
return BUF_SIZE;
}
int main(int argc, char **argv)
{
struct ssc_decode *sscd;
SF_INFO infmt;
SF_INFO outfmt;
int dummy = 0;
int channels = 2;
int rate1 = 0;
int rate2 = 0;
int bits = 32;
int options = 0;
int mqa = 0;
int opt;
while ((opt = getopt(argc, argv, "o:r:")) != -1) {
switch (opt) {
case 'o':
options = strtol(optarg, NULL, 0);
break;
case 'r':
rate2 = strtol(optarg, NULL, 0);
break;
default:
return 1;
}
}
argc -= optind;
argv += optind;
if (argc < 2)
return 1;
memset(&infmt, 0, sizeof(infmt));
infile = sf_open(argv[0], SFM_READ, &infmt);
if (!infile) {
fprintf(stderr, "%s: %s\n", argv[0], sf_strerror(NULL));
return 1;
}
rate1 = infmt.samplerate;
channels = infmt.channels;
sscd = ssc_decode_open(&channels, &rate1, &bits, rate2,
get_samples, consume, write_samples,
write_size, &dummy, (void **)&outfile,
options, "dev");
if (!sscd) {
fprintf(stderr, "ssc_decode_open failed\n");
return 1;
}
memset(&outfmt, 0, sizeof(outfmt));
outfmt.samplerate = rate1;