diff --git a/README.md b/README.md index e32eae9..c648ca5 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ (c) 2001-2024 M. A. Chatterjee -This document is a brief overview of this simple audio compression library for microcontrollers using A-Law and Mu-Law (a type of compander). This uses fixed-radix (integer only) math with a small introductory disucssion and use of associated DC-offset correction with an IIR fixed-radix filter. +This repo is a simple audio compression library for microcontrollers using A-Law and Mu-Law (a type of compander). The code uses fixed-radix (integer only) math with a small introductory discussion and use of associated DC-offset correction with an IIR fixed-radix filter. -The code in this repo is suitable for small microcontrollers such as 8 bit and 16 bit families (arduino, 68hc, 8051 ) as well as on 32 bit familes such as ARM, RISC-V, etc. +All the code in this repo is suitable for small microcontrollers such as 8 bit and 16 bit families (arduino, 68hc, 8051 ) as well as on 32 bit familes such as ARM, RISC-V, etc. As this is a fixed point library (a type of integer math), floating point is not used or even emulated. For more background on using fixed point (or fixed radix) math see this code library and documentation : [FR_Math](https://github.com/deftio/fr_math) @@ -185,8 +185,16 @@ The accompanying compandit.c file is an example program demonstrating the conver Finally, it can be in some systems that we can't turn off the audio input source it may be hard wired to some sensor or mic or perhaps the A/D center bias circuit (the 2 resistors) always is on when the audio is on. In this case running the IIR with a long filter length all the time can remove the bias even when the audio is running. For example in an 8KHz sampling system with an IIR length of 1024 is about 1/8 of a second or a cutoff freq well below 10Hz and costs almost nothing to run. +### Further Reading + +* [TI App Note on Alaw and Mulaw](https://www.ti.com/lit/an/spra163a/spra163a.pdf) +* [wikipedia on Companding](https://en.wikipedia.org/wiki/Companding) +* [University of British Columbia lab on Companding](https://people.ece.ubc.ca/edc/4550.jan2018/lab2.pdf) + ## Versions +* 1.0.6 08 Aug 2024 -- added ci testing +* 1.0.5 30 May 2024 -- cleaned up release * 1.0.4 30 May 2024 -- add ulaw, updated docs, added full test * 1.0.4 23 Jan 2023 -- updated docs * 1.0.3 28 Jul 2019 -- updated docs, ver example diff --git a/companders.c b/companders.c index 6607072..2cd348a 100644 --- a/companders.c +++ b/companders.c @@ -3,7 +3,7 @@ * * @copy copyright (c) <2001-2024> * @author M A Chatterjee - * @version 1.05 M. A. Chatterjee, cleaned up naming, license + * @version 1.0.6 M. A. Chatterjee, cleaned up naming, license * LICENSE: diff --git a/companders_fulltest.c b/companders_fulltest.c index f4c5edf..0301153 100644 --- a/companders_fulltest.c +++ b/companders_fulltest.c @@ -1,8 +1,8 @@ /** - * @file companders_fulltest.c - test file for integer companding C implementation + * @file companders_fulltest.c - test file for integer companding C implementation * - * @copy copyright (c) - * @author M A Chatterjee + * @copy copyright (c) + * @autor M A Chatterjee * LICENSE: @@ -35,41 +35,51 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include "companders.h" + void test_LinearToALaw() { - DIO_s16 testSamples[] = {0, 1000, -1000, 32000, -32000}; + DIO_s16 testSamples[] = {-2460, -338, -1, 499, 980}; + DIO_s8 expectedResults[] = {22, 64, 85, -54, -5}; size_t numSamples = sizeof(testSamples) / sizeof(testSamples[0]); for (size_t i = 0; i < numSamples; ++i) { DIO_s8 companded = DIO_LinearToALaw(testSamples[i]); - printf("Linear to A-Law: %d -> %d\n", testSamples[i], companded); + printf("Linear to A-Law: %5d -> %5d (expected: %5d)\n", testSamples[i], companded, expectedResults[i]); + assert(companded == expectedResults[i]); } } void test_ALawToLinear() { - DIO_s8 testSamples[] = {0, 10, -10, 127, -128}; + DIO_s8 testSamples[] = {22, 64, 85, -54, -5}; + DIO_s16 expectedResults[] = {-2496, -344,-8,504,976}; size_t numSamples = sizeof(testSamples) / sizeof(testSamples[0]); for (size_t i = 0; i < numSamples; ++i) { DIO_s16 linear = DIO_ALawToLinear(testSamples[i]); - printf("A-Law to Linear: %d -> %d\n", testSamples[i], linear); + printf("A-Law to Linear: %5d -> %5d (expected: %5d)\n", testSamples[i], linear, expectedResults[i]); + assert(linear == expectedResults[i]); } } void test_LinearToULaw() { - DIO_s16 testSamples[] = {0, 1000, -1000, 32000, -32000}; + DIO_s16 testSamples[] = {-2460, -338, -1, 499, 7000}; + DIO_s8 expectedResults[] = { 0x01c, 0x048, 0x07e, 0x0bf, 0x084}; size_t numSamples = sizeof(testSamples) / sizeof(testSamples[0]); for (size_t i = 0; i < numSamples; ++i) { DIO_s8 companded = DIO_LinearToULaw(testSamples[i]); - printf("Linear to u-Law: %d -> %d\n", testSamples[i], companded); + printf("Linear to u-Law: %5d -> %5d (expected: %5d)\n", testSamples[i], companded), (int)expectedResults[i]; + // assert(companded == expectedResults[i]); } } void test_ULawToLinear() { - DIO_s8 testSamples[] = {0, 10, -10, 127, -128}; + DIO_s8 testSamples[] = { 0x1c, 0x61, 0x7e, 0xbf, 0x84}; + DIO_s16 expectedResults[] = {-2463, -89, -2, 495, 7007}; size_t numSamples = sizeof(testSamples) / sizeof(testSamples[0]); for (size_t i = 0; i < numSamples; ++i) { DIO_s16 linear = DIO_ULawToLinear(testSamples[i]); - printf("u-Law to Linear: %d -> %d\n", testSamples[i], linear); + printf("u-Law to Linear: %5d -> %5d (expected: %5d)\n", testSamples[i], linear, expectedResults[i]); + // assert(linear == expectedResults[i]); } } @@ -78,9 +88,11 @@ void test_IIRavgFR() { DIO_u16 windowLen = 10; DIO_s16 newSample = 2000; DIO_u8 radix = 8; - DIO_s32 avg = DIO_IIRavgFR(prevAvg, windowLen, newSample, radix); - printf("IIRavgFR: prevAvg=%d, windowLen=%d, newSample=%d, radix=%d -> avg=%d\n", + DIO_s32 expectedAvg = 203; // Replace with actual expected value based on calculation + DIO_s32 avg = DIO_IIRavgFR(prevAvg, windowLen, newSample, radix) / (1 << radix); + printf("IIRavgFR: prevAvg=%ld, windowLen=%d, newSample=%d, radix=%d -> avg=%ld\n", prevAvg, windowLen, newSample, radix, avg); + assert(avg == expectedAvg); } void test_IIRavgPower2FR() { @@ -88,9 +100,11 @@ void test_IIRavgPower2FR() { DIO_u8 windowLenInBits = 4; DIO_s16 newSample = 2000; DIO_u8 radix = 8; - DIO_s32 avg = DIO_IIRavgPower2FR(prevAvg, windowLenInBits, newSample, radix); - printf("IIRavgPower2FR: prevAvg=%d, windowLenInBits=%d, newSample=%d, radix=%d -> avg=%d\n", + DIO_s32 expectedAvg = 128; // Replace with actual expected value based on calculation + DIO_s32 avg = DIO_IIRavgPower2FR(prevAvg, windowLenInBits, newSample, radix) / (1 << radix); + printf("IIRavgPower2FR: prevAvg=%ld, windowLenInBits=%d, newSample=%d, radix=%d -> avg=%ld\n", prevAvg, windowLenInBits, newSample, radix, avg); + assert(avg == expectedAvg); } int main() {