This commit is contained in:
freq-mod 2024-08-12 19:25:53 +02:00
parent aa225175a8
commit d1e198ddff
7 changed files with 996 additions and 0 deletions

131
src/engine/fileOps/p.cpp Normal file
View file

@ -0,0 +1,131 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "shared.h"
#ifdef HAVE_GUI
#include "../gui/gui.h"
extern FurnaceGUI g;
#endif
#define _LE(string) (string)
class DivEngine;
//P VOX ADPCM sample bank
/* =======================================
Header
=======================================
0x0000 - 0x03FF 256 * {
Sample start (uint32_t)
- 0x00000000 = unused
}
=======================================
Body
=======================================
Stream of Sample Data {
MSM6258 ADPCM encoding
nibble-swapped VOX / Dialogic ADPCM
Mono
Sample rate?
16000Hz seems fine
} */
#define P_BANK_SIZE 256
#define P_SAMPLE_RATE 16000
typedef struct
{
uint32_t start_pointer;
} P_HEADER;
void DivEngine::loadP(SafeReader& reader, std::vector<DivSample*>& ret, String& stripPath)
{
try
{
reader.seek(0, SEEK_SET);
P_HEADER headers[P_BANK_SIZE];
for(int i = 0; i < P_BANK_SIZE; i++)
{
headers[i].start_pointer = (unsigned int)reader.readI_BE();
}
for(int i = 0; i < P_BANK_SIZE; i++)
{
if(headers[i].start_pointer != 0)
{
DivSample* s = new DivSample;
s->rate = P_SAMPLE_RATE;
s->centerRate = P_SAMPLE_RATE;
s->depth = DIV_SAMPLE_DEPTH_VOX;
reader.seek((int)headers[i].start_pointer, SEEK_SET);
int sample_pos = 0;
int sample_len = 0;
if(i < P_BANK_SIZE - 1)
{
sample_len = headers[i + 1].start_pointer - headers[i].start_pointer;
}
else
{
sample_len = (int)reader.size() - headers[i].start_pointer;
}
if(sample_len > 0)
{
s->init(sample_len * 2);
for(int j = 0; j < sample_len; j++)
{
unsigned char curr_byte = (unsigned char)reader.readC();
curr_byte = (curr_byte << 4) | (curr_byte >> 4);
s->dataVOX[sample_pos] = curr_byte;
sample_pos++;
}
ret.push_back(s);
logI("p: start %d len %d", headers[i].start_pointer, sample_len);
}
else
{
delete s;
}
}
}
}
catch (EndOfFileException& e)
{
lastError=_LE("premature end of file");
logE("premature end of file");
}
}

149
src/engine/fileOps/p86.cpp Normal file
View file

@ -0,0 +1,149 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "shared.h"
#ifdef HAVE_GUI
#include "../gui/gui.h"
extern FurnaceGUI g;
#endif
#define _LE(string) (string)
class DivEngine;
//P86 8-bit PCM sample bank
/* =======================================
Header
=======================================
0x0000 Identifier (12b)
"PCM86 DATA(\n)(\0)"
0x000C Targeted P86DRV version (1b)
version <high nibble>.<low nibble>
0x000D File Length (3b)
0x0010 - 0x060F 256 * {
Pointer to Sample Data Start (3b)
Length of Sample Data (3b)
(0x000000 0x000000 -> no sample for this instrument ID)
}
=======================================
Body
=======================================
Stream of Sample Data {
8-Bit Signed
Mono
16540Hz
(above sample rate according to KAJA's documentation
any sample rate possible, for different base note & octave)
} */
#define P86_BANK_SIZE 256
#define P86_SAMPLE_RATE 16540
#define P86_FILE_SIG "PCM86 DATA\n\0"
typedef struct
{
uint32_t start_pointer;
uint32_t sample_length;
} P86_HEADER;
#define UNUSED(x) (void)(x)
uint32_t read_3bytes(SafeReader& reader)
{
unsigned char arr[3];
for (int i = 0; i < 3; i++)
{
arr[i] = (unsigned char)reader.readC();
}
return (arr[0] | (arr[1] << 8) | (arr[2] << 16));
}
void DivEngine::loadP86(SafeReader& reader, std::vector<DivSample*>& ret, String& stripPath)
{
try
{
reader.seek(0, SEEK_SET);
P86_HEADER headers[P86_BANK_SIZE];
String file_sig = reader.readString(12);
if(file_sig != P86_FILE_SIG) return;
uint8_t version = reader.readC();
UNUSED(version);
uint32_t file_size = read_3bytes(reader);
UNUSED(file_size);
for(int i = 0; i < P86_BANK_SIZE; i++)
{
headers[i].start_pointer = read_3bytes(reader);
headers[i].sample_length = read_3bytes(reader);
}
for(int i = 0; i < P86_BANK_SIZE; i++)
{
if(headers[i].start_pointer != 0 && headers[i].sample_length != 0)
{
DivSample* s = new DivSample;
s->rate = P86_SAMPLE_RATE;
s->centerRate = P86_SAMPLE_RATE;
s->depth = DIV_SAMPLE_DEPTH_8BIT;
s->init(headers[i].sample_length); //byte per sample
reader.seek((int)headers[i].start_pointer, SEEK_SET);
int sample_pos = 0;
for(uint32_t j = 0; j < headers[i].sample_length; j++)
{
unsigned char curr_byte = (unsigned char)reader.readC();
//curr_byte += 0x80;
s->data8[sample_pos] = curr_byte;
sample_pos++;
}
ret.push_back(s);
logI("p86: start %06X len %06X", headers[i].start_pointer, headers[i].sample_length);
}
}
}
catch (EndOfFileException& e)
{
lastError=_LE("premature end of file");
logE("premature end of file");
}
}

108
src/engine/fileOps/pdx.cpp Normal file
View file

@ -0,0 +1,108 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "shared.h"
#ifdef HAVE_GUI
#include "../gui/gui.h"
extern FurnaceGUI g;
#endif
#define _LE(string) (string)
class DivEngine;
//PDX 8-bit OKI ADPCM sample bank
/* File format
The file starts with a header with 96 8-byte pairs, with each pair containing offset and length of ADPCM data chunks for each note value, like so:
[[byte pointer to sample in file -- 32-bit unsigned integer (4 bytes)] [empty: $0000 -- 16-bit integer] [length of sample, amount in bytes -- 16-bit unsigned integer] ×96] [ADPCM data] EOF
The first sample (1) is mapped to 0x80 (= the lowest note within MXDRV) and the last sample (96) is mapped to 0xDF (= the highest note within MXDRV).
Samples are encoded in 4-bit OKI ADPCM encoded nibbles, where each byte contains 2 nibbles: [nibble 2 << 4 || nibble 1]
Unfortunately, sample rates for each samples are not defined within the .PDX file and have to be set manually with the appropriate command for that at play-time */
#define PDX_BANK_SIZE 96
#define PDX_SAMPLE_RATE 16000
typedef struct
{
unsigned int start_pointer;
unsigned short sample_length;
} PDX_HEADER;
#define UNUSED(x) (void)(x)
void DivEngine::loadPDX(SafeReader& reader, std::vector<DivSample*>& ret, String& stripPath)
{
try
{
reader.seek(0, SEEK_SET);
PDX_HEADER headers[PDX_BANK_SIZE];
for(int i = 0; i < PDX_BANK_SIZE; i++)
{
headers[i].start_pointer = (unsigned int)reader.readI_BE();
unsigned short empty = (unsigned short)reader.readS_BE(); //skip 1st 2 bytes
UNUSED(empty);
headers[i].sample_length = (unsigned short)reader.readS_BE();
}
for(int i = 0; i < PDX_BANK_SIZE; i++)
{
if(headers[i].start_pointer != 0 && headers[i].sample_length != 0)
{
DivSample* s = new DivSample;
s->rate = PDX_SAMPLE_RATE;
s->centerRate = PDX_SAMPLE_RATE;
s->depth = DIV_SAMPLE_DEPTH_VOX;
s->init(headers[i].sample_length * 2);
reader.seek((int)headers[i].start_pointer, SEEK_SET);
int sample_pos = 0;
for(unsigned short j = 0; j < headers[i].sample_length; j++)
{
unsigned char curr_byte = (unsigned char)reader.readC();
curr_byte = (curr_byte << 4) | (curr_byte >> 4);
s->dataVOX[sample_pos] = curr_byte;
sample_pos++;
}
ret.push_back(s);
logI("pdx: start %d len %d", headers[i].start_pointer, headers[i].sample_length);
}
}
}
catch (EndOfFileException& e)
{
lastError=_LE("premature end of file");
logE("premature end of file");
}
}

149
src/engine/fileOps/ppc.cpp Normal file
View file

@ -0,0 +1,149 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "shared.h"
#ifdef HAVE_GUI
#include "../gui/gui.h"
extern FurnaceGUI g;
#endif
#define _LE(string) (string)
class DivEngine;
//PPC PMD's YM2608 ADPCM-B sample bank
/* ========================================
General
========================================
ADPCM RAM addresses: see docs/common.txt {
address_start = 0x0026
file_header_size = 0x0420
}
========================================
Header
========================================
0x0000 Identifier (30b)
"ADPCM DATA for PMD ver.4.4- "
0x001E Address of End of Data (32B blocks) in ADPCM RAM (1h)
File Size == address -> file offset
0x0020 - 0x041F 256 * {
Start of Sample (32b blocks) in ADPCM RAM (1h)
End of Sample (32b blocks) in ADPCM RAM (1h)
(0x0000 0x0000 -> no sample for this instrument ID)
}
========================================
Body
========================================
Stream of Sample Data {
Yamaha ADPCM-B encoding (4-Bit Signed ADPCM)
Mono
16kHz
(above sample rate according to KAJA's documentation
any sample rate possible, for different base note & octave)
} */
#define PPC_FILE_SIG "ADPCM DATA for PMD ver.4.4- "
#define PPC_BANK_SIZE 256
#define PPC_SAMPLE_RATE 16000
typedef struct
{
uint16_t start_pointer;
uint16_t end_pointer;
} PPC_HEADER;
#define UNUSED(x) (void)(x)
#define ADPCM_DATA_START 0x0420
void DivEngine::loadPPC(SafeReader& reader, std::vector<DivSample*>& ret, String& stripPath)
{
try
{
reader.seek(0, SEEK_SET);
String file_sig = reader.readString(30);
unsigned short end_of_data = (unsigned short)reader.readS();
UNUSED(end_of_data);
if(file_sig != PPC_FILE_SIG) return;
PPC_HEADER headers[PPC_BANK_SIZE];
for(int i = 0; i < PPC_BANK_SIZE; i++)
{
headers[i].start_pointer = (unsigned short)reader.readS();
headers[i].end_pointer = (unsigned short)reader.readS();
}
for(int i = 0; i < PPC_BANK_SIZE; i++)
{
if((headers[i].start_pointer != 0 || headers[i].end_pointer != 0) && headers[i].start_pointer < headers[i].end_pointer)
{
DivSample* s = new DivSample;
s->rate = PPC_SAMPLE_RATE;
s->centerRate = PPC_SAMPLE_RATE;
s->depth = DIV_SAMPLE_DEPTH_ADPCM_B;
s->init((headers[i].end_pointer - headers[i].start_pointer) * 32 * 2);
int sample_pos = 0;
int sample_length = (headers[i].end_pointer - headers[i].start_pointer) * 32;
//reader.seek(ADPCM_DATA_START + headers[i].start_pointer * 32, SEEK_SET);
for(int j = 0; j < sample_length; j++)
{
unsigned char curr_byte = (unsigned char)reader.readC();
//curr_byte=(curr_byte<<4)|(curr_byte>>4);
s->dataB[sample_pos] = curr_byte;
sample_pos++;
}
logI("ppc: start %d end %d len in bytes %d", headers[i].start_pointer, headers[i].end_pointer, (headers[i].end_pointer - headers[i].start_pointer) * 32);
ret.push_back(s);
}
}
}
catch (EndOfFileException& e)
{
lastError=_LE("premature end of file");
logE("premature end of file");
}
}

132
src/engine/fileOps/pps.cpp Normal file
View file

@ -0,0 +1,132 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "shared.h"
#ifdef HAVE_GUI
#include "../gui/gui.h"
extern FurnaceGUI g;
#endif
#define _LE(string) (string)
class DivEngine;
//PPS AY-3-8910 sample bank
/* =======================================
Header
=======================================
0x0000 - 0x0053 14 * {
Pointer to Sample Data Start (1h)
Length of Sample Data (1h)
"Pitch"(?) (1b)
Volume Reduction (1b)
}
(0x0000 0x0000 [0x00 0x00] -> no sample for this instrument ID)
}
=======================================
Body
=======================================
Stream of Sample Data {
4-Bit Unsigned
(afaict)
Mono
16Hz
(based on tests, maybe alternatively 8kHz)
} */
#define PPS_BANK_SIZE 14
#define PPS_SAMPLE_RATE 16000
typedef struct
{
uint16_t start_pointer;
uint16_t sample_length;
uint8_t _pitch;
uint8_t _vol;
} PPS_HEADER;
void DivEngine::loadPPS(SafeReader& reader, std::vector<DivSample*>& ret, String& stripPath)
{
try
{
reader.seek(0, SEEK_SET);
PPS_HEADER headers[PPS_BANK_SIZE];
for(int i = 0; i < PPS_BANK_SIZE; i++)
{
headers[i].start_pointer = (unsigned short)reader.readS();
headers[i].sample_length = (unsigned short)reader.readS();
headers[i]._pitch = (unsigned char)reader.readC();
headers[i]._vol = (unsigned char)reader.readC();
}
for(int i = 0; i < PPS_BANK_SIZE; i++)
{
if(headers[i].start_pointer != 0 || headers[i].sample_length != 0
|| headers[i]._pitch != 0 || headers[i]._vol != 0)
{
DivSample* s = new DivSample;
s->rate = PPS_SAMPLE_RATE;
s->centerRate = PPS_SAMPLE_RATE;
s->depth = DIV_SAMPLE_DEPTH_8BIT;
s->init(headers[i].sample_length * 2); //byte per sample
reader.seek((int)headers[i].start_pointer, SEEK_SET);
int sample_pos = 0;
for(int j = 0; j < headers[i].sample_length; j++)
{
unsigned char curr_byte = (unsigned char)reader.readC();
s->data8[sample_pos] = (curr_byte >> 4) | (curr_byte & 0xf0);
s->data8[sample_pos] += 0x80;
sample_pos++;
s->data8[sample_pos] = (curr_byte << 4) | (curr_byte & 0xf);
s->data8[sample_pos] += 0x80;
sample_pos++;
}
ret.push_back(s);
logI("pps: start %d len %d", headers[i].start_pointer, headers[i].sample_length);
}
}
}
catch (EndOfFileException& e)
{
lastError=_LE("premature end of file");
logE("premature end of file");
}
}

165
src/engine/fileOps/pvi.cpp Normal file
View file

@ -0,0 +1,165 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "shared.h"
#ifdef HAVE_GUI
#include "../gui/gui.h"
extern FurnaceGUI g;
#endif
#define _LE(string) (string)
class DivEngine;
//PVI YM2608 ADPCM-B sample bank
/* =======================================
General
=======================================
ADPCM RAM addresses: see docs/common.txt {
address_start = 0x0000
file_header_size = 0x0210
}
=======================================
Header
=======================================
0x0000 Identifier (4b)
"PVI2"
0x0004 - 0x0007 Unknown Settings (4b)
Unknown mappings PCME switches <-> Values
"0x10 0x00 0x10 0x02" in all example files
First 1h may be Start Address in ADPCM RAM?
0x0008 - 0x0009 "Delta-N" playback frequency (1h)
Default 0x49BA "== 16kHz"??
0x000A Unknown (1b)
RAM type? (Docs indicate values 0 or 8, all example files have value 0x02?)
0x000B Amount of defined Samples (1b)
0x000C - 0x000F Unknown (4b)
Padding?
"0x00 0x00 0x00 0x00" in all example files
0x0010 - 0x020F 128 * {
Start of Sample (32b blocks) in ADPCM RAM (1h)
End of Sample (32b blocks) in ADPCM RAM (1h)
(0x0000 0x0000 -> no sample for this instrument ID)
}
=======================================
Body
=======================================
Stream of Sample Data {
Yamaha ADPCM-B encoding (4-Bit Signed ADPCM)
Mono
Sample rate as specified earlier
(examples i have seems Stereo or 32kHz despite "16kHz" playback frequency setting?)
} */
#define PVIV2_FILE_SIG "PVI2"
#define PVIV1_FILE_SIG "PVI1"
#define PVI_BANK_SIZE 128
#define PVI_SAMPLE_RATE 16000
typedef struct
{
uint16_t start_pointer;
uint16_t end_pointer;
} PVI_HEADER;
#define UNUSED(x) (void)(x)
#define ADPCM_DATA_START 0x0210
void DivEngine::loadPVI(SafeReader& reader, std::vector<DivSample*>& ret, String& stripPath)
{
try
{
reader.seek(0, SEEK_SET);
String file_sig = reader.readString(4);
if(file_sig != PVIV1_FILE_SIG && file_sig != PVIV2_FILE_SIG) return;
unsigned int unknown_settings = (unsigned int)reader.readI();
UNUSED(unknown_settings);
unsigned short delta_n = (unsigned short)reader.readS();
UNUSED(delta_n);
unsigned char one_byte = (unsigned char)reader.readC();
UNUSED(one_byte);
unsigned char amount_of_samples = (unsigned char)reader.readC();
UNUSED(amount_of_samples);
unsigned int padding = (unsigned int)reader.readI();
UNUSED(padding);
PVI_HEADER headers[PVI_BANK_SIZE];
for(int i = 0; i < PVI_BANK_SIZE; i++)
{
headers[i].start_pointer = (unsigned short)reader.readS();
headers[i].end_pointer = (unsigned short)reader.readS();
}
for(int i = 0; i < PVI_BANK_SIZE; i++)
{
if((headers[i].start_pointer != 0 || headers[i].end_pointer != 0) && headers[i].start_pointer < headers[i].end_pointer)
{
DivSample* s = new DivSample;
s->rate = PVI_SAMPLE_RATE;
s->centerRate = PVI_SAMPLE_RATE;
s->depth = DIV_SAMPLE_DEPTH_ADPCM_B;
s->init((headers[i].end_pointer - headers[i].start_pointer) * 32 * 2);
int sample_pos = 0;
int sample_length = (headers[i].end_pointer - headers[i].start_pointer) * 32;
reader.seek(ADPCM_DATA_START + headers[i].start_pointer * 32, SEEK_SET);
for(int j = 0; j < sample_length; j++)
{
unsigned char curr_byte = (unsigned char)reader.readC();
//curr_byte=(curr_byte<<4)|(curr_byte>>4);
s->dataB[sample_pos] = curr_byte;
sample_pos++;
}
logI("pvi: start %d end %d len in bytes %d", headers[i].start_pointer, headers[i].end_pointer, (headers[i].end_pointer - headers[i].start_pointer) * 32);
ret.push_back(s);
}
}
}
catch (EndOfFileException& e)
{
lastError=_LE("premature end of file");
logE("premature end of file");
}
}

162
src/engine/fileOps/pzi.cpp Normal file
View file

@ -0,0 +1,162 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "shared.h"
#ifdef HAVE_GUI
#include "../gui/gui.h"
extern FurnaceGUI g;
#endif
#define _LE(string) (string)
class DivEngine;
//PZI 8-bit PCM sample bank
/* =======================================
Header
=======================================
0x0000 Identifier (4b)
"PZI1"
0x0004 - 0x001F Unknown (28b)
Part of identifier? Settings?
All (\0)s in all example files
0x0020 - 0x091F 128 * {
Start of Sample after header (2h)
Length of Sample (2h)
Offset of loop start from sample start (2h)
Offset of loop end from sample start (2h)
Sample rate (1h)
(0xFFFFFFFF 0xFFFFFFFF loop offsets -> no loop information)
}
=======================================
Body
=======================================
Stream of Sample Data {
Unsigned 8-Bit
Mono
Sample rate as specified in header
} */
#define PZI_BANK_SIZE 128
#define PZI_FILE_SIG "PZI1"
#define NO_LOOP (0xFFFFFFFFU)
#define SAMPLE_DATA_OFFSET 0x0920
#define MAX_SANITY_CAP 9999999
#define HEADER_JUNK_SIZE 28
typedef struct
{
uint32_t start_pointer;
uint32_t sample_length;
uint32_t loop_start;
uint32_t loop_end;
uint16_t sample_rate;
} PZI_HEADER;
#define UNUSED(x) (void)(x)
void DivEngine::loadPZI(SafeReader& reader, std::vector<DivSample*>& ret, String& stripPath)
{
try
{
reader.seek(0, SEEK_SET);
PZI_HEADER headers[PZI_BANK_SIZE];
String file_sig = reader.readString(4);
if(file_sig != PZI_FILE_SIG) return;
for (int i = 0; i < HEADER_JUNK_SIZE; i++)
{
unsigned char curr_byte = (unsigned char)reader.readC();
UNUSED(curr_byte);
}
for(int i = 0; i < PZI_BANK_SIZE; i++)
{
headers[i].start_pointer = (unsigned int)reader.readI();
headers[i].sample_length = (unsigned int)reader.readI();
headers[i].loop_start = (unsigned int)reader.readI();
headers[i].loop_end = (unsigned int)reader.readI();
headers[i].sample_rate = (unsigned short)reader.readS();
}
for(int i = 0; i < PZI_BANK_SIZE; i++)
{
if (headers[i].start_pointer < MAX_SANITY_CAP && headers[i].sample_length < MAX_SANITY_CAP &&
headers[i].loop_start < MAX_SANITY_CAP && headers[i].loop_end < MAX_SANITY_CAP &&
headers[i].start_pointer > 0 && headers[i].sample_length > 0)
{
DivSample* s = new DivSample;
s->rate = headers[i].sample_rate;
s->centerRate = headers[i].sample_rate;
s->depth = DIV_SAMPLE_DEPTH_8BIT;
s->init(headers[i].sample_length); //byte per sample
reader.seek((int)headers[i].start_pointer + SAMPLE_DATA_OFFSET, SEEK_SET);
int sample_pos = 0;
for (uint32_t j = 0; j < headers[i].sample_length; j++)
{
unsigned char curr_byte = (unsigned char)reader.readC();
curr_byte += 0x80;
s->data8[sample_pos] = curr_byte;
sample_pos++;
}
if (headers[i].loop_start != NO_LOOP && headers[i].loop_end != NO_LOOP)
{
s->loop = true;
s->loopMode = DIV_SAMPLE_LOOP_FORWARD;
s->loopStart = headers[i].loop_start;
s->loopEnd = headers[i].loop_end;
}
ret.push_back(s);
logI("pzi: start %d len %d sample rate %d loop start %d loop end %d", headers[i].start_pointer, headers[i].sample_length,
headers[i].sample_rate, headers[i].loop_start, headers[i].loop_end);
}
}
}
catch (EndOfFileException& e)
{
lastError=_LE("premature end of file");
logE("premature end of file");
}
}