fix opening/saving audio files with non-ASCII char

s on Windows

this required making a wrapper...
This commit is contained in:
tildearrow 2022-06-28 02:00:08 -05:00
parent f483292a88
commit be7d7002e2
6 changed files with 189 additions and 17 deletions

View file

@ -451,6 +451,10 @@ src/engine/platform/rf5c68.cpp
src/engine/platform/dummy.cpp src/engine/platform/dummy.cpp
) )
if (USE_SNDFILE)
list(APPEND ENGINE_SOURCES src/engine/sfWrapper.cpp)
endif()
if (WIN32) if (WIN32)
list(APPEND ENGINE_SOURCES src/utfutils.cpp) list(APPEND ENGINE_SOURCES src/utfutils.cpp)
list(APPEND ENGINE_SOURCES src/engine/winStuff.cpp) list(APPEND ENGINE_SOURCES src/engine/winStuff.cpp)

View file

@ -37,7 +37,7 @@
#endif #endif
#include <math.h> #include <math.h>
#ifdef HAVE_SNDFILE #ifdef HAVE_SNDFILE
#include <sndfile.h> #include "sfWrapper.h"
#endif #endif
#include <fmt/printf.h> #include <fmt/printf.h>
@ -200,11 +200,12 @@ void DivEngine::runExportThread() {
case DIV_EXPORT_MODE_ONE: { case DIV_EXPORT_MODE_ONE: {
SNDFILE* sf; SNDFILE* sf;
SF_INFO si; SF_INFO si;
SFWrapper sfWrap;
si.samplerate=got.rate; si.samplerate=got.rate;
si.channels=2; si.channels=2;
si.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16; si.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;
sf=sf_open(exportPath.c_str(),SFM_WRITE,&si); sf=sfWrap.doOpen(exportPath.c_str(),SFM_WRITE,&si);
if (sf==NULL) { if (sf==NULL) {
logE("could not open file for writing! (%s)",sf_strerror(NULL)); logE("could not open file for writing! (%s)",sf_strerror(NULL));
exporting=false; exporting=false;
@ -259,7 +260,7 @@ void DivEngine::runExportThread() {
delete[] outBuf[1]; delete[] outBuf[1];
delete[] outBuf[2]; delete[] outBuf[2];
if (sf_close(sf)!=0) { if (sfWrap.doClose()!=0) {
logE("could not close audio file!"); logE("could not close audio file!");
} }
exporting=false; exporting=false;
@ -280,6 +281,7 @@ void DivEngine::runExportThread() {
SNDFILE* sf[32]; SNDFILE* sf[32];
SF_INFO si[32]; SF_INFO si[32];
String fname[32]; String fname[32];
SFWrapper sfWrap[32];
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
sf[i]=NULL; sf[i]=NULL;
si[i].samplerate=got.rate; si[i].samplerate=got.rate;
@ -294,11 +296,11 @@ void DivEngine::runExportThread() {
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
fname[i]=fmt::sprintf("%s_s%02d.wav",exportPath,i+1); fname[i]=fmt::sprintf("%s_s%02d.wav",exportPath,i+1);
logI("- %s",fname[i].c_str()); logI("- %s",fname[i].c_str());
sf[i]=sf_open(fname[i].c_str(),SFM_WRITE,&si[i]); sf[i]=sfWrap[i].doOpen(fname[i].c_str(),SFM_WRITE,&si[i]);
if (sf[i]==NULL) { if (sf[i]==NULL) {
logE("could not open file for writing! (%s)",sf_strerror(NULL)); logE("could not open file for writing! (%s)",sf_strerror(NULL));
for (int j=0; j<i; j++) { for (int j=0; j<i; j++) {
sf_close(sf[i]); sfWrap[i].doClose();
} }
return; return;
} }
@ -369,7 +371,7 @@ void DivEngine::runExportThread() {
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
delete[] sysBuf[i]; delete[] sysBuf[i];
if (sf_close(sf[i])!=0) { if (sfWrap[i].doClose()!=0) {
logE("could not close audio file!"); logE("could not close audio file!");
} }
} }
@ -402,13 +404,14 @@ void DivEngine::runExportThread() {
for (int i=0; i<chans; i++) { for (int i=0; i<chans; i++) {
SNDFILE* sf; SNDFILE* sf;
SF_INFO si; SF_INFO si;
SFWrapper sfWrap;
String fname=fmt::sprintf("%s_c%02d.wav",exportPath,i+1); String fname=fmt::sprintf("%s_c%02d.wav",exportPath,i+1);
logI("- %s",fname.c_str()); logI("- %s",fname.c_str());
si.samplerate=got.rate; si.samplerate=got.rate;
si.channels=2; si.channels=2;
si.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16; si.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;
sf=sf_open(fname.c_str(),SFM_WRITE,&si); sf=sfWrap.doOpen(fname.c_str(),SFM_WRITE,&si);
if (sf==NULL) { if (sf==NULL) {
logE("could not open file for writing! (%s)",sf_strerror(NULL)); logE("could not open file for writing! (%s)",sf_strerror(NULL));
break; break;
@ -473,7 +476,7 @@ void DivEngine::runExportThread() {
} }
} }
if (sf_close(sf)!=0) { if (sfWrap.doClose()!=0) {
logE("could not close audio file!"); logE("could not close audio file!");
} }
@ -2189,8 +2192,9 @@ int DivEngine::addSampleFromFile(const char* path) {
return -1; return -1;
#else #else
SF_INFO si; SF_INFO si;
SFWrapper sfWrap;
memset(&si,0,sizeof(SF_INFO)); memset(&si,0,sizeof(SF_INFO));
SNDFILE* f=sf_open(path,SFM_READ,&si); SNDFILE* f=sfWrap.doOpen(path,SFM_READ,&si);
if (f==NULL) { if (f==NULL) {
BUSY_END; BUSY_END;
int err=sf_error(NULL); int err=sf_error(NULL);
@ -2203,7 +2207,7 @@ int DivEngine::addSampleFromFile(const char* path) {
} }
if (si.frames>16777215) { if (si.frames>16777215) {
lastError="this sample is too big! max sample size is 16777215."; lastError="this sample is too big! max sample size is 16777215.";
sf_close(f); sfWrap.doClose();
BUSY_END; BUSY_END;
return -1; return -1;
} }
@ -2301,7 +2305,7 @@ int DivEngine::addSampleFromFile(const char* path) {
if (sample->centerRate<4000) sample->centerRate=4000; if (sample->centerRate<4000) sample->centerRate=4000;
if (sample->centerRate>64000) sample->centerRate=64000; if (sample->centerRate>64000) sample->centerRate=64000;
sf_close(f); sfWrap.doClose();
saveLock.lock(); saveLock.lock();
song.sample.push_back(sample); song.sample.push_back(sample);
song.sampleLen=sampleCount+1; song.sampleLen=sampleCount+1;

View file

@ -24,9 +24,6 @@
#include "engine.h" #include "engine.h"
#include "../ta-log.h" #include "../ta-log.h"
#include <math.h> #include <math.h>
#ifdef HAVE_SNDFILE
#include <sndfile.h>
#endif
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0; constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;

View file

@ -22,7 +22,7 @@
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#ifdef HAVE_SNDFILE #ifdef HAVE_SNDFILE
#include <sndfile.h> #include "sfWrapper.h"
#endif #endif
#include "filter.h" #include "filter.h"
@ -45,6 +45,7 @@ bool DivSample::save(const char* path) {
#else #else
SNDFILE* f; SNDFILE* f;
SF_INFO si; SF_INFO si;
SFWrapper sfWrap;
memset(&si,0,sizeof(SF_INFO)); memset(&si,0,sizeof(SF_INFO));
if (length16<1) return false; if (length16<1) return false;
@ -60,7 +61,7 @@ bool DivSample::save(const char* path) {
break; break;
} }
f=sf_open(path,SFM_WRITE,&si); f=sfWrap.doOpen(path,SFM_WRITE,&si);
if (f==NULL) { if (f==NULL) {
logE("could not open wave file for saving! %s",sf_error_number(sf_error(f))); logE("could not open wave file for saving! %s",sf_error_number(sf_error(f)));
@ -100,7 +101,7 @@ bool DivSample::save(const char* path) {
break; break;
} }
sf_close(f); sfWrap.doClose();
return true; return true;
#endif #endif

112
src/engine/sfWrapper.cpp Normal file
View file

@ -0,0 +1,112 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 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 "sfWrapper.h"
#include "../fileutils.h"
sf_count_t _vioGetSize(void* user) {
return ((SFWrapper*)user)->ioGetSize();
}
sf_count_t _vioSeek(sf_count_t offset, int whence, void* user) {
return ((SFWrapper*)user)->ioSeek(offset,whence);
}
sf_count_t _vioRead(void* ptr, sf_count_t count, void* user) {
return ((SFWrapper*)user)->ioRead(ptr,count);
}
sf_count_t _vioWrite(const void* ptr, sf_count_t count, void* user) {
return ((SFWrapper*)user)->ioWrite(ptr,count);
}
sf_count_t _vioTell(void* user) {
return ((SFWrapper*)user)->ioTell();
}
sf_count_t SFWrapper::ioGetSize() {
return (sf_count_t)len;
}
sf_count_t SFWrapper::ioSeek(sf_count_t offset, int whence) {
return fseek(f,offset,whence);
}
sf_count_t SFWrapper::ioRead(void* ptr, sf_count_t count) {
return fread(ptr,1,count,f);
}
sf_count_t SFWrapper::ioWrite(const void* ptr, sf_count_t count) {
return fwrite(ptr,1,count,f);
}
sf_count_t SFWrapper::ioTell() {
return ftell(f);
}
int SFWrapper::doClose() {
int ret=sf_close(sf);
fclose(f);
return ret;
}
SNDFILE* SFWrapper::doOpen(const char* path, int mode, SF_INFO* sfinfo) {
vio.get_filelen=_vioGetSize;
vio.read=_vioRead;
vio.seek=_vioSeek;
vio.tell=_vioTell;
vio.write=_vioWrite;
const char* modeC="rb";
if (mode==SFM_WRITE) {
modeC="wb";
}
if (mode==SFM_RDWR) {
modeC="rb+";
}
f=ps_fopen(path,modeC);
if (f==NULL) {
return NULL;
}
if (fseek(f,0,SEEK_END)==-1) {
fclose(f);
f=NULL;
return NULL;
}
len=ftell(f);
if (len==(SIZE_MAX>>1)) {
len=0;
fclose(f);
f=NULL;
return NULL;
}
if (fseek(f,0,SEEK_SET)==-1) {
len=0;
fclose(f);
f=NULL;
return NULL;
}
sf=sf_open_virtual(&vio,mode,sfinfo,this);
return sf;
}

54
src/engine/sfWrapper.h Normal file
View file

@ -0,0 +1,54 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 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.
*/
// sfWrapper.h: libsndfile FILE* wrapper to work around Windows issue with
// non-ASCII chars in file path
// I wanted to do this in sndfile directly, but it's a
// submodule...
#ifndef _SFWRAPPER_H
#define _SFWRAPPER_H
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sndfile.h>
#include "../ta-utils.h"
class SFWrapper {
FILE* f;
size_t len;
SF_VIRTUAL_IO vio;
SNDFILE* sf;
public:
sf_count_t ioGetSize();
sf_count_t ioSeek(sf_count_t offset, int whence);
sf_count_t ioRead(void* ptr, sf_count_t count);
sf_count_t ioWrite(const void* ptr, sf_count_t count);
sf_count_t ioTell();
int doClose();
SNDFILE* doOpen(const char* path, int mode, SF_INFO* sfinfo);
SFWrapper():
f(NULL),
len(0),
sf(NULL) {}
};
#endif