diff --git a/Makefile b/Makefile index db231d9..8682093 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -CXXFLAGS = -std=c++14 +CXXFLAGS = -std=c++14 -I. LDFLAGS = -lm -gen_ft8: gen_ft8.o encode.o pack.o text.o pack_77.o encode_91.o +gen_ft8: gen_ft8.o ft8/encode.o ft8/pack.o ft8/text.o ft8/pack_77.o ft8/encode_91.o common/wave.o $(CXX) $(LDFLAGS) -o $@ $^ .PHONY: run_tests @@ -9,6 +9,6 @@ gen_ft8: gen_ft8.o encode.o pack.o text.o pack_77.o encode_91.o run_tests: test @./test -test: test.o encode.o pack.o text.o pack_77.o encode_91.o unpack.o +test: test.o ft8/encode.o ft8/pack.o ft8/text.o ft8/pack_77.o ft8/encode_91.o ft8/unpack.o $(CXX) $(LDFLAGS) -o $@ $^ diff --git a/debug.h b/common/debug.h similarity index 100% rename from debug.h rename to common/debug.h diff --git a/common/wave.cpp b/common/wave.cpp new file mode 100644 index 0000000..0f98408 --- /dev/null +++ b/common/wave.cpp @@ -0,0 +1,59 @@ +#include "wave.h" + +#include +#include +#include + +#include + + +// Save signal in floating point format (-1 .. +1) as a WAVE file using 16-bit signed integers. +void save_wav(const float *signal, int num_samples, int sample_rate, const char *path) { + FILE *f = fopen(path, "wb"); + char subChunk1ID[4] = {'f', 'm', 't', ' '}; + uint32_t subChunk1Size = 16; // 16 for PCM + uint16_t audioFormat = 1; // PCM = 1 + uint16_t numChannels = 1; + uint16_t bitsPerSample = 16; + uint32_t sampleRate = sample_rate; + uint16_t blockAlign = numChannels * bitsPerSample / 8; + uint32_t byteRate = sampleRate * blockAlign; + + char subChunk2ID[4] = {'d', 'a', 't', 'a'}; + uint32_t subChunk2Size = num_samples * blockAlign; + + char chunkID[4] = {'R', 'I', 'F', 'F'}; + uint32_t chunkSize = 4 + (8 + subChunk1Size) + (8 + subChunk2Size); + char format[4] = {'W', 'A', 'V', 'E'}; + + int16_t *raw_data = (int16_t *)malloc(num_samples * blockAlign); + for (int i = 0; i < num_samples; i++) { + float x = signal[i]; + if (x > 1.0) x = 1.0; + else if (x < -1.0) x = -1.0; + raw_data[i] = int(0.5 + (x * 32767.0)); + } + + // NOTE: works only on little-endian architecture + fwrite(chunkID, sizeof(chunkID), 1, f); + fwrite(&chunkSize, sizeof(chunkSize), 1, f); + fwrite(format, sizeof(format), 1, f); + + fwrite(subChunk1ID, sizeof(subChunk1ID), 1, f); + fwrite(&subChunk1Size, sizeof(subChunk1Size), 1, f); + fwrite(&audioFormat, sizeof(audioFormat), 1, f); + fwrite(&numChannels, sizeof(numChannels), 1, f); + fwrite(&sampleRate, sizeof(sampleRate), 1, f); + fwrite(&byteRate, sizeof(byteRate), 1, f); + fwrite(&blockAlign, sizeof(blockAlign), 1, f); + fwrite(&bitsPerSample, sizeof(bitsPerSample), 1, f); + + fwrite(subChunk2ID, sizeof(subChunk2ID), 1, f); + fwrite(&subChunk2Size, sizeof(subChunk2Size), 1, f); + + fwrite(raw_data, blockAlign, num_samples, f); + + fclose(f); + + free(raw_data); +} diff --git a/common/wave.h b/common/wave.h new file mode 100644 index 0000000..88906e1 --- /dev/null +++ b/common/wave.h @@ -0,0 +1,9 @@ +#pragma once + + +// Save signal in floating point format (-1 .. +1) as a WAVE file using 16-bit signed integers. +void save_wav(const float *signal, int num_samples, int sample_rate, const char *path); + + +// Load signal in floating point format (-1 .. +1) as a WAVE file using 16-bit signed integers. +void load_wav(float *signal, int &num_samples, int &sample_rate, const char *path); diff --git a/encode.cpp b/ft8/encode.cpp similarity index 100% rename from encode.cpp rename to ft8/encode.cpp diff --git a/encode.h b/ft8/encode.h similarity index 100% rename from encode.h rename to ft8/encode.h diff --git a/encode_91.cpp b/ft8/encode_91.cpp similarity index 100% rename from encode_91.cpp rename to ft8/encode_91.cpp diff --git a/encode_91.h b/ft8/encode_91.h similarity index 100% rename from encode_91.h rename to ft8/encode_91.h diff --git a/pack.cpp b/ft8/pack.cpp similarity index 100% rename from pack.cpp rename to ft8/pack.cpp diff --git a/pack.h b/ft8/pack.h similarity index 100% rename from pack.h rename to ft8/pack.h diff --git a/pack_77.cpp b/ft8/pack_77.cpp similarity index 100% rename from pack_77.cpp rename to ft8/pack_77.cpp diff --git a/pack_77.h b/ft8/pack_77.h similarity index 100% rename from pack_77.h rename to ft8/pack_77.h diff --git a/text.cpp b/ft8/text.cpp similarity index 100% rename from text.cpp rename to ft8/text.cpp diff --git a/text.h b/ft8/text.h similarity index 100% rename from text.h rename to ft8/text.h diff --git a/unpack.cpp b/ft8/unpack.cpp similarity index 100% rename from unpack.cpp rename to ft8/unpack.cpp diff --git a/unpack.h b/ft8/unpack.h similarity index 100% rename from unpack.h rename to ft8/unpack.h diff --git a/gen_ft8.cpp b/gen_ft8.cpp index 791b8d9..01741a1 100644 --- a/gen_ft8.cpp +++ b/gen_ft8.cpp @@ -3,15 +3,15 @@ #include #include -#include "pack.h" -#include "encode.h" - -#include "pack_77.h" -#include "encode_91.h" +#include "common/wave.h" +#include "ft8/pack.h" +#include "ft8/encode.h" +#include "ft8/pack_77.h" +#include "ft8/encode_91.h" // Convert a sequence of symbols (tones) into a sinewave of continuous phase (FSK). -// Symbol 0 gets encoded as a sine of frequency f0, the others are spaced in incresing +// Symbol 0 gets encoded as a sine of frequency f0, the others are spaced in increasing // fashion. void synth_fsk(const uint8_t *symbols, int num_symbols, float f0, float spacing, float symbol_rate, float signal_rate, float *signal) { @@ -35,57 +35,6 @@ void synth_fsk(const uint8_t *symbols, int num_symbols, float f0, float spacing, } } -// Save signal in floating point format (-1 .. +1) as a WAVE file using 16-bit signed integers. -void save_wav(const float *signal, int num_samples, int sample_rate, const char *path) { - FILE *f = fopen(path, "wb"); - char subChunk1ID[4] = {'f', 'm', 't', ' '}; - uint32_t subChunk1Size = 16; // 16 for PCM - uint16_t audioFormat = 1; // PCM = 1 - uint16_t numChannels = 1; - uint16_t bitsPerSample = 16; - uint32_t sampleRate = sample_rate; - uint16_t blockAlign = numChannels * bitsPerSample / 8; - uint32_t byteRate = sampleRate * blockAlign; - - char subChunk2ID[4] = {'d', 'a', 't', 'a'}; - uint32_t subChunk2Size = num_samples * blockAlign; - - char chunkID[4] = {'R', 'I', 'F', 'F'}; - uint32_t chunkSize = 4 + (8 + subChunk1Size) + (8 + subChunk2Size); - char format[4] = {'W', 'A', 'V', 'E'}; - - int16_t *raw_data = (int16_t *)malloc(num_samples * blockAlign); - for (int i = 0; i < num_samples; i++) { - float x = signal[i]; - if (x > 1.0) x = 1.0; - else if (x < -1.0) x = -1.0; - raw_data[i] = int(0.5 + (x * 32767.0)); - } - - // NOTE: works only on little-endian architecture - fwrite(chunkID, sizeof(chunkID), 1, f); - fwrite(&chunkSize, sizeof(chunkSize), 1, f); - fwrite(format, sizeof(format), 1, f); - - fwrite(subChunk1ID, sizeof(subChunk1ID), 1, f); - fwrite(&subChunk1Size, sizeof(subChunk1Size), 1, f); - fwrite(&audioFormat, sizeof(audioFormat), 1, f); - fwrite(&numChannels, sizeof(numChannels), 1, f); - fwrite(&sampleRate, sizeof(sampleRate), 1, f); - fwrite(&byteRate, sizeof(byteRate), 1, f); - fwrite(&blockAlign, sizeof(blockAlign), 1, f); - fwrite(&bitsPerSample, sizeof(bitsPerSample), 1, f); - - fwrite(subChunk2ID, sizeof(subChunk2ID), 1, f); - fwrite(&subChunk2Size, sizeof(subChunk2Size), 1, f); - - fwrite(raw_data, blockAlign, num_samples, f); - - fclose(f); - - free(raw_data); -} - void usage() { printf("Generate a 15-second WAV file encoding a given message.\n"); diff --git a/test.cpp b/test.cpp index 8d64252..0a32a99 100644 --- a/test.cpp +++ b/test.cpp @@ -3,14 +3,14 @@ #include #include -#include "text.h" -#include "pack.h" -#include "pack_77.h" -#include "encode.h" -#include "encode_91.h" -#include "unpack.h" +#include "ft8/text.h" +#include "ft8/pack.h" +#include "ft8/pack_77.h" +#include "ft8/encode.h" +#include "ft8/encode_91.h" +#include "ft8/unpack.h" -#include "debug.h" +#include "common/debug.h" #define LOG_LEVEL LOG_INFO