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
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
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)");
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)");
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();
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)");
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...
uint8_t Attributes
Bit field of attribute flags (ATM only bit 0 is used, better call Use2ndStart() instead of accessing ...
String Name24
Longer Human readable name (24 characters) of the instrument for display purposes (not the file name)...
String Name() const
Returns the long name (Name24) if it was stored in the file, otherwise returns the short name (Name16...
String SampleFileName
Base file name of sample file (12 bytes). Call FullSampleFileName() for getting the file name with pa...
uint8_t BitDepth
i.e. 8 or 16
uint8_t Channels
Number of audio channels (seems to be always 1, thus Mono for all Korg sound files ATM).
buffer_t GetCache() const
Returns current cached sample points.
unsigned long Read(void *pBuffer, unsigned long SampleCount)
Reads SampleCount number of sample points from the current position into the buffer pointed by pBuffe...
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).
uint32_t SamplePoints
Currently the library expects all Korg samples to be Mono, thus the value here might be incorrect in ...
String Name
Sample name for drums (since this name is always stored with 16 bytes, this name must never be longer...
buffer_t LoadSampleData()
Loads the whole sample wave into RAM.
int FrameSize() const
Returns the size of one sample point of this sample in bytes.
uint32_t SampleRate
i.e. 44100
buffer_t LoadSampleDataWithNullSamplesExtension(uint NullSamplesCount)
Loads the whole sample wave into RAM.
void ReleaseSampleData()
Frees the cached sample from RAM if loaded with LoadSampleData() previously.
uint8_t Attributes
Bit field of flags, better call IsCompressed(), CompressionID() and Use2ndStart() instead of accessin...
unsigned long GetPos() const
Returns the current position in the sample (in sample points).
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.
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).
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...
file_offset_t GetPos() const
Position within the chunk data body (starting with 0).
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...
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...
file_offset_t GetSize() const
Chunk size in bytes (without header, thus the chunk data body)
File * GetFile() const
Returns pointer to the chunk's File object.
Chunk * GetSubChunk(uint32_t ChunkID)
Returns subchunk with chunk ID ChunkID within this chunk list.
KORG sound format specific classes and definitions.
String libraryVersion()
Returns version of this C++ library.
String libraryName()
Returns the name of this C++ library.
String readText16(RIFF::Chunk *ck)
Read 16 bytes of ASCII text from given chunk and return it as String.
String readText24(RIFF::Chunk *ck)
Read 24 bytes of ASCII text from given chunk and return it as String.
String readText12(RIFF::Chunk *ck)
Read 12 bytes of ASCII text from given chunk and return it as String.
String removeFileTypeExtension(const String &filename)
For example passing "FOO.KMP" will return "FOO".
RIFF specific classes and definitions.
stream_whence_t
File stream position dependent to these relations.
@ layout_flat
Not a "real" RIFF file: First chunk in file is an ordinary data chunk, not a List chunk,...
Pointer address and size of a buffer.
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 * pStart
Points to the beginning of the buffer.
file_offset_t Size
Size of the actual data in the buffer in bytes.