#include "PixTone.h"
struct PIXTONEPARAMETER2
{
	int model;
	double num;
	int top;
	int offset;
};
struct PIXTONEPARAMETER
{
	int use;
	int size;
	PIXTONEPARAMETER2 oMain;
	PIXTONEPARAMETER2 oPitch;
    PIXTONEPARAMETER2 oPitch2;//增加Pitch2
	PIXTONEPARAMETER2 oVolume;
	int initial;
	int pointAx;
	int pointAy;
	int pointBx;
	int pointBy;
	int pointCx;
	int pointCy;
};

PixTone::PixTone()
{
    MakeWaveTables();
}

Mix_Chunk* PixTone::LoadPixTone(const wchar_t* filename)
{
    PIXTONEPARAMETER pixtone_parameters[4];
    if (LoadPixToneFile(filename, pixtone_parameters))
    {
        int ptp_num = 0;
        for (auto& param : pixtone_parameters)
            if (param.use)
                ptp_num++;
        return MakePixToneChunk_SDL(pixtone_parameters, ptp_num);
    }
    return nullptr;
}

void PixTone::MakeWaveTables()
{
    int i, a;

    // Sine wave
    for (i = 0; i < 256; ++i)
    {
        gWaveModelTable[0][i] = (signed char)(sin(i * 6.283184 / 256.0) * 64.0);
        a = gWaveModelTable[0][i];
    }

    // Triangle wave
    for (a = 0, i = 0; i < 0x40; ++i)
    {
        // Upwards
        gWaveModelTable[1][i] = (a * 0x40) / 0x40;
        ++a;
    }
    for (a = 0; i < 0xC0; ++i)
    {
        // Downwards
        gWaveModelTable[1][i] = 0x40 - (a * 0x40) / 0x40;
        ++a;
    }
    for (a = 0; i < 0x100; ++i)
    {
        // Back up
        gWaveModelTable[1][i] = (a * 0x40) / 0x40 - 0x40;
        ++a;
    }

    // Saw up wave
    for (i = 0; i < 0x100; ++i)
        gWaveModelTable[2][i] = i / 2 - 0x40;

    // Saw down wave
    for (i = 0; i < 0x100; ++i)
        gWaveModelTable[3][i] = 0x40 - i / 2;

    // Square wave
    for (i = 0; i < 0x80; ++i)
        gWaveModelTable[4][i] = 0x40;
    for (; i < 0x100; ++i)
        gWaveModelTable[4][i] = -0x40;

    // White noise wave
    srand(0);
    for (i = 0; i < 256; ++i)
        gWaveModelTable[5][i] = (signed char)(rand() & 0xFF) / 2;
}

BOOL PixTone::MakePixelWaveData(const PIXTONEPARAMETER* ptp, unsigned char* pData)
{
    constexpr int   PHASE_MASK = 0xFF;
    constexpr double WAVE_NORM = 64.0;

    // -------------------------------------------------
    // Envelope table (0..255)
    // -------------------------------------------------
    signed char envelope[256] = {};

    auto FillEnvelope = [&](int from, int to, double& v, double target)
    {
        if (to <= from) return;
        const double step = (target - v) / (to - from);
        for (int i = from; i < to; ++i)
        {
            envelope[i] = (signed char)v;
            v += step;
        }
    };

    double env = ptp->initial;
    FillEnvelope(0, ptp->pointAx, env, ptp->pointAy);
    FillEnvelope(ptp->pointAx, ptp->pointBx, env, ptp->pointBy);
    FillEnvelope(ptp->pointBx, ptp->pointCx, env, ptp->pointCy);

    // release
    FillEnvelope(ptp->pointCx, 256, env, 0.0);

    // -------------------------------------------------
    // Phase & step helpers
    // -------------------------------------------------
    auto CalcStep = [&](double freq)
    {
        return (freq == 0.0) ? 0.0 : 256.0 / (ptp->size / freq);
    };

    double mainPhase = ptp->oMain.offset;
    double pitchPhase1 = ptp->oPitch.offset;
    double pitchPhase2 = ptp->oPitch2.offset;
    double volumePhase = ptp->oVolume.offset;

    const double mainStep = CalcStep(ptp->oMain.num);
    const double pitchStep1 = CalcStep(ptp->oPitch.num);
    const double pitchStep2 = CalcStep(ptp->oPitch2.num);
    const double volumeStep = CalcStep(ptp->oVolume.num);

    // -------------------------------------------------
    // Wave generation
    // -------------------------------------------------
    for (int i = 0; i < ptp->size; ++i)
    {
        const int mainIdx = (int)mainPhase & PHASE_MASK;
        const int pitchIdx1 = (int)pitchPhase1 & PHASE_MASK;
        const int pitchIdx2 = (int)pitchPhase2 & PHASE_MASK;
        const int volIdx = (int)volumePhase & PHASE_MASK;
        const int envIdx = (i * 256) / ptp->size;

        // ---- sample ----
        pData[i] =
            (BYTE)(gWaveModelTable[ptp->oMain.model][mainIdx]
            * ptp->oMain.top / WAVE_NORM
            * (gWaveModelTable[ptp->oVolume.model][volIdx] * ptp->oVolume.top / WAVE_NORM + WAVE_NORM)
            / WAVE_NORM
            * envelope[envIdx]
            / WAVE_NORM
            + 128);

        // ---- pitch wave (Pitch1 + Pitch2) ----
        double pitchWave =
            gWaveModelTable[ptp->oPitch.model][pitchIdx1] * ptp->oPitch.top +
            gWaveModelTable[ptp->oPitch2.model][pitchIdx2] * ptp->oPitch2.top;

        pitchWave /= WAVE_NORM;

        // ---- PixTone asymmetric modulation ----
        if (pitchWave < 0.0)
            mainPhase += mainStep - mainStep * 0.5 * (-pitchWave) / WAVE_NORM;
        else
            mainPhase += mainStep + mainStep * 2.0 * pitchWave / WAVE_NORM;

        pitchPhase1 += pitchStep1;
        pitchPhase2 += pitchStep2;
        volumePhase += volumeStep;
    }

    return TRUE;
}

Mix_Chunk* PixTone::MakePixToneChunk_SDL(const PIXTONEPARAMETER* ptp, int ptp_num)
{
#pragma pack(push, 1)
    struct WavHeader
    {
        char   riff[4];          // "RIFF"
        Uint32 wav_size;         // file size - 8
        char   wave[4];          // "WAVE"
        char   fmt[4];           // "fmt "
        Uint32 fmt_chunk_size;   // 16
        Uint16 audio_format;     // 1 = PCM
        Uint16 num_channels;     // 1
        Uint32 sample_rate;      // 22050
        Uint32 byte_rate;
        Uint16 sample_alignment;
        Uint16 bit_depth;        // 8
        char   data[4];          // "data"
        Uint32 data_bytes;
    };
#pragma pack(pop)

    if (!ptp || ptp_num <= 0)
        return nullptr;

    // -------------------------------------------------
    // 计算 sample_count（和原实现一致）
    // -------------------------------------------------
    int sample_count = 0;
    for (int i = 0; i < 4; ++i)
    {
        auto& param = ptp[i];
        if (param.use == 0)
            continue;
        if (param.size > sample_count)
            sample_count = param.size;
    }
    if (sample_count <= 0)
        return nullptr;

    // -------------------------------------------------
    // PixTone 工作缓冲（vector 管理）
    // -------------------------------------------------
    std::vector<Uint8> pcm_buffer(sample_count, 0x80);
    std::vector<Uint8> mixed_pcm_buffer(sample_count, 0x80);

    // -------------------------------------------------
    // PixTone 合成（逻辑完全不变）
    // -------------------------------------------------
    for (int i = 0; i < 4; i++)
    {
        auto& param = ptp[i];
        if (param.use == 0)
            continue;
        if (!MakePixelWaveData(&param, pcm_buffer.data()))
            return nullptr;

        for (int j = 0; j < param.size; ++j)
        {
            int v = pcm_buffer[j] + mixed_pcm_buffer[j] - 0x100;
            if (v < -0x7F)
                mixed_pcm_buffer[j] = 0x00;
            else if (v > 0x7F)
                mixed_pcm_buffer[j] = 0xFF;
            else
                mixed_pcm_buffer[j] = static_cast<Uint8>(v + 0x80);
        }
    }

    // 原始代码里的“防爆音占位”
    mixed_pcm_buffer.front() = mixed_pcm_buffer.front();
    mixed_pcm_buffer.back() = mixed_pcm_buffer.back();

    // -------------------------------------------------
    // 构造 WAV 内存（vector）
    // -------------------------------------------------
    const Uint32 wav_size = static_cast<Uint32>(sizeof(WavHeader) + sample_count);

    std::vector<Uint8> wav_buffer(wav_size);

    WavHeader* h = reinterpret_cast<WavHeader*>(wav_buffer.data());
    h->bit_depth = 8;
    h->sample_rate = 22050;
    h->num_channels = 1;
    h->audio_format = 1;        // PCM
    h->fmt_chunk_size = 16;
    memcpy(h->riff, "RIFF", 4);
    memcpy(h->fmt, "fmt ", 4);
    memcpy(h->wave, "WAVE", 4);
    memcpy(h->data, "data", 4);
    h->sample_alignment = h->bit_depth / 8 * h->num_channels;
    h->byte_rate = h->sample_alignment * h->sample_rate;
    h->data_bytes = sample_count;
    h->wav_size = wav_size - 8;

    memcpy(
        wav_buffer.data() + sizeof(WavHeader),
        mixed_pcm_buffer.data(),
        sample_count
    );

    // -------------------------------------------------
    // SDL_mixer 加载（SDL 完全托管）
    // -------------------------------------------------
    SDL_RWops* rw = SDL_RWFromConstMem(wav_buffer.data(), wav_size);
    Mix_Chunk* chunk = Mix_LoadWAV_RW(rw, 1); // 1 = 自动释放 RWops
    return chunk; // vector 自动析构，无需手动释放
}

BOOL PixTone::LoadPixToneFile(const wchar_t* filename, PIXTONEPARAMETER* pixtone_parameters)
{
    if (!filename || !pixtone_parameters)
        return FALSE;

    FILE* fp = nullptr;
    if (_wfopen_s(&fp, filename, L"rb") != 0 || fp == nullptr)
        return FALSE;

    // -------------------------------------------------
    // 读取整个文件到 vector
    // -------------------------------------------------
    fseek(fp, 0, SEEK_END);
    const size_t file_size = static_cast<size_t>(ftell(fp));
    rewind(fp);

    if (file_size == 0)
    {
        fclose(fp);
        return FALSE;
    }

    std::vector<char> file_buffer(file_size + 1); // +1 方便安全
    fread(file_buffer.data(), 1, file_size, fp);
    fclose(fp);

    file_buffer[file_size] = '\0'; // 保证结尾

    char* p = file_buffer.data();

    // -------------------------------------------------
    // 解析 PixTone 参数（逻辑不变）
    // -------------------------------------------------
    ZeroMemory(pixtone_parameters, sizeof(PIXTONEPARAMETER) * 4);
    for (unsigned int i = 0; i < 4; ++i)
    {
        float freq = 0.0f;
        int increment = 0;
        sscanf_s(p, "use  :%d\n%n", &pixtone_parameters[i].use, &increment);
        p += increment;
        sscanf_s(p, "size :%d\n%n", &pixtone_parameters[i].size, &increment);
        p += increment;
        sscanf_s(p, "main_model   :%d\n%n", &pixtone_parameters[i].oMain.model, &increment);
        p += increment;
        sscanf_s(p, "main_freq    :%f\n%n", &freq, &increment);
        p += increment;
        pixtone_parameters[i].oMain.num = freq;
        sscanf_s(p, "main_top     :%d\n%n", &pixtone_parameters[i].oMain.top, &increment);
        p += increment;
        sscanf_s(p, "main_offset  :%d\n%n", &pixtone_parameters[i].oMain.offset, &increment);
        p += increment;
        sscanf_s(p, "pitch_model  :%d\n%n", &pixtone_parameters[i].oPitch.model, &increment);
        p += increment;
        sscanf_s(p, "pitch_freq   :%f\n%n", &freq, &increment);
        p += increment;
        pixtone_parameters[i].oPitch.num = freq;
        sscanf_s(p, "pitch_top    :%d\n%n", &pixtone_parameters[i].oPitch.top, &increment);
        p += increment;
        sscanf_s(p, "pitch_offset :%d\n%n", &pixtone_parameters[i].oPitch.offset, &increment);
        p += increment;
        sscanf_s(p, "volume_model :%d\n%n", &pixtone_parameters[i].oVolume.model, &increment);
        p += increment;
        sscanf_s(p, "volume_freq  :%f\n%n", &freq, &increment);
        p += increment;
        pixtone_parameters[i].oVolume.num = freq;
        sscanf_s(p, "volume_top   :%d\n%n", &pixtone_parameters[i].oVolume.top, &increment);
        p += increment;
        sscanf_s(p, "volume_offset:%d\n%n", &pixtone_parameters[i].oVolume.offset, &increment);
        p += increment;
        sscanf_s(p, "initialY:%d\n%n", &pixtone_parameters[i].initial, &increment);
        p += increment;
        sscanf_s(p, "ax      :%d\n%n", &pixtone_parameters[i].pointAx, &increment);
        p += increment;
        sscanf_s(p, "ay      :%d\n%n", &pixtone_parameters[i].pointAy, &increment);
        p += increment;
        sscanf_s(p, "bx      :%d\n%n", &pixtone_parameters[i].pointBx, &increment);
        p += increment;
        sscanf_s(p, "by      :%d\n%n", &pixtone_parameters[i].pointBy, &increment);
        p += increment;
        sscanf_s(p, "cx      :%d\n%n", &pixtone_parameters[i].pointCx, &increment);
        p += increment;
        sscanf_s(p, "cy      :%d\n\n%n", &pixtone_parameters[i].pointCy, &increment);
        p += increment;
    }
    //解析PITCH2参数
    const char* scan = file_buffer.data();

    while (*scan)
    {
        if (scan[0] == '-' && scan[1] == '>')
        {
            ParsePitch2Line(scan, pixtone_parameters);
            break; // 只取第一组 -> {}
        }
        while (*scan && *scan != '\n')
            scan++;
        if (*scan == '\n')
            scan++;
    }
    return TRUE;
}

bool PixTone::ParsePitch2Line(const char* line, PIXTONEPARAMETER* tracks)
{
    // 临时数组
    PIXTONEPARAMETER2 arg[4];
    int parsed = sscanf_s(
        line,
        "-> {%d,%lf,%d,%d,%d,%lf,%d,%d,%d,%lf,%d,%d,%d,%lf,%d,%d",
        &arg[0].model, &arg[0].num, &arg[0].top, &arg[0].offset,
        &arg[1].model, &arg[1].num, &arg[1].top, &arg[1].offset,
        &arg[2].model, &arg[2].num, &arg[2].top, &arg[2].offset,
        &arg[3].model, &arg[3].num, &arg[3].top, &arg[3].offset
    );
    // 写入每个轨道
    for (int i = 0; i < 4; ++i)
        tracks[i].oPitch2 = arg[i];
    return parsed == 16;
}
