1
0
mirror of https://github.com/cookiengineer/audacity synced 2026-03-04 13:40:58 +01:00

More consistent mutual exclusion in calls to certain sf_ functions; ...

... also SFCall to simplify thread-safe calls, and SFFile for RAII of SNDFILE
objects.
This commit is contained in:
Paul Licameli
2016-04-12 15:59:17 -04:00
parent 24df87bb4c
commit 61177a15ad
11 changed files with 360 additions and 384 deletions

View File

@@ -89,7 +89,7 @@ public:
class PCMImportFileHandle final : public ImportFileHandle
{
public:
PCMImportFileHandle(wxString name, SNDFILE *file, SF_INFO info);
PCMImportFileHandle(wxString name, SFFile &&file, SF_INFO info);
~PCMImportFileHandle();
wxString GetFileDescription();
@@ -108,7 +108,7 @@ public:
void SetStreamUsage(wxInt32 WXUNUSED(StreamID), bool WXUNUSED(Use)){}
private:
SNDFILE *mFile;
SFFile mFile;
SF_INFO mInfo;
sampleFormat mFormat;
};
@@ -127,11 +127,11 @@ wxString PCMImportPlugin::GetPluginFormatDescription()
std::unique_ptr<ImportFileHandle> PCMImportPlugin::Open(const wxString &filename)
{
SF_INFO info;
SNDFILE *file = NULL;
wxFile f; // will be closed when it goes out of scope
SFFile file;
memset(&info, 0, sizeof(info));
wxFile f; // will be closed when it goes out of scope
#ifdef __WXGTK__
if (filename.Lower().EndsWith(wxT("mp3"))) {
@@ -154,11 +154,11 @@ std::unique_ptr<ImportFileHandle> PCMImportPlugin::Open(const wxString &filename
// Even though there is an sf_open() that takes a filename, use the one that
// takes a file descriptor since wxWidgets can open a file with a Unicode name and
// libsndfile can't (under Windows).
file = sf_open_fd(f.fd(), SFM_READ, &info, TRUE);
file.reset(SFCall<SNDFILE*>(sf_open_fd, f.fd(), SFM_READ, &info, TRUE));
}
// The file descriptor is now owned by "file", so we must tell "f" to leave
// it alone. The file descriptor is closed by sf_open_fd() even if an error
// it alone. The file descriptor is closed by the destructor of file even if an error
// occurs.
f.Detach();
@@ -184,13 +184,14 @@ std::unique_ptr<ImportFileHandle> PCMImportPlugin::Open(const wxString &filename
return nullptr;
}
return std::make_unique<PCMImportFileHandle>(filename, file, info);
// Success, so now transfer the duty to close the file from "file".
return std::make_unique<PCMImportFileHandle>(filename, std::move(file), info);
}
PCMImportFileHandle::PCMImportFileHandle(wxString name,
SNDFILE *file, SF_INFO info)
SFFile &&file, SF_INFO info)
: ImportFileHandle(name),
mFile(file),
mFile(std::move(file)),
mInfo(info)
{
//
@@ -211,7 +212,7 @@ PCMImportFileHandle::PCMImportFileHandle(wxString name,
wxString PCMImportFileHandle::GetFileDescription()
{
return sf_header_name(mInfo.format);
return SFCall<wxString>(sf_header_name, mInfo.format);
}
int PCMImportFileHandle::GetFileUncompressedBytes()
@@ -327,7 +328,7 @@ int PCMImportFileHandle::Import(TrackFactory *trackFactory,
{
outTracks.clear();
wxASSERT(mFile);
wxASSERT(mFile.get());
// Get the preference / warn the user about aliased files.
wxString copyEdit = AskCopyOrEdit();
@@ -454,10 +455,10 @@ int PCMImportFileHandle::Import(TrackFactory *trackFactory,
block = maxBlock;
if (mFormat == int16Sample)
block = sf_readf_short(mFile, (short *)srcbuffer.ptr(), block);
block = SFCall<sf_count_t>(sf_readf_short, mFile.get(), (short *)srcbuffer.ptr(), block);
//import 24 bit int as float and have the append function convert it. This is how PCMAliasBlockFile works too.
else
block = sf_readf_float(mFile, (float *)srcbuffer.ptr(), block);
block = SFCall<sf_count_t>(sf_readf_float, mFile.get(), (float *)srcbuffer.ptr(), block);
if (block) {
auto iter = channels.begin();
@@ -497,47 +498,47 @@ int PCMImportFileHandle::Import(TrackFactory *trackFactory,
const char *str;
str = sf_get_string(mFile, SF_STR_TITLE);
str = sf_get_string(mFile.get(), SF_STR_TITLE);
if (str) {
tags->SetTag(TAG_TITLE, UTF8CTOWX(str));
}
str = sf_get_string(mFile, SF_STR_ALBUM);
str = sf_get_string(mFile.get(), SF_STR_ALBUM);
if (str) {
tags->SetTag(TAG_ALBUM, UTF8CTOWX(str));
}
str = sf_get_string(mFile, SF_STR_ARTIST);
str = sf_get_string(mFile.get(), SF_STR_ARTIST);
if (str) {
tags->SetTag(TAG_ARTIST, UTF8CTOWX(str));
}
str = sf_get_string(mFile, SF_STR_COMMENT);
str = sf_get_string(mFile.get(), SF_STR_COMMENT);
if (str) {
tags->SetTag(TAG_COMMENTS, UTF8CTOWX(str));
}
str = sf_get_string(mFile, SF_STR_DATE);
str = sf_get_string(mFile.get(), SF_STR_DATE);
if (str) {
tags->SetTag(TAG_YEAR, UTF8CTOWX(str));
}
str = sf_get_string(mFile, SF_STR_COPYRIGHT);
str = sf_get_string(mFile.get(), SF_STR_COPYRIGHT);
if (str) {
tags->SetTag(TAG_COPYRIGHT, UTF8CTOWX(str));
}
str = sf_get_string(mFile, SF_STR_SOFTWARE);
str = sf_get_string(mFile.get(), SF_STR_SOFTWARE);
if (str) {
tags->SetTag(TAG_SOFTWARE, UTF8CTOWX(str));
}
str = sf_get_string(mFile, SF_STR_TRACKNUMBER);
str = sf_get_string(mFile.get(), SF_STR_TRACKNUMBER);
if (str) {
tags->SetTag(TAG_TRACK, UTF8CTOWX(str));
}
str = sf_get_string(mFile, SF_STR_GENRE);
str = sf_get_string(mFile.get(), SF_STR_GENRE);
if (str) {
tags->SetTag(TAG_GENRE, UTF8CTOWX(str));
}
@@ -690,5 +691,4 @@ int PCMImportFileHandle::Import(TrackFactory *trackFactory,
PCMImportFileHandle::~PCMImportFileHandle()
{
sf_close(mFile);
}

View File

@@ -98,175 +98,177 @@ void ImportRaw(wxWindow *parent, const wxString &fileName,
{
outTracks.clear();
int encoding = 0; // Guess Format
int numChannels = 0;
sampleFormat format;
sf_count_t offset = 0;
sampleCount totalFrames;
double rate = 44100.0;
double percent = 100.0;
SNDFILE *sndFile = NULL;
SF_INFO sndInfo;
int result;
try {
// Yes, FormatClassifier currently handles filenames in UTF8 format only, that's
// a TODO ...
FormatClassifier theClassifier(fileName.utf8_str());
encoding = theClassifier.GetResultFormatLibSndfile();
numChannels = theClassifier.GetResultChannels();
offset = 0;
} catch (...) {
// Something went wrong in FormatClassifier, use defaults instead.
encoding = 0;
}
if (encoding <= 0) {
// Unable to guess. Use mono, 16-bit samples with CPU endianness
// as the default.
encoding = SF_FORMAT_RAW | SF_ENDIAN_CPU | SF_FORMAT_PCM_16;
numChannels = 1;
offset = 0;
}
ImportRawDialog dlog(parent, encoding, numChannels, (int)offset, rate);
dlog.ShowModal();
if (!dlog.GetReturnCode())
return;
encoding = dlog.mEncoding;
numChannels = dlog.mChannels;
rate = dlog.mRate;
offset = (sf_count_t)dlog.mOffset;
percent = dlog.mPercent;
memset(&sndInfo, 0, sizeof(SF_INFO));
sndInfo.samplerate = (int)rate;
sndInfo.channels = (int)numChannels;
sndInfo.format = encoding | SF_FORMAT_RAW;
wxFile f; // will be closed when it goes out of scope
if (f.Open(fileName)) {
// Even though there is an sf_open() that takes a filename, use the one that
// takes a file descriptor since wxWidgets can open a file with a Unicode name and
// libsndfile can't (under Windows).
sndFile = sf_open_fd(f.fd(), SFM_READ, &sndInfo, FALSE);
}
if (!sndFile){
// TODO: Handle error
char str[1000];
sf_error_str((SNDFILE *)NULL, str, 1000);
printf("%s\n", str);
return;
}
result = sf_command(sndFile, SFC_SET_RAW_START_OFFSET, &offset, sizeof(offset));
if (result != 0) {
char str[1000];
sf_error_str(sndFile, str, 1000);
printf("%s\n", str);
}
sf_seek(sndFile, 0, SEEK_SET);
totalFrames = (sampleCount)(sndInfo.frames * percent / 100.0);
//
// Sample format:
//
// In general, go with the user's preferences. However, if
// the file is higher-quality, go with a format which preserves
// the quality of the original file.
//
format = (sampleFormat)
gPrefs->Read(wxT("/SamplingRate/DefaultProjectSampleFormat"), floatSample);
if (format != floatSample &&
sf_subtype_more_than_16_bits(encoding))
format = floatSample;
TrackHolders channels(numChannels);
auto iter = channels.begin();
for (int c = 0; c < numChannels; ++iter, ++c) {
const auto channel =
(*iter = trackFactory->NewWaveTrack(format, rate)).get();
if (numChannels > 1)
switch (c) {
case 0:
channel->SetChannel(Track::LeftChannel);
break;
case 1:
channel->SetChannel(Track::RightChannel);
break;
default:
channel->SetChannel(Track::MonoChannel);
}
}
const auto firstChannel = channels.begin()->get();
if (numChannels == 2) {
firstChannel->SetLinked(true);
}
sampleCount maxBlockSize = firstChannel->GetMaxBlockSize();
TrackHolders channels;
int updateResult = eProgressSuccess;
SampleBuffer srcbuffer(maxBlockSize * numChannels, format);
SampleBuffer buffer(maxBlockSize, format);
sampleCount framescompleted = 0;
wxString msg;
msg.Printf(_("Importing %s"), wxFileName::FileName(fileName).GetFullName().c_str());
/* i18n-hint: 'Raw' means 'unprocessed' here and should usually be tanslated.*/
ProgressDialog progress(_("Import Raw"), msg);
long block;
do {
block = maxBlockSize;
{
SF_INFO sndInfo;
int result;
if (block + framescompleted > totalFrames)
block = totalFrames - framescompleted;
int numChannels = 0;
if (format == int16Sample)
block = sf_readf_short(sndFile, (short *)srcbuffer.ptr(), block);
else
block = sf_readf_float(sndFile, (float *)srcbuffer.ptr(), block);
if (block) {
auto iter = channels.begin();
for(int c=0; c<numChannels; ++iter, ++c) {
if (format==int16Sample) {
for(int j=0; j<block; j++)
((short *)buffer.ptr())[j] =
((short *)srcbuffer.ptr())[numChannels*j+c];
}
else {
for(int j=0; j<block; j++)
((float *)buffer.ptr())[j] =
((float *)srcbuffer.ptr())[numChannels*j+c];
}
iter->get()->Append(buffer.ptr(), format, block);
}
framescompleted += block;
try {
// Yes, FormatClassifier currently handles filenames in UTF8 format only, that's
// a TODO ...
FormatClassifier theClassifier(fileName.utf8_str());
encoding = theClassifier.GetResultFormatLibSndfile();
numChannels = theClassifier.GetResultChannels();
offset = 0;
} catch (...) {
// Something went wrong in FormatClassifier, use defaults instead.
encoding = 0;
}
updateResult = progress.Update((wxULongLong_t)framescompleted,
(wxULongLong_t)totalFrames);
if (updateResult != eProgressSuccess)
break;
if (encoding <= 0) {
// Unable to guess. Use mono, 16-bit samples with CPU endianness
// as the default.
encoding = SF_FORMAT_RAW | SF_ENDIAN_CPU | SF_FORMAT_PCM_16;
numChannels = 1;
offset = 0;
}
} while (block > 0 && framescompleted < totalFrames);
ImportRawDialog dlog(parent, encoding, numChannels, (int)offset, rate);
dlog.ShowModal();
if (!dlog.GetReturnCode())
return;
sf_close(sndFile);
encoding = dlog.mEncoding;
numChannels = dlog.mChannels;
rate = dlog.mRate;
offset = (sf_count_t)dlog.mOffset;
percent = dlog.mPercent;
memset(&sndInfo, 0, sizeof(SF_INFO));
sndInfo.samplerate = (int)rate;
sndInfo.channels = (int)numChannels;
sndInfo.format = encoding | SF_FORMAT_RAW;
wxFile f; // will be closed when it goes out of scope
SFFile sndFile;
if (f.Open(fileName)) {
// Even though there is an sf_open() that takes a filename, use the one that
// takes a file descriptor since wxWidgets can open a file with a Unicode name and
// libsndfile can't (under Windows).
sndFile.reset(SFCall<SNDFILE*>(sf_open_fd, f.fd(), SFM_READ, &sndInfo, FALSE));
}
if (!sndFile){
// TODO: Handle error
char str[1000];
sf_error_str((SNDFILE *)NULL, str, 1000);
printf("%s\n", str);
return;
}
result = sf_command(sndFile.get(), SFC_SET_RAW_START_OFFSET, &offset, sizeof(offset));
if (result != 0) {
char str[1000];
sf_error_str(sndFile.get(), str, 1000);
printf("%s\n", str);
}
SFCall<sf_count_t>(sf_seek, sndFile.get(), 0, SEEK_SET);
totalFrames = (sampleCount)(sndInfo.frames * percent / 100.0);
//
// Sample format:
//
// In general, go with the user's preferences. However, if
// the file is higher-quality, go with a format which preserves
// the quality of the original file.
//
format = (sampleFormat)
gPrefs->Read(wxT("/SamplingRate/DefaultProjectSampleFormat"), floatSample);
if (format != floatSample &&
sf_subtype_more_than_16_bits(encoding))
format = floatSample;
channels.resize(numChannels);
auto iter = channels.begin();
for (int c = 0; c < numChannels; ++iter, ++c) {
const auto channel =
(*iter = trackFactory->NewWaveTrack(format, rate)).get();
if (numChannels > 1)
switch (c) {
case 0:
channel->SetChannel(Track::LeftChannel);
break;
case 1:
channel->SetChannel(Track::RightChannel);
break;
default:
channel->SetChannel(Track::MonoChannel);
}
}
const auto firstChannel = channels.begin()->get();
if (numChannels == 2) {
firstChannel->SetLinked(true);
}
sampleCount maxBlockSize = firstChannel->GetMaxBlockSize();
SampleBuffer srcbuffer(maxBlockSize * numChannels, format);
SampleBuffer buffer(maxBlockSize, format);
sampleCount framescompleted = 0;
wxString msg;
msg.Printf(_("Importing %s"), wxFileName::FileName(fileName).GetFullName().c_str());
/* i18n-hint: 'Raw' means 'unprocessed' here and should usually be tanslated.*/
ProgressDialog progress(_("Import Raw"), msg);
do {
block = maxBlockSize;
if (block + framescompleted > totalFrames)
block = totalFrames - framescompleted;
if (format == int16Sample)
block = SFCall<sf_count_t>(sf_readf_short, sndFile.get(), (short *)srcbuffer.ptr(), block);
else
block = SFCall<sf_count_t>(sf_readf_float, sndFile.get(), (float *)srcbuffer.ptr(), block);
if (block) {
auto iter = channels.begin();
for(int c=0; c<numChannels; ++iter, ++c) {
if (format==int16Sample) {
for(int j=0; j<block; j++)
((short *)buffer.ptr())[j] =
((short *)srcbuffer.ptr())[numChannels*j+c];
}
else {
for(int j=0; j<block; j++)
((float *)buffer.ptr())[j] =
((float *)srcbuffer.ptr())[numChannels*j+c];
}
iter->get()->Append(buffer.ptr(), format, block);
}
framescompleted += block;
}
updateResult = progress.Update((wxULongLong_t)framescompleted,
(wxULongLong_t)totalFrames);
if (updateResult != eProgressSuccess)
break;
} while (block > 0 && framescompleted < totalFrames);
}
int res = updateResult;
if (block < 0)