From bcf4f5f50815ab0e60d7cd9b0768a58c3f878af2 Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Tue, 27 May 2025 17:21:26 +0400 Subject: [PATCH 1/8] add 4 bit pcm depth --- src/engine/sample.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/engine/sample.h | 6 +++++- src/gui/guiConst.cpp | 2 +- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 59e97891a..a8d1ba770 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -291,6 +291,8 @@ int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) { case DIV_SAMPLE_DEPTH_16BIT: off=offset*2; break; + case DIV_SAMPLE_DEPTH_4BIT: + off=(offset+1)/2; default: break; } @@ -355,6 +357,10 @@ int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) { off=((offset*3)+1)/2; len=((length*3)+1)/2; break; + case DIV_SAMPLE_DEPTH_4BIT: + off=(offset+1)/2; + len=(length+1)/2; + break; case DIV_SAMPLE_DEPTH_16BIT: off=offset*2; len=length*2; @@ -419,6 +425,9 @@ int DivSample::getEndPosition(DivSampleDepth depth) { case DIV_SAMPLE_DEPTH_12BIT: off=length12; break; + case DIV_SAMPLE_DEPTH_4BIT: + off=length4; + break; case DIV_SAMPLE_DEPTH_16BIT: off=length16; break; @@ -622,6 +631,12 @@ bool DivSample::initInternal(DivSampleDepth d, int count) { data12=new unsigned char[length12+8]; memset(data12,0,length12+8); break; + case DIV_SAMPLE_DEPTH_4BIT: + if (data4!=NULL) delete[] data4; + length4=count; + data4=new unsigned char[length4]; + memset(data4,0,length4); + break; case DIV_SAMPLE_DEPTH_16BIT: // 16-bit if (data16!=NULL) delete[] data16; length16=count*2; @@ -860,6 +875,8 @@ void DivSample::convert(DivSampleDepth newDepth, unsigned int formatMask) { case DIV_SAMPLE_DEPTH_VOX: // VOX setSampleCount((samples+1)&(~1)); break; + case DIV_SAMPLE_DEPTH_4BIT: + setSampleCount((samples+1)&(~1)); default: break; } @@ -1317,6 +1334,11 @@ void DivSample::render(unsigned int formatMask) { } } break; + case DIV_SAMPLE_DEPTH_4BIT: + for (unsigned int i=0; i>12)&0xf; + // if (i+1>12); + // } + } + } } void* DivSample::getCurBuf() { @@ -1550,6 +1581,8 @@ void* DivSample::getCurBuf() { return dataIMA; case DIV_SAMPLE_DEPTH_12BIT: return data12; + case DIV_SAMPLE_DEPTH_4BIT: + return data4; case DIV_SAMPLE_DEPTH_16BIT: return data16; default: @@ -1588,6 +1621,8 @@ unsigned int DivSample::getCurBufLen() { return lengthIMA; case DIV_SAMPLE_DEPTH_12BIT: return length12; + case DIV_SAMPLE_DEPTH_4BIT: + return length4; case DIV_SAMPLE_DEPTH_16BIT: return length16; default: @@ -1703,4 +1738,5 @@ DivSample::~DivSample() { if (dataC219) delete[] dataC219; if (dataIMA) delete[] dataIMA; if (data12) delete[] data12; + if (data4) delete[] data4; } diff --git a/src/engine/sample.h b/src/engine/sample.h index 988dcc317..dfd69b400 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -48,6 +48,7 @@ enum DivSampleDepth: unsigned char { DIV_SAMPLE_DEPTH_C219=12, DIV_SAMPLE_DEPTH_IMA_ADPCM=13, DIV_SAMPLE_DEPTH_12BIT=14, + DIV_SAMPLE_DEPTH_4BIT=15, DIV_SAMPLE_DEPTH_16BIT=16, DIV_SAMPLE_DEPTH_MAX // boundary for sample depth }; @@ -147,8 +148,9 @@ struct DivSample { unsigned char* dataC219; // 12 unsigned char* dataIMA; // 13 unsigned char* data12; // 14 + unsigned char* data4; // 15 - unsigned int length8, length16, length1, lengthDPCM, lengthZ, lengthQSoundA, lengthA, lengthB, lengthK, lengthBRR, lengthVOX, lengthMuLaw, lengthC219, lengthIMA, length12; + unsigned int length8, length16, length1, lengthDPCM, lengthZ, lengthQSoundA, lengthA, lengthB, lengthK, lengthBRR, lengthVOX, lengthMuLaw, lengthC219, lengthIMA, length12, length4; unsigned int samples; @@ -360,6 +362,7 @@ struct DivSample { dataC219(NULL), dataIMA(NULL), data12(NULL), + data4(NULL), length8(0), length16(0), length1(0), @@ -375,6 +378,7 @@ struct DivSample { lengthC219(0), lengthIMA(0), length12(0), + length4(0), samples(0) { for (int i=0; i Date: Wed, 4 Jun 2025 14:37:01 +0400 Subject: [PATCH 2/8] fix 4 bit pcm --- src/engine/fileOpsSample.cpp | 4 +++- src/engine/sample.cpp | 28 ++++++++++++++++++++-------- src/gui/gui.cpp | 4 +++- src/gui/sampleEdit.cpp | 13 ++++++++++++- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/engine/fileOpsSample.cpp b/src/engine/fileOpsSample.cpp index 8e16cc504..16c0432e3 100644 --- a/src/engine/fileOpsSample.cpp +++ b/src/engine/fileOpsSample.cpp @@ -505,6 +505,7 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, case DIV_SAMPLE_DEPTH_ADPCM_B: case DIV_SAMPLE_DEPTH_ADPCM_K: case DIV_SAMPLE_DEPTH_VOX: + case DIV_SAMPLE_DEPTH_4BIT: samples=lenDivided*2; break; case DIV_SAMPLE_DEPTH_IMA_ADPCM: @@ -617,6 +618,7 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, case DIV_SAMPLE_DEPTH_ADPCM_B: case DIV_SAMPLE_DEPTH_ADPCM_K: case DIV_SAMPLE_DEPTH_VOX: + case DIV_SAMPLE_DEPTH_4BIT: // swap nibbles for (unsigned int i=0; igetCurBufLen(); i++) { b[i]=(b[i]<<4)|(b[i]>>4); @@ -629,7 +631,7 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, for (unsigned int i=0; igetCurBufLen(); i++) { b[i]=(((b[i]&7)<<4)|(((b[i]>>3)&15)^((b[i]&0x80)?15:0))|(b[i]&0x80))^0xff; } - break; + break;\ default: break; } diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index a8d1ba770..6a52ede6a 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -633,7 +633,7 @@ bool DivSample::initInternal(DivSampleDepth d, int count) { break; case DIV_SAMPLE_DEPTH_4BIT: if (data4!=NULL) delete[] data4; - length4=count; + length4=(count+1)/2; data4=new unsigned char[length4]; memset(data4,0,length4); break; @@ -1334,11 +1334,18 @@ void DivSample::render(unsigned int formatMask) { } } break; - case DIV_SAMPLE_DEPTH_4BIT: + case DIV_SAMPLE_DEPTH_4BIT: { + unsigned short nibble=0; for (unsigned int i=0; i>4; + } + data16[i]=(nibble<<12)^0x8000; } break; + } default: return; } @@ -1542,11 +1549,16 @@ void DivSample::render(unsigned int formatMask) { } if (NOT_IN_FORMAT(DIV_SAMPLE_DEPTH_4BIT)) { if (!initInternal(DIV_SAMPLE_DEPTH_4BIT,samples)) return; - for (unsigned int i=0; i>12)&0xf; - // if (i+1>12); - // } + unsigned char _sample=0, sample4=0; + unsigned short* samplePtr = (unsigned short*)data16; + for (unsigned int i=0; i>12; + sample4=_sample<<4; + if (i+1>12; + sample4|=_sample; + } + data4[i/2]=sample4; } } } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 6f0aa455c..9a162c190 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -7010,6 +7010,7 @@ bool FurnaceGUI::loop() { ImGui::SameLine(); ImGui::SetNextItemWidth(120.0f*dpiScale); if (ImGui::InputInt("##RSChans",&pendingRawSampleChannels,1,2)) { + CLAMP_VAR(pendingRawSampleChannels, 1, 16) } ImGui::Text(_("(will be mixed down to mono)")); ImGui::Checkbox(_("Unsigned"),&pendingRawSampleUnsigned); @@ -7023,7 +7024,8 @@ bool FurnaceGUI::loop() { pendingRawSampleDepth==DIV_SAMPLE_DEPTH_QSOUND_ADPCM || pendingRawSampleDepth==DIV_SAMPLE_DEPTH_ADPCM_A || pendingRawSampleDepth==DIV_SAMPLE_DEPTH_ADPCM_B || - pendingRawSampleDepth==DIV_SAMPLE_DEPTH_VOX) { + pendingRawSampleDepth==DIV_SAMPLE_DEPTH_VOX || + pendingRawSampleDepth==DIV_SAMPLE_DEPTH_4BIT) { ImGui::Checkbox(_("Swap nibbles"),&pendingRawSampleSwapNibbles); } diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 77121e641..bb1be9371 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -1917,7 +1917,18 @@ void FurnaceGUI::drawSampleEdit() { posX=samplePos+pos.x*sampleZoom; if (posX>(int)sample->samples) posX=-1; } - posY=(0.5-pos.y/rectSize.y)*((sample->depth==DIV_SAMPLE_DEPTH_8BIT)?255:65535); + switch (sample->depth) { + case DIV_SAMPLE_DEPTH_8BIT: + posY=(0.5-pos.y/rectSize.y)*255; + break; + case DIV_SAMPLE_DEPTH_4BIT: + posY=(1-pos.y/rectSize.y)*15; + break; + default: + posY=(0.5-pos.y/rectSize.y)*65535; + break; + } + if (posX>=0) { statusBar2=fmt::sprintf("(%d, %d)",posX,posY); } From b374932ce214969c504e4cfc63b16a4a617b80d1 Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Wed, 4 Jun 2025 14:38:16 +0400 Subject: [PATCH 3/8] wtf --- src/engine/fileOpsSample.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/fileOpsSample.cpp b/src/engine/fileOpsSample.cpp index 16c0432e3..97f693011 100644 --- a/src/engine/fileOpsSample.cpp +++ b/src/engine/fileOpsSample.cpp @@ -631,7 +631,7 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, for (unsigned int i=0; igetCurBufLen(); i++) { b[i]=(((b[i]&7)<<4)|(((b[i]>>3)&15)^((b[i]&0x80)?15:0))|(b[i]&0x80))^0xff; } - break;\ + break; default: break; } From 0426cf3a71292b282d447ee36a88cbf7d9cfeaf0 Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Sun, 15 Jun 2025 17:31:32 +0400 Subject: [PATCH 4/8] pps support --- src/engine/fileOps/pps.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/engine/fileOps/pps.cpp b/src/engine/fileOps/pps.cpp index 37f4a8644..6c0ded2de 100644 --- a/src/engine/fileOps/pps.cpp +++ b/src/engine/fileOps/pps.cpp @@ -92,23 +92,14 @@ void DivEngine::loadPPS(SafeReader& reader, std::vector& ret, String 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 + s->depth = DIV_SAMPLE_DEPTH_4BIT; + 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++; + s->data4[j] = reader.readC(); } ret.push_back(s); From c9f3e95add1874ac1d64f7d0fd82f198ec5c6b49 Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Thu, 24 Jul 2025 13:08:28 +0400 Subject: [PATCH 5/8] 4 bit pcm: requseted changes --- src/engine/fileOps/pps.cpp | 2 +- src/engine/sample.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/engine/fileOps/pps.cpp b/src/engine/fileOps/pps.cpp index 6c0ded2de..3ee81862a 100644 --- a/src/engine/fileOps/pps.cpp +++ b/src/engine/fileOps/pps.cpp @@ -93,7 +93,7 @@ void DivEngine::loadPPS(SafeReader& reader, std::vector& ret, String s->rate = PPS_SAMPLE_RATE; s->centerRate = PPS_SAMPLE_RATE; s->depth = DIV_SAMPLE_DEPTH_4BIT; - s->init(headers[i].sample_length*2); //byte per sample + s->init(headers[i].sample_length); reader.seek((int)headers[i].start_pointer, SEEK_SET); diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 6a52ede6a..19e33032e 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -877,6 +877,7 @@ void DivSample::convert(DivSampleDepth newDepth, unsigned int formatMask) { break; case DIV_SAMPLE_DEPTH_4BIT: setSampleCount((samples+1)&(~1)); + break; default: break; } @@ -1338,9 +1339,9 @@ void DivSample::render(unsigned int formatMask) { unsigned short nibble=0; for (unsigned int i=0; i>1]&0xf; } else { - nibble=data4[i/2]>>4; + nibble=data4[i>>1]>>4; } data16[i]=(nibble<<12)^0x8000; } @@ -1558,7 +1559,7 @@ void DivSample::render(unsigned int formatMask) { _sample=(*samplePtr++^0x8000)>>12; sample4|=_sample; } - data4[i/2]=sample4; + data4[i>>1]=sample4; } } } From b6c49712d74aa8cd72e228992bebdc835ed79abe Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Thu, 24 Jul 2025 13:49:38 +0400 Subject: [PATCH 6/8] copy nibble and revert pps init length pps sample length may be in bytes --- src/engine/fileOps/pps.cpp | 2 +- src/engine/sample.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/fileOps/pps.cpp b/src/engine/fileOps/pps.cpp index 3ee81862a..b69ff3eb6 100644 --- a/src/engine/fileOps/pps.cpp +++ b/src/engine/fileOps/pps.cpp @@ -93,7 +93,7 @@ void DivEngine::loadPPS(SafeReader& reader, std::vector& ret, String s->rate = PPS_SAMPLE_RATE; s->centerRate = PPS_SAMPLE_RATE; s->depth = DIV_SAMPLE_DEPTH_4BIT; - s->init(headers[i].sample_length); + s->init(headers[i].sample_length*2); // bytes->samples reader.seek((int)headers[i].start_pointer, SEEK_SET); diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 19e33032e..9884bdc27 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -1343,7 +1343,7 @@ void DivSample::render(unsigned int formatMask) { } else { nibble=data4[i>>1]>>4; } - data16[i]=(nibble<<12)^0x8000; + data16[i]=((nibble<<12)|(nibble<<8)|(nibble<<4)|nibble)^0x8000; } break; } From 6d44ef5641877c41acfcc9fd77df225659a1050b Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Fri, 25 Jul 2025 12:26:49 +0400 Subject: [PATCH 7/8] another break --- src/engine/sample.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 9884bdc27..c0a05f277 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -293,6 +293,7 @@ int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) { break; case DIV_SAMPLE_DEPTH_4BIT: off=(offset+1)/2; + break; default: break; } From f7ded06987450b48b8f92980bc93beba28c1e1dd Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Fri, 25 Jul 2025 23:33:09 +0400 Subject: [PATCH 8/8] clamp only to minimum --- src/gui/gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 9a162c190..dfab96fa0 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -7010,7 +7010,7 @@ bool FurnaceGUI::loop() { ImGui::SameLine(); ImGui::SetNextItemWidth(120.0f*dpiScale); if (ImGui::InputInt("##RSChans",&pendingRawSampleChannels,1,2)) { - CLAMP_VAR(pendingRawSampleChannels, 1, 16) + if (pendingRawSampleChannels<1) pendingRawSampleChannels=1; } ImGui::Text(_("(will be mixed down to mono)")); ImGui::Checkbox(_("Unsigned"),&pendingRawSampleUnsigned);