Skip to content

Commit

Permalink
Add test MPX file
Browse files Browse the repository at this point in the history
* Enable Git-LFS and add a test FLAC file
* Write a basic skeleton for MPX tests
* This will help contributors develop subcarrier-based features in the future
  and write tests for them
  • Loading branch information
windytan committed Jul 31, 2024
1 parent d1d112a commit e9386d1
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.flac filter=lfs diff=lfs merge=lfs -text
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ jobs:
run: meson setup -Dwerror=true -Db_sanitize=address,undefined -Db_lundef=false build
- name: compile & install
run: cd build && meson install
- name: download test data
run: git lfs pull
- name: test
run: cd build && meson test
- name: Test command-line interface
Expand Down
18 changes: 14 additions & 4 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,21 @@ executable(
catch2 = dependency('catch2-with-main', required: false)

if catch2.found()
test_exec = executable(
'redsea-test',
[sources_no_main, 'test/unit.cc'],
unit_test_exe = executable(
'redsea-test-unit',
[
sources_no_main,
'test/unit.cc',
],
dependencies: [iconv, json, liquid, sndfile, catch2],
override_options: override_options,
)
test('Smoke tests', test_exec)
mpx_test_exe = executable(
'redsea-test-mpx',
[sources_no_main, 'test/mpx.cc'],
dependencies: [iconv, json, liquid, sndfile, catch2],
override_options: override_options,
)
test('Unit tests', unit_test_exe)
test('MPX tests', mpx_test_exe)
endif
15 changes: 5 additions & 10 deletions src/input.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ namespace redsea {
* An MPXReader deals with reading an FM multiplex signal from an audio file or
* raw PCM via stdin, separating it into channels and converting to chunks of
* floating-point samples.
* @throws if attempting to read beyond EOF
* @throws BeyondEofError if there is nothing to read
* @throws std::runtime_error for sndfile errors
*/
void MPXReader::init(const Options& options) {
num_channels_ = options.num_channels;
Expand Down Expand Up @@ -66,12 +67,10 @@ void MPXReader::init(const Options& options) {
if (sf_error(file_) == 26 || options.input_type == InputType::MPX_stdin)
throw BeyondEofError();

std::cerr << "error: failed to open file: " << sf_error_number(sf_error(file_)) << '\n';
is_error_ = true;
throw std::runtime_error(sf_error_number(sf_error(file_)));
} else if (sfinfo_.samplerate < static_cast<int>(kMinimumSampleRate_Hz)) {
std::cerr << "error: sample rate is " << sfinfo_.samplerate << ", must be "
<< kMinimumSampleRate_Hz << " Hz or higher\n";
is_error_ = true;
throw std::runtime_error("sample rate is " + std::to_string(sfinfo_.samplerate) + ", must be " +
std::to_string(kMinimumSampleRate_Hz) + " Hz or higher");
} else {
chunk_size_ = static_cast<sf_count_t>((kInputChunkSize / num_channels_) * num_channels_);

Expand Down Expand Up @@ -138,10 +137,6 @@ uint32_t MPXReader::getNumChannels() const {
return num_channels_;
}

bool MPXReader::hasError() const {
return is_error_;
}

/*
* An AsciiBitReader reads an unsynchronized serial bitstream as '0' and '1'
* characters via stdin.
Expand Down
2 changes: 0 additions & 2 deletions src/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class MPXReader {
~MPXReader();
void init(const Options& options);
bool eof() const;
bool hasError() const;
void fillBuffer();
MPXBuffer& readChunk(uint32_t channel);
float getSamplerate() const;
Expand All @@ -68,7 +67,6 @@ class MPXReader {
uint32_t num_channels_{};
sf_count_t chunk_size_{};
bool is_eof_{true};
bool is_error_{false};
bool feed_thru_{false};
std::string filename_;
MPXBuffer buffer_{};
Expand Down
6 changes: 3 additions & 3 deletions src/redsea.cc
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,14 @@ int processMPXInput(Options options) {
} catch (BeyondEofError&) {
printUsage();
return EXIT_FAILURE;
} catch (const std::exception& e) {
std::cerr << e.what() << "\n";
return EXIT_FAILURE;
}

options.samplerate = mpx.getSamplerate();
options.num_channels = mpx.getNumChannels();

if (mpx.hasError())
return EXIT_FAILURE;

auto& output_stream = options.feed_thru ? std::cerr : std::cout;

std::vector<std::unique_ptr<Channel>> channels;
Expand Down
49 changes: 49 additions & 0 deletions test/mpx.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <sstream>
#include <vector>

#include <catch2/catch_test_macros.hpp>
#include <nlohmann/json.hpp>

#include "../src/dsp/subcarrier.h"
#include "../src/input.h"
#include "../src/options.h"
#include "test_helpers.h"

TEST_CASE("MPX file input") {
redsea::Options options;

options.sndfilename = "../test/resources/mpx-testfile-yksi.flac";
options.input_type = redsea::InputType::MPX_sndfile;

std::vector<nlohmann::ordered_json> json;

redsea::MPXReader mpx;
mpx.init(options);
options.samplerate = mpx.getSamplerate();
options.num_channels = mpx.getNumChannels();

std::stringstream json_stream;
redsea::Channel channel(options, 0, json_stream);
redsea::Subcarrier subcarrier(options);

while (!mpx.eof()) {
mpx.fillBuffer();
const auto bits = subcarrier.processChunk(mpx.readChunk(0));

for (const auto& bit : bits.bits) {
channel.processBit(bit);
if (!json_stream.str().empty()) {
nlohmann::ordered_json jsonroot;
json_stream >> jsonroot;
json.push_back(jsonroot);

json_stream.str("");
json_stream.clear();
}
}
}

CHECK(json.size() == 1);
CHECK(json.at(0)["pi"] == "0x6201");
CHECK(json.at(0)["prog_type"] == "Serious classical");
}
3 changes: 3 additions & 0 deletions test/resources/mpx-testfile-yksi.flac
Git LFS file not shown

0 comments on commit e9386d1

Please sign in to comment.