ref: f8b152bf5dba91eb8b408b9c7335c1f9062c1b79
dir: /src/PixTone.cpp/
#include <cstdio>
#include <cstdlib>
#include <stdint.h>
#include <vector>
#include <cstring>
#include <math.h>
#include "CommonDefines.h"
#include "Tags.h"
#include "PixTone.h"
int8_t gWaveModelTable[6][0x100];
void MakeWaveTables()
{
/* Sine wave */
for (int i = 0; i < 0x100; i++)
gWaveModelTable[0][i] = (sin(i * 6.283184 / 256.0) * 64.0);
/* Triangle wave */
int triangle = 0;
for (int i = 0; i < 0x40; ++i) //Upwards
gWaveModelTable[1][i] = (triangle++ << 6) / 0x40;
triangle = 0;
for (int i = 0x40; i < 0xC0; ++i) //Downwards
gWaveModelTable[1][i] = 0x40 - (triangle++ << 6) / 0x40;
triangle = 0;
for (int i = 0xC0; i < 0x100; ++i) //Back upwards
gWaveModelTable[1][i] = (triangle++ << 6) / 0x40 - 0x40;
/* Saw up wave */
for (int i = 0; i < 0x100; i++)
gWaveModelTable[2][i] = i / 2 - 0x40;
/* Saw down wave */
for (int i = 0; i < 0x100; i++)
gWaveModelTable[3][i] = 0x40 - i / 2;
/* Square wave */
for (int i = 0; i < 0x80; i++)
gWaveModelTable[4][i] = 0x40;
for (int i = 0x80; i < 0x100; i++)
gWaveModelTable[4][i] = -0x40;
/* White noise wave */
srand(0);
for (int i = 0; i < 0x100; i++)
gWaveModelTable[5][i] = (int8_t)rand() / 2;
}
//Loading .pxt files
double fgetv(FILE *fp) // Load a numeric value from text file; one per line.
{
//Create buffer
char Buf[0x1000];
Buf[0xFFF] = '\0';
char *p = Buf;
if (!std::fgets(Buf, sizeof(Buf) - 1, fp))
return 0.0;
// Ignore empty lines. If the line was empty, try next line.
if (!Buf[0] || Buf[0] == '\r' || Buf[0] == '\n')
return fgetv(fp);
while (*p && *p++ != ':')
{
}
return std::strtod(p, 0); // Parse the value and return it.
}
bool MakePixelWaveData(const std::vector<double>& pxtData, uint8_t *data)
{
//Get some envelope stuff
char envelopeTable[0x100];
memset(envelopeTable, 0, sizeof(envelopeTable));
size_t i = 0;
//Point A
long double currentEnvelope = pxtData[14];
while (i < pxtData[15])
{
envelopeTable[i] = (char)currentEnvelope;
currentEnvelope = (pxtData[16] - pxtData[14])
/ pxtData[15]
+ currentEnvelope;
++i;
}
//Point B
long double currentEnvelopea = pxtData[16];
while (i < pxtData[17])
{
envelopeTable[i] = (char)currentEnvelopea;
currentEnvelopea = (pxtData[18] - pxtData[16])
/ (pxtData[17] - pxtData[15])
+ currentEnvelopea;
++i;
}
//Point C
long double currentEnvelopeb = pxtData[18];
while (i < pxtData[19])
{
envelopeTable[i] = (char)currentEnvelopeb;
currentEnvelopeb = (pxtData[20] - pxtData[18])
/ (pxtData[19] - pxtData[17])
+ currentEnvelopeb;
++i;
}
//End
long double currentEnvelopec = pxtData[20];
while (i < 0x100)
{
envelopeTable[i] = (char)currentEnvelopec;
currentEnvelopec = currentEnvelopec
- pxtData[20] / (0x100 - pxtData[19]);
++i;
}
long double pitchOffset = pxtData[9];
long double mainOffset = pxtData[5];
long double volumeOffset = pxtData[13];
//Main
long double mainFreq;
if (pxtData[3] == 0.0)
mainFreq = 0.0;
else
mainFreq = 256.0 / (pxtData[1] / pxtData[3]);
//Pitch
long double pitchFreq;
if (pxtData[7] == 0.0)
pitchFreq = 0.0;
else
pitchFreq = 256.0 / (pxtData[1] / pxtData[7]);
//Volume
long double volumeFreq;
if (pxtData[11] == 0.0)
volumeFreq = 0.0;
else
volumeFreq = 256.0 / (pxtData[1] / pxtData[11]);
for (i = 0; i < pxtData[1]; ++i)
{
const int a = (int)(uint64_t)mainOffset % 256;
const int v2 = (int)(uint64_t)pitchOffset % 256;
//Input data
data[i] = envelopeTable[(unsigned __int64)((long double)(i << 8) / pxtData[1])]
* (pxtData[4]
* gWaveModelTable[(size_t)pxtData[2]][a]
/ 0x40
* (pxtData[12]
* gWaveModelTable[(size_t)pxtData[10]][(signed int)(uint64_t)volumeOffset % 0x100]
/ 0x40
+ 0x40)
/ 0x40)
/ 0x40
+ 0x80;
long double newMainOffset;
if (gWaveModelTable[(size_t)pxtData[6]][v2] >= 0)
newMainOffset = (mainFreq * 2)
* (long double)gWaveModelTable[(size_t)pxtData[6]][(signed int)(unsigned __int64)pitchOffset % 256]
* pxtData[8]
/ 64.0
/ 64.0
+ mainFreq
+ mainOffset;
else
newMainOffset = mainFreq
- mainFreq
* 0.5
* (long double)-gWaveModelTable[(size_t)pxtData[6]][v2]
* pxtData[8]
/ 64.0
/ 64.0
+ mainOffset;
mainOffset = newMainOffset;
pitchOffset = pitchOffset + pitchFreq;
volumeOffset = volumeOffset + volumeFreq;
}
return true;
}
bool LoadPxt(char *name, uint8_t **buf, size_t *length)
{
//Open file
char path[PATH_LENGTH];
sprintf(path, "%s/Sound/%s", gDataPath, name);
FILE *fp = fopen(path, "rb");
if (!fp)
return false;
//Read data
std::vector<double> lineNumbers[4];
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 21; j++)
{
double val = fgetv(fp);
lineNumbers[i].push_back(val);
}
}
//Close file
fclose(fp);
//Get size
size_t size;
for (int i = 0; i < 4; i++)
{
if (lineNumbers[i][1] > size)
size = (size_t)lineNumbers[i][1];
}
//Allocate buffers
uint8_t *dest = (uint8_t*)malloc(size);
uint8_t *pBlock = (uint8_t*)malloc(size);
if (dest && pBlock)
{
//Set buffers to default value of 0x80
memset(dest, 0x80, size);
memset(pBlock, 0x80, size);
for (int i = 0; i < 4; ++i)
{
//Get wave data
if (!MakePixelWaveData(lineNumbers[i], dest))
{
printf("MakePixelWaveData failed for %s\n", name);
free(dest);
free(pBlock);
return -1;
}
//Put data into buffer
for (int j = 0; j < lineNumbers[i][1]; ++j)
{
if (dest[j] + pBlock[j] - 0x100 >= -0x7F)
{
if (dest[j] + pBlock[j] - 0x100 <= 0x7F)
pBlock[j] += dest[j] - 0x80;
else
pBlock[j] = (uint8_t)-1;
}
else
{
pBlock[j] = 0;
}
}
}
//Put data from buffers into main sound buffer
*buf = (uint8_t*)malloc(size);
if (!*buf)
{
printf("Failed to allocate buffer for %s\n", name);
free(dest);
free(pBlock);
return false;
}
*length = size;
memcpy(*buf, pBlock, size);
//Free the two buffers
free(dest);
free(pBlock);
return true;
}
printf("Failed to allocate dest or pBlock for %s\n", name);
free(dest);
free(pBlock);
return false;
}