part 4
This commit is contained in:
parent
aa225175a8
commit
d1e198ddff
131
src/engine/fileOps/p.cpp
Normal file
131
src/engine/fileOps/p.cpp
Normal 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
149
src/engine/fileOps/p86.cpp
Normal 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
108
src/engine/fileOps/pdx.cpp
Normal 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
149
src/engine/fileOps/ppc.cpp
Normal 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
132
src/engine/fileOps/pps.cpp
Normal 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
165
src/engine/fileOps/pvi.cpp
Normal 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
162
src/engine/fileOps/pzi.cpp
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue