|  | #include "FFTCrossFader.h"
#include "ColoredNoise.h"
#include "asserts.h"
#include <vector>
class Tester
{
public:
    Tester(int crossFadeSize, int frameSize) :
        f(crossFadeSize)
    {
        for (int i = 0; i < 3; ++i) {
            std::shared_ptr<NoiseMessage> p = std::make_shared<NoiseMessage>(frameSize);
            messages.push_back(p);
        }
    }
    FFTCrossFader f;
    std::vector< std::shared_ptr<NoiseMessage> > messages;
};
// accepting data on empty should not return on
static void test0()
{
    Tester test(4, 10);
    assertEQ(test.messages[0]->dataBuffer->get(0), 0);
    assertEQ(test.messages[0]->dataBuffer->get(9), 0);
    NoiseMessage* t = test.f.acceptData(test.messages[0].get());
    assertEQ(t, 0);
}
//empty should return 0
static void test1()
{
    Tester test(4, 10);
    for (int i = 0; i < 20; ++i) {
        float x = 5;
        test.f.step(&x);
        assertEQ(x, 0);
    }
}
// one buff, should play it
static void test2()
{
    Tester test(4, 10);
    for (int i = 0; i < 10; ++i) {
        test.messages[0]->dataBuffer->set(i, float(i));
    }
    NoiseMessage* t = test.f.acceptData(test.messages[0].get());
    assertEQ(t, 0);
    // pluy buffer once
    for (int i = 0; i < 10; ++i) {
        float x = 5;
        test.f.step(&x);
        assertEQ(x, i);
    }
    //play it again.
    for (int i = 0; i < 10; ++i) {
        float x = 5;
        test.f.step(&x);
        assertEQ(x, i);
    }
}
// two buff, should crossfade
static void test3(bool testBuff0)
{
    Tester test(4, 10);
    // fill the buff to test with data, other one with zeros
    for (int i = 0; i < 10; ++i) {
        test.messages[0]->dataBuffer->set(i, testBuff0 ? 9.f : 0.f);
        test.messages[1]->dataBuffer->set(i, testBuff0 ? 0.f : 18.f);
    }
    // put both in, to cross fade
    NoiseMessage* t = test.f.acceptData(test.messages[0].get());
    assertEQ(t, 0);
    t = test.f.acceptData(test.messages[1].get());
    assertEQ(t, 0);
    int emptyCount = 0;
    // play buffer once
    // buffer 0 full of 9, so should see fade 9..0
    float expected0[] = {9, 6, 3, 0, 0, 0, 0, 0, 0, 0};
    // buffer 0 all zero, 1 all 18, so should see 0..18
    float expected1[] = {0, 6, 12, 18, 18, 18, 18, 18, 18, 18};
    for (int i = 0; i < 10; ++i) {
        float x = 5;
        t = test.f.step(&x);
        if (t) {
            ++emptyCount;
        }
        const float expected = testBuff0 ? expected0[i] : expected1[i];
        assertEQ(x, expected);
    }
    //play it again.
    for (int i = 0; i < 10; ++i) {
        float x = 5;
       // test.f.step(&x);
        t = test.f.step(&x);
        if (t) {
            ++emptyCount;
        }
        const float expectedTail = testBuff0 ? 0.f : 18.f;
        assertEQ(x, expectedTail);
    }
    assertEQ(emptyCount, 1);
}
// two buff, should crossfade. odd size crossfade
static void test7(bool testBuff0)
{
    Tester test(5, 10);
    // fill the buff to test with data, other one with zeros
    for (int i = 0; i < 10; ++i) {
        test.messages[0]->dataBuffer->set(i, testBuff0 ? 12.f : 0.f);
        test.messages[1]->dataBuffer->set(i, testBuff0 ? 0.f : 24.f);
    }
    // put both in, to cross fade
    NoiseMessage* t = test.f.acceptData(test.messages[0].get());
    assertEQ(t, 0);
    t = test.f.acceptData(test.messages[1].get());
    assertEQ(t, 0);
    int emptyCount = 0;
    // play buffer once
    float expected0[] = {12, 9, 6, 3, 0, 0, 0, 0, 0, 0};
    float expected1[] = {0, 6, 12, 18, 24, 24, 24, 24, 24, 24};
    for (int i = 0; i < 10; ++i) {
        float x = 5;
        t = test.f.step(&x);
        if (t) {
            ++emptyCount;
        }
        const float expected = testBuff0 ? expected0[i] : expected1[i];
        assertEQ(x, expected);
    }
    //play it again.
    for (int i = 0; i < 10; ++i) {
        float x = 5;
        // test.f.step(&x);
        t = test.f.step(&x);
        if (t) {
            ++emptyCount;
        }
        const float expectedTail = testBuff0 ? 0.f : 24.f;
        assertEQ(x, expectedTail);
    }
    assertEQ(emptyCount, 1);
}
// extra buffer rejected
static void test4()
{
    Tester test(4, 10);
    NoiseMessage* t = test.f.acceptData(test.messages[0].get());
    assertEQ(t, 0);
    t = test.f.acceptData(test.messages[1].get());
    assertEQ(t, 0);
    t = test.f.acceptData(test.messages[2].get());
    assertNE(t, 0);
}
// test wrap-around case
static void test5()
{
    // fade of 4, buffer of 8
    Tester test(4, 8);
    // fill the buff to test with data, other one with zeros
    for (int i = 0; i < 8; ++i) {
        test.messages[0]->dataBuffer->set(i, 0.f);
        test.messages[1]->dataBuffer->set(i, float(i));
    }
    // put zero 0
    NoiseMessage* t = test.f.acceptData(test.messages[0].get());
    float x;
    // clock 6
    for (int i = 0; i < 6; ++i) {
        x = 5;
        t = test.f.step(&x);
        assertEQ(x, 0);         // 0
        assertEQ(t, 0);
    }
    // now start crossfade
    t = test.f.acceptData(test.messages[1].get());
    assertEQ(t, 0);
    // sample #6. start fade
    t = test.f.step(&x);
    assertEQ(x, 0);         // 0
    assertEQ(t, 0);
    // sample #7.  fade #2
    t = test.f.step(&x);
    assertClose(x, .3333333f, .0001);         // 0
    assertEQ(t, 0);
    // sample#8, fade #3
    t = test.f.step(&x);
    assertClose(x, 1.3333333f, .0001);         // 0
    assertEQ(t, 0);
    // sample#8, fade #4 (last), buff 0 (?) gets returned
    t = test.f.step(&x);
    assertClose(x, 3.f, .0001);         // 0
    assertNE(t, 0);
    // done fading
    t = test.f.step(&x);
    assertClose(x, 4.f, .0001);         // 0
    assertEQ(t, 0);
    t = test.f.step(&x);
    assertClose(x, 5.f, .0001);         // 0
    assertEQ(t, 0);
    t = test.f.step(&x);
    assertClose(x, 6.f, .0001);         // 0
    assertEQ(t, 0);
    t = test.f.step(&x);
    assertClose(x, 7.f, .0001);         // 0
    assertEQ(t, 0);
    t = test.f.step(&x);
    assertClose(x, 0.f, .0001);         // 0
    assertEQ(t, 0);
}
// test makeup gain
static void test6(bool makeup)
{
    // fade of 5, buffer of 8
    Tester test(5, 8);
    test.f.enableMakeupGain(makeup);
    // fill the buffers with 1
    for (int i = 0; i < 8; ++i) {
        test.messages[0]->dataBuffer->set(i, 1.f);
        test.messages[1]->dataBuffer->set(i, 1.f);
    }
    // put messages
    test.f.acceptData(test.messages[0].get());
    test.f.acceptData(test.messages[1].get());
    float x;
    for (int i = 0; i < 5; ++i) {
        x = 5;
        test.f.step(&x);
        float expected = 1;
        if (makeup) switch (i) {
            case 0:
            case 4:
                expected = 1;
                break;
            case 2:
                expected = std::sqrt(2.f);
                break;
            case 1:
            case 3:
                expected = (1.f + std::sqrt(2.f)) / 2.f;
                break;
            default: assert(false);
        }
        assertClose(x, expected, .0001);
    }
}
void testFFTCrossFader()
{
    assertEQ(FFTDataReal::_count, 0);
    test0();
    test1();
    test2();
    test3(true);
    test3(false);
    test7(true);
    test7(false);
    test4();
    test5();
    test6(false);
    test6(true);
    assertEQ(FFTDataReal::_count, 0);
}
 |