mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-04 09:39:42 +02: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:
parent
24df87bb4c
commit
61177a15ad
@ -285,4 +285,20 @@ OSType sf_header_mactype(int format)
|
||||
return '\?\?\?\?';
|
||||
}
|
||||
|
||||
#include <wx/msgdlg.h>
|
||||
ODLock libSndFileMutex;
|
||||
|
||||
void SFFileCloser::operator() (SNDFILE *sf) const
|
||||
{
|
||||
auto err = SFCall<int>(sf_close, sf);
|
||||
if (err) {
|
||||
char buffer[1000];
|
||||
sf_error_str(sf, buffer, 1000);
|
||||
wxMessageBox(wxString::Format
|
||||
/* i18n-hint: %s will be the error message from libsndfile */
|
||||
(_("Error (file may not have been written): %s"),
|
||||
buffer));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __WXMAC__
|
||||
|
@ -8,6 +8,9 @@
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_FILE_FORMATS__
|
||||
#define __AUDACITY_FILE_FORMATS__
|
||||
|
||||
#include <wx/list.h>
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/string.h>
|
||||
@ -108,6 +111,25 @@ wxString sf_normalize_name(const char *name);
|
||||
# else
|
||||
# include <Types.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
OSType sf_header_mactype(int format);
|
||||
|
||||
// This function wrapper uses a mutex to serialize calls to the SndFile library.
|
||||
#include "../MemoryX.h"
|
||||
#include "../ondemand/ODTaskThread.h"
|
||||
class ODLock;
|
||||
class ODLocker;
|
||||
extern ODLock libSndFileMutex;
|
||||
template<typename R, typename F, typename... Args>
|
||||
inline R SFCall(F fun, Args&&... args)
|
||||
{
|
||||
ODLocker locker{ libSndFileMutex };
|
||||
return fun(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
//RAII for SNDFILE*
|
||||
struct SFFileCloser { void operator () (SNDFILE*) const; };
|
||||
using SFFile = std::unique_ptr<SNDFILE, SFFileCloser>;
|
||||
|
||||
#endif
|
||||
|
@ -212,13 +212,13 @@ int LegacyBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
SAMPLE_SIZE(mFormat));
|
||||
|
||||
wxFile f; // will be closed when it goes out of scope
|
||||
SNDFILE *sf = NULL;
|
||||
SFFile sf;
|
||||
|
||||
if (f.Open(mFileName.GetFullPath())) {
|
||||
// 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).
|
||||
sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE);
|
||||
sf.reset(SFCall<SNDFILE*>(sf_open_fd, f.fd(), SFM_READ, &info, FALSE));
|
||||
}
|
||||
|
||||
{
|
||||
@ -239,7 +239,7 @@ int LegacyBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
|
||||
sf_count_t seekstart = start +
|
||||
(mSummaryInfo.totalSummaryBytes / SAMPLE_SIZE(mFormat));
|
||||
sf_seek(sf, seekstart , SEEK_SET);
|
||||
SFCall<sf_count_t>(sf_seek, sf.get(), seekstart , SEEK_SET);
|
||||
|
||||
SampleBuffer buffer(len, floatSample);
|
||||
int framesRead = 0;
|
||||
@ -249,10 +249,11 @@ int LegacyBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
// converting to float and back, which is unneccesary)
|
||||
if (format == int16Sample &&
|
||||
sf_subtype_is_integer(info.format)) {
|
||||
framesRead = sf_readf_short(sf, (short *)data, len);
|
||||
}else if (format == int24Sample &&
|
||||
framesRead = SFCall<sf_count_t>(sf_readf_short, sf.get(), (short *)data, len);
|
||||
}
|
||||
else if (format == int24Sample &&
|
||||
sf_subtype_is_integer(info.format)) {
|
||||
framesRead = sf_readf_int(sf, (int *)data, len);
|
||||
framesRead = SFCall<sf_count_t>(sf_readf_int, sf.get(), (int *)data, len);
|
||||
|
||||
// libsndfile gave us the 3 byte sample in the 3 most
|
||||
// significant bytes -- we want it in the 3 least
|
||||
@ -264,13 +265,11 @@ int LegacyBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
// Otherwise, let libsndfile handle the conversion and
|
||||
// scaling, and pass us normalized data as floats. We can
|
||||
// then convert to whatever format we want.
|
||||
framesRead = sf_readf_float(sf, (float *)buffer.ptr(), len);
|
||||
framesRead = SFCall<sf_count_t>(sf_readf_float, sf.get(), (float *)buffer.ptr(), len);
|
||||
CopySamples(buffer.ptr(), floatSample,
|
||||
(samplePtr)data, format, framesRead);
|
||||
}
|
||||
|
||||
sf_close(sf);
|
||||
|
||||
return framesRead;
|
||||
}
|
||||
|
||||
|
@ -606,34 +606,28 @@ int ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
if(!mAliasedFileName.IsOk()){ // intentionally silenced
|
||||
memset(data,0,SAMPLE_SIZE(format)*len);
|
||||
UnlockRead();
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
wxString aliasPath = mAliasedFileName.GetFullPath();
|
||||
//there are thread-unsafe crashes here - not sure why. sf_open may be called on the same file
|
||||
//from different threads, but this seems okay, unless it is implemented strangely..
|
||||
static ODLock sfMutex;
|
||||
|
||||
wxFile f; // will be closed when it goes out of scope
|
||||
SNDFILE *sf = NULL;
|
||||
SFFile sf;
|
||||
|
||||
if (f.Exists(aliasPath) && f.Open(aliasPath)) {
|
||||
// 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).
|
||||
ODManager::LockLibSndFileMutex();
|
||||
sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
sf.reset(SFCall<SNDFILE*>(sf_open_fd, f.fd(), SFM_READ, &info, FALSE));
|
||||
}
|
||||
|
||||
if (!sf){
|
||||
if (!sf) {
|
||||
|
||||
memset(data,0,SAMPLE_SIZE(format)*len);
|
||||
|
||||
mSilentAliasLog=TRUE;
|
||||
mSilentAliasLog = TRUE;
|
||||
// Set a marker to display an error message
|
||||
if (!wxGetApp().ShouldShowMissingAliasedFileWarning())
|
||||
wxGetApp().MarkAliasedFilesMissingWarning(this);
|
||||
@ -644,9 +638,7 @@ int ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
|
||||
mSilentAliasLog=FALSE;
|
||||
|
||||
ODManager::LockLibSndFileMutex();
|
||||
sf_seek(sf, mAliasStart + start, SEEK_SET);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
SFCall<sf_count_t>(sf_seek, sf.get(), mAliasStart + start, SEEK_SET);
|
||||
|
||||
SampleBuffer buffer(len * info.channels, floatSample);
|
||||
|
||||
@ -658,9 +650,7 @@ int ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
// and the calling method wants 16-bit data, go ahead and
|
||||
// read 16-bit data directly. This is a pretty common
|
||||
// case, as most audio files are 16-bit.
|
||||
ODManager::LockLibSndFileMutex();
|
||||
framesRead = sf_readf_short(sf, (short *)buffer.ptr(), len);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
framesRead = SFCall<sf_count_t>(sf_readf_short, sf.get(), (short *)buffer.ptr(), len);
|
||||
|
||||
for (int i = 0; i < framesRead; i++)
|
||||
((short *)data)[i] =
|
||||
@ -670,19 +660,13 @@ int ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
// Otherwise, let libsndfile handle the conversion and
|
||||
// scaling, and pass us normalized data as floats. We can
|
||||
// then convert to whatever format we want.
|
||||
ODManager::LockLibSndFileMutex();
|
||||
framesRead = sf_readf_float(sf, (float *)buffer.ptr(), len);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
framesRead = SFCall<sf_count_t>(sf_readf_float, sf.get(), (float *)buffer.ptr(), len);
|
||||
float *bufferPtr = &((float *)buffer.ptr())[mAliasChannel];
|
||||
CopySamples((samplePtr)bufferPtr, floatSample,
|
||||
(samplePtr)data, format,
|
||||
framesRead, true, info.channels);
|
||||
}
|
||||
|
||||
ODManager::LockLibSndFileMutex();
|
||||
sf_close(sf);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
|
||||
UnlockRead();
|
||||
return framesRead;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ int PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
}
|
||||
|
||||
wxFile f; // will be closed when it goes out of scope
|
||||
SNDFILE *sf = NULL;
|
||||
SFFile sf;
|
||||
{
|
||||
Maybe<wxLogNull> silence{};
|
||||
if (mSilentAliasLog)
|
||||
@ -97,13 +97,11 @@ int PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
// 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).
|
||||
ODManager::LockLibSndFileMutex();
|
||||
sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
sf.reset(SFCall<SNDFILE*>(sf_open_fd, f.fd(), SFM_READ, &info, FALSE));
|
||||
}
|
||||
}
|
||||
|
||||
if (!sf){
|
||||
if (!sf) {
|
||||
memset(data, 0, SAMPLE_SIZE(format)*len);
|
||||
silence.reset();
|
||||
mSilentAliasLog = TRUE;
|
||||
@ -116,9 +114,7 @@ int PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
}
|
||||
mSilentAliasLog=FALSE;
|
||||
|
||||
ODManager::LockLibSndFileMutex();
|
||||
sf_seek(sf, mAliasStart + start, SEEK_SET);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
SFCall<sf_count_t>(sf_seek, sf.get(), mAliasStart + start, SEEK_SET);
|
||||
SampleBuffer buffer(len * info.channels, floatSample);
|
||||
|
||||
int framesRead = 0;
|
||||
@ -129,9 +125,7 @@ int PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
// and the calling method wants 16-bit data, go ahead and
|
||||
// read 16-bit data directly. This is a pretty common
|
||||
// case, as most audio files are 16-bit.
|
||||
ODManager::LockLibSndFileMutex();
|
||||
framesRead = sf_readf_short(sf, (short *)buffer.ptr(), len);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
framesRead = SFCall<sf_count_t>(sf_readf_short, sf.get(), (short *)buffer.ptr(), len);
|
||||
for (int i = 0; i < framesRead; i++)
|
||||
((short *)data)[i] =
|
||||
((short *)buffer.ptr())[(info.channels * i) + mAliasChannel];
|
||||
@ -140,18 +134,13 @@ int PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
// Otherwise, let libsndfile handle the conversion and
|
||||
// scaling, and pass us normalized data as floats. We can
|
||||
// then convert to whatever format we want.
|
||||
ODManager::LockLibSndFileMutex();
|
||||
framesRead = sf_readf_float(sf, (float *)buffer.ptr(), len);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
framesRead = SFCall<sf_count_t>(sf_readf_float, sf.get(), (float *)buffer.ptr(), len);
|
||||
float *bufferPtr = &((float *)buffer.ptr())[mAliasChannel];
|
||||
CopySamples((samplePtr)bufferPtr, floatSample,
|
||||
(samplePtr)data, format,
|
||||
framesRead, true, info.channels);
|
||||
}
|
||||
|
||||
ODManager::LockLibSndFileMutex();
|
||||
sf_close(sf);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
return framesRead;
|
||||
}
|
||||
|
||||
|
@ -407,7 +407,7 @@ int SimpleBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
|
||||
SF_INFO info;
|
||||
wxFile f; // will be closed when it goes out of scope
|
||||
SNDFILE *sf = NULL;
|
||||
SFFile sf;
|
||||
{
|
||||
Maybe<wxLogNull> silence{};
|
||||
if (mSilentLog)
|
||||
@ -419,7 +419,7 @@ int SimpleBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
// 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).
|
||||
sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE);
|
||||
sf.reset(SFCall<SNDFILE*>(sf_open_fd, f.fd(), SFM_READ, &info, FALSE));
|
||||
}
|
||||
|
||||
if (!sf) {
|
||||
@ -433,7 +433,7 @@ int SimpleBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
}
|
||||
mSilentLog=FALSE;
|
||||
|
||||
sf_seek(sf, start, SEEK_SET);
|
||||
SFCall<sf_count_t>(sf_seek, sf.get(), start, SEEK_SET);
|
||||
SampleBuffer buffer(len, floatSample);
|
||||
|
||||
int framesRead = 0;
|
||||
@ -443,13 +443,13 @@ int SimpleBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
// converting to float and back, which is unneccesary)
|
||||
if (format == int16Sample &&
|
||||
sf_subtype_is_integer(info.format)) {
|
||||
framesRead = sf_readf_short(sf, (short *)data, len);
|
||||
framesRead = SFCall<sf_count_t>(sf_readf_short, sf.get(), (short *)data, len);
|
||||
}
|
||||
else
|
||||
if (format == int24Sample &&
|
||||
sf_subtype_is_integer(info.format))
|
||||
{
|
||||
framesRead = sf_readf_int(sf, (int *)data, len);
|
||||
framesRead = SFCall<sf_count_t>(sf_readf_int, sf.get(), (int *)data, len);
|
||||
|
||||
// libsndfile gave us the 3 byte sample in the 3 most
|
||||
// significant bytes -- we want it in the 3 least
|
||||
@ -462,13 +462,11 @@ int SimpleBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
// Otherwise, let libsndfile handle the conversion and
|
||||
// scaling, and pass us normalized data as floats. We can
|
||||
// then convert to whatever format we want.
|
||||
framesRead = sf_readf_float(sf, (float *)buffer.ptr(), len);
|
||||
framesRead = SFCall<sf_count_t>(sf_readf_float, sf.get(), (float *)buffer.ptr(), len);
|
||||
CopySamples(buffer.ptr(), floatSample,
|
||||
(samplePtr)data, format, framesRead);
|
||||
}
|
||||
|
||||
sf_close(sf);
|
||||
|
||||
return framesRead;
|
||||
}
|
||||
}
|
||||
|
@ -250,8 +250,9 @@ void ExportPCMOptions::OnHeaderChoice(wxCommandEvent & WXUNUSED(evt))
|
||||
bool valid = ValidatePair(fmt);
|
||||
if (valid)
|
||||
{
|
||||
mEncodingNames.Add(sf_encoding_index_name(i));
|
||||
mEncodingChoice->Append(sf_encoding_index_name(i));
|
||||
const auto name = sf_encoding_index_name(i);
|
||||
mEncodingNames.Add(name);
|
||||
mEncodingChoice->Append(name);
|
||||
mEncodingFormats.Add(enc);
|
||||
for (j = 0; j < sfnum; j++)
|
||||
{
|
||||
@ -405,148 +406,127 @@ int ExportPCM::Export(AudacityProject *project,
|
||||
sf_format = kFormats[subformat].format;
|
||||
}
|
||||
|
||||
wxString formatStr;
|
||||
SF_INFO info;
|
||||
SNDFILE *sf = NULL;
|
||||
int err;
|
||||
|
||||
//This whole operation should not occur while a file is being loaded on OD,
|
||||
//(we are worried about reading from a file being written to,) so we block.
|
||||
//Furthermore, we need to do this because libsndfile is not threadsafe.
|
||||
ODManager::LockLibSndFileMutex();
|
||||
formatStr = sf_header_name(sf_format & SF_FORMAT_TYPEMASK);
|
||||
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
|
||||
// Use libsndfile to export file
|
||||
|
||||
info.samplerate = (unsigned int)(rate + 0.5);
|
||||
info.frames = (unsigned int)((t1 - t0)*rate + 0.5);
|
||||
info.channels = numChannels;
|
||||
info.format = sf_format;
|
||||
info.sections = 1;
|
||||
info.seekable = 0;
|
||||
|
||||
// If we can't export exactly the format they requested,
|
||||
// try the default format for that header type...
|
||||
if (!sf_format_check(&info))
|
||||
info.format = (info.format & SF_FORMAT_TYPEMASK);
|
||||
if (!sf_format_check(&info)) {
|
||||
wxMessageBox(_("Cannot export audio in this format."));
|
||||
return false;
|
||||
}
|
||||
|
||||
wxFile f; // will be closed when it goes out of scope
|
||||
|
||||
if (f.Open(fName, wxFile::write)) {
|
||||
// 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).
|
||||
ODManager::LockLibSndFileMutex();
|
||||
sf = sf_open_fd(f.fd(), SFM_WRITE, &info, FALSE);
|
||||
//add clipping for integer formats. We allow floats to clip.
|
||||
sf_command(sf, SFC_SET_CLIPPING, NULL,sf_subtype_is_integer(sf_format)?SF_TRUE:SF_FALSE) ;
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
}
|
||||
|
||||
if (!sf) {
|
||||
wxMessageBox(wxString::Format(_("Cannot export audio to %s"),
|
||||
fName.c_str()));
|
||||
return false;
|
||||
}
|
||||
// Retrieve tags if not given a set
|
||||
if (metadata == NULL)
|
||||
metadata = project->GetTags();
|
||||
|
||||
// Install the metata at the beginning of the file (except for
|
||||
// WAV and WAVEX formats)
|
||||
if ((sf_format & SF_FORMAT_TYPEMASK) != SF_FORMAT_WAV &&
|
||||
(sf_format & SF_FORMAT_TYPEMASK) != SF_FORMAT_WAVEX) {
|
||||
if (!AddStrings(project, sf, metadata, sf_format)) {
|
||||
sf_close(sf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sampleFormat format;
|
||||
if (sf_subtype_more_than_16_bits(info.format))
|
||||
format = floatSample;
|
||||
else
|
||||
format = int16Sample;
|
||||
|
||||
int maxBlockLen = 44100 * 5;
|
||||
|
||||
int updateResult = eProgressSuccess;
|
||||
|
||||
const WaveTrackConstArray waveTracks =
|
||||
tracks->GetWaveTrackConstArray(selectionOnly, false);
|
||||
{
|
||||
auto mixer = CreateMixer(waveTracks,
|
||||
tracks->GetTimeTrack(),
|
||||
t0, t1,
|
||||
info.channels, maxBlockLen, true,
|
||||
rate, format, true, mixerSpec);
|
||||
wxFile f; // will be closed when it goes out of scope
|
||||
SFFile sf; // wraps f
|
||||
|
||||
ProgressDialog progress(wxFileName(fName).GetName(),
|
||||
selectionOnly ?
|
||||
wxString::Format(_("Exporting the selected audio as %s"),
|
||||
formatStr.c_str()) :
|
||||
wxString::Format(_("Exporting the entire project as %s"),
|
||||
formatStr.c_str()));
|
||||
wxString formatStr;
|
||||
SF_INFO info;
|
||||
int err;
|
||||
|
||||
while (updateResult == eProgressSuccess) {
|
||||
sampleCount samplesWritten;
|
||||
sampleCount numSamples = mixer->Process(maxBlockLen);
|
||||
//This whole operation should not occur while a file is being loaded on OD,
|
||||
//(we are worried about reading from a file being written to,) so we block.
|
||||
//Furthermore, we need to do this because libsndfile is not threadsafe.
|
||||
formatStr = SFCall<wxString>(sf_header_name, sf_format & SF_FORMAT_TYPEMASK);
|
||||
|
||||
if (numSamples == 0)
|
||||
break;
|
||||
// Use libsndfile to export file
|
||||
|
||||
samplePtr mixed = mixer->GetBuffer();
|
||||
info.samplerate = (unsigned int)(rate + 0.5);
|
||||
info.frames = (unsigned int)((t1 - t0)*rate + 0.5);
|
||||
info.channels = numChannels;
|
||||
info.format = sf_format;
|
||||
info.sections = 1;
|
||||
info.seekable = 0;
|
||||
|
||||
ODManager::LockLibSndFileMutex();
|
||||
if (format == int16Sample)
|
||||
samplesWritten = sf_writef_short(sf, (short *)mixed, numSamples);
|
||||
else
|
||||
samplesWritten = sf_writef_float(sf, (float *)mixed, numSamples);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
|
||||
if (samplesWritten != numSamples) {
|
||||
char buffer2[1000];
|
||||
sf_error_str(sf, buffer2, 1000);
|
||||
wxMessageBox(wxString::Format(
|
||||
/* i18n-hint: %s will be the error message from libsndfile, which
|
||||
* is usually something unhelpful (and untranslated) like "system
|
||||
* error" */
|
||||
_("Error while writing %s file (disk full?).\nLibsndfile says \"%s\""),
|
||||
formatStr.c_str(),
|
||||
wxString::FromAscii(buffer2).c_str()));
|
||||
break;
|
||||
}
|
||||
|
||||
updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0);
|
||||
}
|
||||
}
|
||||
|
||||
// Install the WAV metata in a "LIST" chunk at the end of the file
|
||||
if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV ||
|
||||
(sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAVEX) {
|
||||
if (!AddStrings(project, sf, metadata, sf_format)) {
|
||||
sf_close(sf);
|
||||
// If we can't export exactly the format they requested,
|
||||
// try the default format for that header type...
|
||||
if (!sf_format_check(&info))
|
||||
info.format = (info.format & SF_FORMAT_TYPEMASK);
|
||||
if (!sf_format_check(&info)) {
|
||||
wxMessageBox(_("Cannot export audio in this format."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ODManager::LockLibSndFileMutex();
|
||||
err = sf_close(sf);
|
||||
ODManager::UnlockLibSndFileMutex();
|
||||
if (f.Open(fName, wxFile::write)) {
|
||||
// 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).
|
||||
sf.reset(SFCall<SNDFILE*>(sf_open_fd, f.fd(), SFM_WRITE, &info, FALSE));
|
||||
//add clipping for integer formats. We allow floats to clip.
|
||||
sf_command(sf.get(), SFC_SET_CLIPPING, NULL, sf_subtype_is_integer(sf_format)?SF_TRUE:SF_FALSE) ;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
char buffer[1000];
|
||||
sf_error_str(sf, buffer, 1000);
|
||||
wxMessageBox(wxString::Format
|
||||
/* i18n-hint: %s will be the error message from libsndfile */
|
||||
(_("Error (file may not have been written): %s"),
|
||||
buffer));
|
||||
if (!sf) {
|
||||
wxMessageBox(wxString::Format(_("Cannot export audio to %s"),
|
||||
fName.c_str()));
|
||||
return false;
|
||||
}
|
||||
// Retrieve tags if not given a set
|
||||
if (metadata == NULL)
|
||||
metadata = project->GetTags();
|
||||
|
||||
// Install the metata at the beginning of the file (except for
|
||||
// WAV and WAVEX formats)
|
||||
if ((sf_format & SF_FORMAT_TYPEMASK) != SF_FORMAT_WAV &&
|
||||
(sf_format & SF_FORMAT_TYPEMASK) != SF_FORMAT_WAVEX) {
|
||||
if (!AddStrings(project, sf.get(), metadata, sf_format)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sampleFormat format;
|
||||
if (sf_subtype_more_than_16_bits(info.format))
|
||||
format = floatSample;
|
||||
else
|
||||
format = int16Sample;
|
||||
|
||||
int maxBlockLen = 44100 * 5;
|
||||
|
||||
const WaveTrackConstArray waveTracks =
|
||||
tracks->GetWaveTrackConstArray(selectionOnly, false);
|
||||
{
|
||||
auto mixer = CreateMixer(waveTracks,
|
||||
tracks->GetTimeTrack(),
|
||||
t0, t1,
|
||||
info.channels, maxBlockLen, true,
|
||||
rate, format, true, mixerSpec);
|
||||
|
||||
ProgressDialog progress(wxFileName(fName).GetName(),
|
||||
selectionOnly ?
|
||||
wxString::Format(_("Exporting the selected audio as %s"),
|
||||
formatStr.c_str()) :
|
||||
wxString::Format(_("Exporting the entire project as %s"),
|
||||
formatStr.c_str()));
|
||||
|
||||
while (updateResult == eProgressSuccess) {
|
||||
sampleCount samplesWritten;
|
||||
sampleCount numSamples = mixer->Process(maxBlockLen);
|
||||
|
||||
if (numSamples == 0)
|
||||
break;
|
||||
|
||||
samplePtr mixed = mixer->GetBuffer();
|
||||
|
||||
if (format == int16Sample)
|
||||
samplesWritten = SFCall<sf_count_t>(sf_writef_short, sf.get(), (short *)mixed, numSamples);
|
||||
else
|
||||
samplesWritten = SFCall<sf_count_t>(sf_writef_float, sf.get(), (float *)mixed, numSamples);
|
||||
|
||||
if (samplesWritten != numSamples) {
|
||||
char buffer2[1000];
|
||||
sf_error_str(sf.get(), buffer2, 1000);
|
||||
wxMessageBox(wxString::Format(
|
||||
/* i18n-hint: %s will be the error message from libsndfile, which
|
||||
* is usually something unhelpful (and untranslated) like "system
|
||||
* error" */
|
||||
_("Error while writing %s file (disk full?).\nLibsndfile says \"%s\""),
|
||||
formatStr.c_str(),
|
||||
wxString::FromAscii(buffer2).c_str()));
|
||||
break;
|
||||
}
|
||||
|
||||
updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0);
|
||||
}
|
||||
}
|
||||
|
||||
// Install the WAV metata in a "LIST" chunk at the end of the file
|
||||
if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV ||
|
||||
(sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAVEX) {
|
||||
if (!AddStrings(project, sf.get(), metadata, sf_format)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF) ||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -51,17 +51,6 @@ int CompareNoCaseFileName(const wxString& first, const wxString& second)
|
||||
return first.CmpNoCase(second);
|
||||
}
|
||||
|
||||
void ODManager::LockLibSndFileMutex()
|
||||
{
|
||||
sLibSndFileMutex.Lock();
|
||||
}
|
||||
|
||||
void ODManager::UnlockLibSndFileMutex()
|
||||
{
|
||||
sLibSndFileMutex.Unlock();
|
||||
}
|
||||
|
||||
|
||||
//private constructor - Singleton.
|
||||
ODManager::ODManager()
|
||||
{
|
||||
|
@ -119,9 +119,6 @@ class ODManager final
|
||||
Pauser &operator= (const Pauser&) PROHIBITED;
|
||||
};
|
||||
|
||||
static void LockLibSndFileMutex();
|
||||
static void UnlockLibSndFileMutex();
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
Loading…
x
Reference in New Issue
Block a user