29 # define CHUNK_ID_MSP1 0x4d535031
30 # define CHUNK_ID_RLP1 0x524c5031
31 # define CHUNK_ID_SMP1 0x534d5031
32 # define CHUNK_ID_SMD1 0x534d4431
33 # define CHUNK_ID_NAME 0x4e414d45
34 #else // little endian
35 # define CHUNK_ID_MSP1 0x3150534d
36 # define CHUNK_ID_RLP1 0x31504c52
37 # define CHUNK_ID_SMP1 0x31504d53
38 # define CHUNK_ID_SMD1 0x31444d53
39 # define CHUNK_ID_NAME 0x454d414e
40 #endif // WORDS_BIGENDIAN
42 #define SMD1_CHUNK_HEADER_SZ 12
47 static const String PATH_SEP =
"\\";
49 static const String PATH_SEP =
"/";
55 template<
unsigned int SZ>
58 int n = (int) ck->
Read(buf, SZ, 1);
60 throw Exception(
"Premature end while reading text field");
67 return readText<24>(ck);
72 return readText<16>(ck);
77 return readText<12>(ck);
82 size_t pos = filename.find_last_of(
'.');
83 if (pos == String::npos)
return filename;
84 return filename.substr(0, pos);
90 KSFSample::KSFSample(
const String& filename) {
102 throw Exception(
"Not a Korg sample file ('SMP1' chunk not found)");
103 if (smp1->GetSize() < 32)
104 throw Exception(
"Not a Korg sample file ('SMP1' chunk size too small)");
115 throw Exception(
"Not a Korg sample file ('SMD1' chunk not found)");
116 if (smd1->GetSize() < 12)
117 throw Exception(
"Not a Korg sample file ('SMD1' chunk size too small)");
126 KSFSample::~KSFSample() {
127 if (RAMCache.
pStart)
delete[] (int8_t*) RAMCache.
pStart;
128 if (riff)
delete riff;
199 if (RAMCache.
pStart)
delete[] (int8_t*) RAMCache.
pStart;
200 unsigned long allocationsize = (SampleCount + NullSamplesCount) *
FrameSize();
202 RAMCache.
pStart =
new int8_t[allocationsize];
235 if (RAMCache.
pStart)
delete[] (int8_t*) RAMCache.
pStart;
253 unsigned long samplePos =
GetPos();
255 case RIFF::stream_curpos:
256 samplePos += SampleCount;
258 case RIFF::stream_end:
261 case RIFF::stream_backward:
262 samplePos -= SampleCount;
264 case RIFF::stream_start:
266 samplePos = SampleCount;
270 unsigned long bytes = samplePos *
FrameSize();
272 unsigned long result = smd1->
SetPos(SMD1_CHUNK_HEADER_SZ + bytes);
273 return (result - SMD1_CHUNK_HEADER_SZ) /
FrameSize();
281 return (smd1->GetPos() - SMD1_CHUNK_HEADER_SZ) /
FrameSize();
303 unsigned long samplestoread = SampleCount, totalreadsamples = 0, readsamples;
305 if (samplestoread)
do {
307 samplestoread -= readsamples;
308 totalreadsamples += readsamples;
309 }
while (readsamples && samplestoread);
311 return totalreadsamples;
321 uint8_t KSFSample::CompressionID()
const {
325 bool KSFSample::IsCompressed()
const {
329 bool KSFSample::Use2ndStart()
const {
333 String KSFSample::FileName()
const {
334 return riff->GetFileName();
340 KMPRegion::KMPRegion(KMPInstrument* parent,
RIFF::Chunk* rlp1)
341 : parent(parent), rlp1(rlp1)
344 Transpose = (OriginalKey >> 7) & 1;
354 KMPRegion::~KMPRegion() {
357 String KMPRegion::FullSampleFileName()
const {
362 KMPInstrument* KMPRegion::GetInstrument()
const {
369 KMPInstrument::KMPInstrument(
const String& filename) {
377 throw Exception(
"Not a Korg instrument file ('MSP1' chunk not found)");
378 if (msp1->GetSize() < 18)
379 throw Exception(
"Not a Korg instrument file ('MSP1' chunk size too small)");
393 throw Exception(
"Not a Korg instrument file ('RLP1' chunk not found)");
394 if (rlp1->GetSize() < 18 * nSamples)
395 throw Exception(
"Not a Korg instrument file ('RLP1' chunk size too small)");
396 for (
int i = 0; i < nSamples; ++i) {
397 KMPRegion* region =
new KMPRegion(
this, rlp1);
398 regions.push_back(region);
402 KMPInstrument::~KMPInstrument() {
403 if (riff)
delete riff;
404 for (
int i = 0; i < regions.size(); ++i)
408 KMPRegion* KMPInstrument::GetRegion(
int index) {
409 if (index < 0 || index >= regions.size())
411 return regions[index];
414 int KMPInstrument::GetRegionCount()
const {
415 return (
int) regions.size();
418 bool KMPInstrument::Use2ndStart()
const {
430 String KMPInstrument::FileName()
const {
431 return riff->GetFileName();
437 Exception::Exception(String Message) :
RIFF::Exception(Message) {
440 void Exception::PrintMessage() {
441 std::cout <<
"Korg::Exception: " << Message << std::endl;
String Name16
Human readable name of the instrument for display purposes (not the file name). Since this name is al...
buffer_t LoadSampleData()
Loads the whole sample wave into RAM.
file_offset_t Size
Size of the actual data in the buffer in bytes.
String removeFileTypeExtension(const String &filename)
For example passing "FOO.KMP" will return "FOO".
unsigned long SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence=RIFF::stream_start)
Sets the position within the sample (in sample points, not in bytes).
file_offset_t Read(void *pData, file_offset_t WordCount, file_offset_t WordSize)
Reads WordCount number of data words with given WordSize and copies it into a buffer pointed by pData...
uint8_t Attributes
Bit field of attribute flags (ATM only bit 0 is used, better call Use2ndStart() instead of accessing ...
String libraryName()
Returns the name of this C++ library.
uint32_t SamplePoints
Currently the library expects all Korg samples to be Mono, thus the value here might be incorrect in ...
file_offset_t SetPos(file_offset_t Where, stream_whence_t Whence=stream_start)
Sets the position within the chunk body, thus within the data portion of the chunk (in bytes).
String Name() const
Returns the long name (Name24) if it was stored in the file, otherwise returns the short name (Name16...
file_offset_t ReadUint32(uint32_t *pData, file_offset_t WordCount=1)
Reads WordCount number of 32 Bit unsigned integer words and copies it into the buffer pointed by pDat...
uint8_t Channels
Number of audio channels (seems to be always 1, thus Mono for all Korg sound files ATM).
uint8_t Attributes
Bit field of flags, better call IsCompressed(), CompressionID() and Use2ndStart() instead of accessin...
String Name
Sample name for drums (since this name is always stored with 16 bytes, this name must never be longer...
stream_whence_t
File stream position dependent to these relations.
String readText12(RIFF::Chunk *ck)
Read 12 bytes of ASCII text from given chunk and return it as String.
void * pStart
Points to the beginning of the buffer.
buffer_t LoadSampleDataWithNullSamplesExtension(uint NullSamplesCount)
Loads the whole sample wave into RAM.
String libraryVersion()
Returns version of this C++ library.
Pointer address and size of a buffer.
String readText24(RIFF::Chunk *ck)
Read 24 bytes of ASCII text from given chunk and return it as String.
file_offset_t ReadUint8(uint8_t *pData, file_offset_t WordCount=1)
Reads WordCount number of 8 Bit unsigned integer words and copies it into the buffer pointed by pData...
@ layout_flat
Not a "real" RIFF file: First chunk in file is an ordinary data chunk, not a List chunk,...
unsigned long Read(void *pBuffer, unsigned long SampleCount)
Reads SampleCount number of sample points from the current position into the buffer pointed by pBuffe...
file_offset_t NullExtensionSize
The buffer might be bigger than the actual data, if that's the case that unused space at the end of t...
void ReleaseSampleData()
Frees the cached sample from RAM if loaded with LoadSampleData() previously.
String readText16(RIFF::Chunk *ck)
Read 16 bytes of ASCII text from given chunk and return it as String.
buffer_t GetCache() const
Returns current cached sample points.
unsigned long GetPos() const
Returns the current position in the sample (in sample points).
KORG sound format specific classes and definitions.
String Name24
Longer Human readable name (24 characters) of the instrument for display purposes (not the file name)...
file_offset_t ReadInt8(int8_t *pData, file_offset_t WordCount=1)
Reads WordCount number of 8 Bit signed integer words and copies it into the buffer pointed by pData.
uint32_t SampleRate
i.e. 44100
uint8_t BitDepth
i.e. 8 or 16
RIFF specific classes and definitions.
int FrameSize() const
Returns the size of one sample point of this sample in bytes.
Chunk * GetSubChunk(uint32_t ChunkID)
Returns subchunk with chunk ID ChunkID within this chunk list.
String SampleFileName
Base file name of sample file (12 bytes). Call FullSampleFileName() for getting the file name with pa...