mirror of
https://github.com/tildearrow/furnace.git
synced 2024-12-01 00:43:02 +00:00
implement raw sample import
untested
This commit is contained in:
parent
ce2d322e47
commit
91f9352eaf
3 changed files with 205 additions and 19 deletions
|
@ -2639,6 +2639,172 @@ DivSample* DivEngine::sampleFromFile(const char* path) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian) {
|
||||||
|
if (song.sample.size()>=256) {
|
||||||
|
lastError="too many samples!";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (channels<1) {
|
||||||
|
lastError="invalid channel count";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (depth!=DIV_SAMPLE_DEPTH_8BIT && depth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||||
|
if (channels!=1) {
|
||||||
|
lastError="channel count has to be 1 for non-8/16-bit format";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BUSY_BEGIN;
|
||||||
|
warnings="";
|
||||||
|
|
||||||
|
const char* pathRedux=strrchr(path,DIR_SEPARATOR);
|
||||||
|
if (pathRedux==NULL) {
|
||||||
|
pathRedux=path;
|
||||||
|
} else {
|
||||||
|
pathRedux++;
|
||||||
|
}
|
||||||
|
String stripPath;
|
||||||
|
const char* pathReduxEnd=strrchr(pathRedux,'.');
|
||||||
|
if (pathReduxEnd==NULL) {
|
||||||
|
stripPath=pathRedux;
|
||||||
|
} else {
|
||||||
|
for (const char* i=pathRedux; i!=pathReduxEnd && (*i); i++) {
|
||||||
|
stripPath+=*i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len=0;
|
||||||
|
size_t lenDivided=0;
|
||||||
|
DivSample* sample=new DivSample;
|
||||||
|
sample->name=stripPath;
|
||||||
|
|
||||||
|
FILE* f=ps_fopen(path,"rb");
|
||||||
|
if (f==NULL) {
|
||||||
|
BUSY_END;
|
||||||
|
lastError=fmt::sprintf("could not open file! (%s)",strerror(errno));
|
||||||
|
delete sample;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek(f,0,SEEK_END)<0) {
|
||||||
|
fclose(f);
|
||||||
|
BUSY_END;
|
||||||
|
lastError=fmt::sprintf("could not get file length! (%s)",strerror(errno));
|
||||||
|
delete sample;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
len=ftell(f);
|
||||||
|
|
||||||
|
if (len==0) {
|
||||||
|
fclose(f);
|
||||||
|
BUSY_END;
|
||||||
|
lastError="file is empty!";
|
||||||
|
delete sample;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len==(SIZE_MAX>>1)) {
|
||||||
|
fclose(f);
|
||||||
|
BUSY_END;
|
||||||
|
lastError="file is invalid!";
|
||||||
|
delete sample;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek(f,0,SEEK_SET)<0) {
|
||||||
|
fclose(f);
|
||||||
|
BUSY_END;
|
||||||
|
lastError=fmt::sprintf("could not seek to beginning of file! (%s)",strerror(errno));
|
||||||
|
delete sample;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lenDivided=len/channels;
|
||||||
|
|
||||||
|
unsigned int samples=lenDivided;
|
||||||
|
switch (depth) {
|
||||||
|
case DIV_SAMPLE_DEPTH_1BIT:
|
||||||
|
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
|
||||||
|
samples=lenDivided*8;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
|
||||||
|
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
|
||||||
|
case DIV_SAMPLE_DEPTH_ADPCM_A:
|
||||||
|
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||||
|
case DIV_SAMPLE_DEPTH_VOX:
|
||||||
|
samples=lenDivided*2;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_8BIT:
|
||||||
|
samples=lenDivided;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_BRR:
|
||||||
|
samples=16*((lenDivided+8)/9);
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_16BIT:
|
||||||
|
samples=(lenDivided+1)/2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (samples>16777215) {
|
||||||
|
fclose(f);
|
||||||
|
BUSY_END;
|
||||||
|
lastError="this sample is too big! max sample size is 16777215.";
|
||||||
|
delete sample;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sample->rate=32000;
|
||||||
|
sample->centerRate=32000;
|
||||||
|
sample->depth=depth;
|
||||||
|
sample->init(samples);
|
||||||
|
|
||||||
|
unsigned char* buf=new unsigned char[len];
|
||||||
|
if (fread(buf,1,len,f)==0) {
|
||||||
|
fclose(f);
|
||||||
|
BUSY_END;
|
||||||
|
lastError=fmt::sprintf("could not read file! (%s)",strerror(errno));
|
||||||
|
delete[] buf;
|
||||||
|
delete sample;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
// import sample
|
||||||
|
size_t pos=0;
|
||||||
|
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||||
|
for (unsigned int i=0; i<samples; i++) {
|
||||||
|
int accum=0;
|
||||||
|
for (int j=0; j<channels; j++) {
|
||||||
|
if (pos+1>=len) break;
|
||||||
|
accum+=((short*)buf)[pos>>1];
|
||||||
|
pos+=2;
|
||||||
|
}
|
||||||
|
accum/=channels;
|
||||||
|
sample->data16[i]=accum;
|
||||||
|
}
|
||||||
|
} else if (depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||||
|
for (unsigned int i=0; i<samples; i++) {
|
||||||
|
int accum=0;
|
||||||
|
for (int j=0; j<channels; j++) {
|
||||||
|
if (pos>=len) break;
|
||||||
|
accum+=(signed char)buf[pos++];
|
||||||
|
}
|
||||||
|
accum/=channels;
|
||||||
|
sample->data8[i]=accum;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(sample->getCurBuf(),buf,len);
|
||||||
|
}
|
||||||
|
delete[] buf;
|
||||||
|
|
||||||
|
BUSY_END;
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
void DivEngine::delSample(int index) {
|
void DivEngine::delSample(int index) {
|
||||||
BUSY_BEGIN;
|
BUSY_BEGIN;
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
|
|
|
@ -4152,29 +4152,47 @@ bool FurnaceGUI::loop() {
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool doRespond=false;
|
|
||||||
if (ImGui::BeginPopupModal("Import Raw Sample",NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
|
if (ImGui::BeginPopupModal("Import Raw Sample",NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||||
ImGui::Text("Work In Progress - sorry");
|
ImGui::Text("Data type:");
|
||||||
if (ImGui::Button("Oh... really?")) {
|
for (int i=0; i<DIV_SAMPLE_DEPTH_MAX; i++) {
|
||||||
|
if (sampleDepths[i]==NULL) continue;
|
||||||
|
if (ImGui::RadioButton(sampleDepths[i],pendingRawSampleDepth==i)) pendingRawSampleDepth=i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_8BIT && pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||||
|
pendingRawSampleChannels=1;
|
||||||
|
}
|
||||||
|
if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||||
|
pendingRawSampleBigEndian=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_8BIT && pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT);
|
||||||
|
ImGui::Text("Channels");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::InputInt("##RSChans",&pendingRawSampleChannels)) {
|
||||||
|
}
|
||||||
|
ImGui::Text("(will be mixed down to mono)");
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT);
|
||||||
|
ImGui::Checkbox("Big endian",&pendingRawSampleBigEndian);
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
if (ImGui::Button("OK")) {
|
||||||
|
DivSample* s=e->sampleFromFileRaw(pendingRawSample.c_str(),(DivSampleDepth)pendingRawSampleDepth,pendingRawSampleChannels,pendingRawSampleBigEndian);
|
||||||
|
if (s==NULL) {
|
||||||
|
showError(e->getLastError());
|
||||||
|
} else {
|
||||||
|
if (e->addSamplePtr(s)==-1) {
|
||||||
|
showError(e->getLastError());
|
||||||
|
} else {
|
||||||
|
MARK_MODIFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Why are you so hostile? I'm just trying to import a raw sample.")) {
|
if (ImGui::Button("Cancel")) {
|
||||||
doRespond=true;
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doRespond) {
|
|
||||||
doRespond=false;
|
|
||||||
ImGui::OpenPopup("Fatal Alert");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginPopupModal("Fatal Alert",NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
||||||
ImGui::Text("Well, I'd rather you didn't. So, good night.");
|
|
||||||
if (ImGui::Button("Fine")) {
|
|
||||||
abort();
|
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
|
|
|
@ -974,6 +974,8 @@ class FurnaceGUI {
|
||||||
int waveEditStyle;
|
int waveEditStyle;
|
||||||
|
|
||||||
String pendingRawSample;
|
String pendingRawSample;
|
||||||
|
int pendingRawSampleDepth, pendingRawSampleChannels;
|
||||||
|
bool pendingRawSampleBigEndian;
|
||||||
|
|
||||||
ImGuiWindowFlags globalWinFlags;
|
ImGuiWindowFlags globalWinFlags;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue