1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-09-14 15:29:53 +02:00

Importer functions return a vector of vector of pointers to tracks...

... grouping the channels; rather than one flat vector.

OGG, GStreamer and FFmpeg import were written to allow multiple multi-channel
tracks; others always imported one group of channels.

All of that is reflected in the results returned by the importers, though it
makes no difference yet in AudacityProject::AddImportedTracks (where the
results are used).
This commit is contained in:
Paul Licameli 2018-09-19 11:47:50 -04:00
parent b0c5f42b9a
commit 31d46ae624
15 changed files with 70 additions and 61 deletions

View File

@ -4168,7 +4168,6 @@ AudacityProject::AddImportedTracks(const wxString &fileName,
{ {
std::vector< std::shared_ptr< Track > > results; std::vector< std::shared_ptr< Track > > results;
const auto numTracks = newTracks.size();
SelectNone(); SelectNone();
bool initiallyEmpty = mTracks->empty(); bool initiallyEmpty = mTracks->empty();
@ -4177,9 +4176,11 @@ AudacityProject::AddImportedTracks(const wxString &fileName,
int i = -1; int i = -1;
// Must add all tracks first (before using Track::IsLeader) // Must add all tracks first (before using Track::IsLeader)
for (auto &uNewTrack : newTracks) { for (auto &group : newTracks) {
auto newTrack = mTracks->Add(std::move(uNewTrack)); for (auto &uNewTrack : group) {
results.push_back(Track::Pointer(newTrack)); auto newTrack = mTracks->Add(std::move(uNewTrack));
results.push_back(Track::Pointer(newTrack));
}
} }
newTracks.clear(); newTracks.clear();

View File

@ -49,6 +49,7 @@ and ImportLOF.cpp.
#include <wx/listimpl.cpp> #include <wx/listimpl.cpp>
#include "../ShuttleGui.h" #include "../ShuttleGui.h"
#include "../Project.h" #include "../Project.h"
#include "../WaveTrack.h"
#include "ImportPCM.h" #include "ImportPCM.h"
#include "ImportMP3.h" #include "ImportMP3.h"
@ -538,6 +539,15 @@ bool Importer::Import(const wxString &fName,
return true; return true;
} }
auto end = tracks.end();
auto iter = std::remove_if( tracks.begin(), end,
std::mem_fn( &NewChannelGroup::empty ) );
if ( iter != end ) {
// importer shouldn't give us empty groups of channels!
wxASSERT(false);
// But correct that and proceed anyway
tracks.erase( iter, end );
}
if (tracks.size() > 0) if (tracks.size() > 0)
{ {
// success! // success!

View File

@ -274,7 +274,10 @@ private:
bool mCancelled; //!< True if importing was canceled by user bool mCancelled; //!< True if importing was canceled by user
bool mStopped; //!< True if importing was stopped by user bool mStopped; //!< True if importing was stopped by user
wxString mName; wxString mName;
std::list<TrackHolders> mChannels; //!< 2-dimentional array of WaveTrack's. First dimention - streams, second - channels of a stream. Length is mNumStreams TrackHolders mChannels; //!< 2-dimensional array of WaveTrack's.
//!< First dimension - streams,
//!< second - channels of a stream.
//!< Length is mNumStreams
#ifdef EXPERIMENTAL_OD_FFMPEG #ifdef EXPERIMENTAL_OD_FFMPEG
bool mUsingOD; bool mUsingOD;
#endif #endif
@ -688,13 +691,10 @@ ProgressResult FFmpegImportFileHandle::Import(TrackFactory *trackFactory,
// Copy audio from mChannels to newly created tracks (destroying mChannels elements in process) // Copy audio from mChannels to newly created tracks (destroying mChannels elements in process)
for (auto &stream : mChannels) for (auto &stream : mChannels)
{
for(auto &channel : stream) for(auto &channel : stream)
{
channel->Flush(); channel->Flush();
outTracks.push_back(std::move(channel));
} outTracks.swap(mChannels);
}
// Save metadata // Save metadata
WriteMetadata(tags); WriteMetadata(tags);

View File

@ -181,7 +181,7 @@ private:
FLAC__uint64 mSamplesDone; FLAC__uint64 mSamplesDone;
bool mStreamInfoDone; bool mStreamInfoDone;
ProgressResult mUpdateResult; ProgressResult mUpdateResult;
TrackHolders mChannels; NewChannelGroup mChannels;
std::unique_ptr<ODDecodeFlacTask> mDecoderTask; std::unique_ptr<ODDecodeFlacTask> mDecoderTask;
}; };
@ -536,10 +536,11 @@ ProgressResult FLACImportFileHandle::Import(TrackFactory *trackFactory,
return mUpdateResult; return mUpdateResult;
} }
for (const auto &channel : mChannels) { for (const auto &channel : mChannels)
channel->Flush(); channel->Flush();
}
outTracks.swap(mChannels); if (!mChannels.empty())
outTracks.push_back(std::move(mChannels));
tags->Clear(); tags->Clear();
size_t cnt = mFile->mComments.GetCount(); size_t cnt = mFile->mComments.GetCount();

View File

@ -130,7 +130,7 @@ struct GStreamContext
GstElement *mConv{}; // Audio converter GstElement *mConv{}; // Audio converter
GstElement *mSink{}; // Application sink GstElement *mSink{}; // Application sink
bool mUse{}; // True if this stream should be imported bool mUse{}; // True if this stream should be imported
TrackHolders mChannels; // Array of WaveTrack pointers, one for each channel NewChannelGroup mChannels; // Array of WaveTrack pointers, one for each channel
unsigned mNumChannels{}; // Number of channels unsigned mNumChannels{}; // Number of channels
gdouble mSampleRate{}; // Sample rate gdouble mSampleRate{}; // Sample rate
GstString mType; // Audio type GstString mType; // Audio type
@ -1140,18 +1140,6 @@ GStreamerImportFileHandle::Import(TrackFactory *trackFactory,
// Grab the streams lock // Grab the streams lock
g_mutex_locker locker{ mStreamsLock }; g_mutex_locker locker{ mStreamsLock };
// Count the total number of tracks collected
unsigned outNumTracks = 0;
for (guint s = 0; s < mStreams.size(); s++)
{
GStreamContext *c = mStreams[s].get();
if (c)
outNumTracks += c->mNumChannels;
}
// Create NEW tracks
outTracks.resize(outNumTracks);
// Copy audio from mChannels to newly created tracks (destroying mChannels in process) // Copy audio from mChannels to newly created tracks (destroying mChannels in process)
int trackindex = 0; int trackindex = 0;
for (guint s = 0; s < mStreams.size(); s++) for (guint s = 0; s < mStreams.size(); s++)
@ -1160,12 +1148,8 @@ GStreamerImportFileHandle::Import(TrackFactory *trackFactory,
if (c->mNumChannels) if (c->mNumChannels)
{ {
for (int ch = 0; ch < c->mNumChannels; ch++) for (int ch = 0; ch < c->mNumChannels; ch++)
{
c->mChannels[ch]->Flush(); c->mChannels[ch]->Flush();
outTracks[trackindex++] = std::move(c->mChannels[ch]); outTracks.push_back(std::move(c->mChannels));
}
c->mChannels.clear();
} }
} }

View File

@ -223,8 +223,9 @@ auto LOFImportFileHandle::GetFileUncompressedBytes() -> ByteCount
return 0; return 0;
} }
ProgressResult LOFImportFileHandle::Import(TrackFactory * WXUNUSED(trackFactory), TrackHolders &outTracks, ProgressResult LOFImportFileHandle::Import(
Tags * WXUNUSED(tags)) TrackFactory * WXUNUSED(trackFactory), TrackHolders &outTracks,
Tags * WXUNUSED(tags))
{ {
// Unlike other ImportFileHandle subclasses, this one never gives any tracks // Unlike other ImportFileHandle subclasses, this one never gives any tracks
// back to the caller. // back to the caller.

View File

@ -98,7 +98,7 @@ struct private_data {
ArrayOf<unsigned char> inputBuffer{ static_cast<unsigned int>(INPUT_BUFFER_SIZE) }; ArrayOf<unsigned char> inputBuffer{ static_cast<unsigned int>(INPUT_BUFFER_SIZE) };
int inputBufferFill; /* amount of data in inputBuffer */ int inputBufferFill; /* amount of data in inputBuffer */
TrackFactory *trackFactory; TrackFactory *trackFactory;
TrackHolders channels; NewChannelGroup channels;
ProgressDialog *progress; ProgressDialog *progress;
unsigned numChannels; unsigned numChannels;
ProgressResult updateResult; ProgressResult updateResult;
@ -208,8 +208,9 @@ auto MP3ImportFileHandle::GetFileUncompressedBytes() -> ByteCount
return 0; return 0;
} }
ProgressResult MP3ImportFileHandle::Import(TrackFactory *trackFactory, TrackHolders &outTracks, ProgressResult MP3ImportFileHandle::Import(
Tags *tags) TrackFactory *trackFactory, TrackHolders &outTracks,
Tags *tags)
{ {
outTracks.clear(); outTracks.clear();
@ -252,7 +253,8 @@ ProgressResult MP3ImportFileHandle::Import(TrackFactory *trackFactory, TrackHold
for(const auto &channel : privateData.channels) { for(const auto &channel : privateData.channels) {
channel->Flush(); channel->Flush();
} }
outTracks.swap(privateData.channels); if (!privateData.channels.empty())
outTracks.push_back(std::move(privateData.channels));
/* Read in any metadata */ /* Read in any metadata */
ImportID3(tags); ImportID3(tags);

View File

@ -155,7 +155,7 @@ private:
ArrayOf<int> mStreamUsage; ArrayOf<int> mStreamUsage;
wxArrayString mStreamInfo; wxArrayString mStreamInfo;
std::list<TrackHolders> mChannels; std::list<NewChannelGroup> mChannels;
sampleFormat mFormat; sampleFormat mFormat;
}; };
@ -228,7 +228,8 @@ auto OggImportFileHandle::GetFileUncompressedBytes() -> ByteCount
return 0; return 0;
} }
ProgressResult OggImportFileHandle::Import(TrackFactory *trackFactory, TrackHolders &outTracks, ProgressResult OggImportFileHandle::Import(
TrackFactory *trackFactory, TrackHolders &outTracks,
Tags *tags) Tags *tags)
{ {
outTracks.clear(); outTracks.clear();
@ -374,10 +375,9 @@ ProgressResult OggImportFileHandle::Import(TrackFactory *trackFactory, TrackHold
for (auto &link : mChannels) for (auto &link : mChannels)
{ {
for (auto &channel : link) { for (auto &channel : link)
channel->Flush(); channel->Flush();
outTracks.push_back(std::move(channel)); outTracks.push_back(std::move(link));
}
} }
//\todo { Extract comments from each stream? } //\todo { Extract comments from each stream? }

View File

@ -364,7 +364,7 @@ ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory,
CreateProgress(); CreateProgress();
TrackHolders channels(mInfo.channels); NewChannelGroup channels(mInfo.channels);
auto iter = channels.begin(); auto iter = channels.begin();
for (int c = 0; c < mInfo.channels; ++iter, ++c) { for (int c = 0; c < mInfo.channels; ++iter, ++c) {
@ -529,10 +529,11 @@ ProgressResult PCMImportFileHandle::Import(TrackFactory *trackFactory,
return updateResult; return updateResult;
} }
for(const auto &channel : channels) { for(const auto &channel : channels)
channel->Flush(); channel->Flush();
}
outTracks.swap(channels); if (!channels.empty())
outTracks.push_back(std::move(channels));
const char *str; const char *str;

View File

@ -157,6 +157,8 @@ public:
// The given Tags structure may also be modified. // The given Tags structure may also be modified.
// In case of errors or exceptions, it is not necessary to leave outTracks // In case of errors or exceptions, it is not necessary to leave outTracks
// or tags unmodified. // or tags unmodified.
// If resulting outTracks is not empty,
// then each member of it must be a nonempty vector.
virtual ProgressResult Import(TrackFactory *trackFactory, TrackHolders &outTracks, virtual ProgressResult Import(TrackFactory *trackFactory, TrackHolders &outTracks,
Tags *tags) = 0; Tags *tags) = 0;

View File

@ -336,7 +336,7 @@ ProgressResult QTImportFileHandle::Import(TrackFactory *trackFactory,
(sizeof(AudioBuffer) * numchan))) }; (sizeof(AudioBuffer) * numchan))) };
abl->mNumberBuffers = numchan; abl->mNumberBuffers = numchan;
TrackHolders channels{ numchan }; NewChannelGroup channels{ numchan };
const auto size = sizeof(float) * bufsize; const auto size = sizeof(float) * bufsize;
ArraysOf<unsigned char> holders{ numchan, size }; ArraysOf<unsigned char> holders{ numchan, size };
@ -395,11 +395,10 @@ ProgressResult QTImportFileHandle::Import(TrackFactory *trackFactory,
res = (updateResult == ProgressResult::Success && err == noErr); res = (updateResult == ProgressResult::Success && err == noErr);
if (res) { if (res) {
for (const auto &channel: channels) { for (auto &channel: channels)
channel->Flush(); channel->Flush();
} if (!channels.empty())
outTracks.push_back(std::move(channels));
outTracks.swap(channels);
} }
// //

View File

@ -107,7 +107,7 @@ void ImportRaw(wxWindow *parent, const wxString &fileName,
sf_count_t offset = 0; sf_count_t offset = 0;
double rate = 44100.0; double rate = 44100.0;
double percent = 100.0; double percent = 100.0;
TrackHolders channels; TrackHolders results;
auto updateResult = ProgressResult::Success; auto updateResult = ProgressResult::Success;
{ {
@ -200,6 +200,8 @@ void ImportRaw(wxWindow *parent, const wxString &fileName,
sf_subtype_more_than_16_bits(encoding)) sf_subtype_more_than_16_bits(encoding))
format = floatSample; format = floatSample;
results.resize(1);
auto &channels = results[0];
channels.resize(numChannels); channels.resize(numChannels);
auto iter = channels.begin(); auto iter = channels.begin();
@ -295,9 +297,11 @@ void ImportRaw(wxWindow *parent, const wxString &fileName,
if (updateResult == ProgressResult::Failed || updateResult == ProgressResult::Cancelled) if (updateResult == ProgressResult::Failed || updateResult == ProgressResult::Cancelled)
throw UserException{}; throw UserException{};
for (const auto &channel : channels) if (!results.empty() && !results[0].empty()) {
channel->Flush(); for (const auto &channel : results[0])
outTracks.swap(channels); channel->Flush();
outTracks.swap(results);
}
} }
// //

View File

@ -21,7 +21,10 @@ class wxWindow;
#include <vector> #include <vector>
using TrackHolders = std::vector<std::unique_ptr<WaveTrack>>; // Newly constructed WaveTracks that are not yet owned by a TrackList
// are held in unique_ptr not shared_ptr
using NewChannelGroup = std::vector< std::unique_ptr<WaveTrack> >;
using TrackHolders = std::vector< NewChannelGroup >;
void ImportRaw(wxWindow *parent, const wxString &fileName, void ImportRaw(wxWindow *parent, const wxString &fileName,

View File

@ -109,17 +109,17 @@ private:
int mStreamIndex; int mStreamIndex;
}; };
auto ODDecodeFFmpegTask::FromList(const std::list<TrackHolders> &channels) -> Streams auto ODDecodeFFmpegTask::FromList( const TrackHolders &channels ) -> Streams
{ {
Streams streams; Streams streams;
streams.reserve(channels.size()); streams.reserve(channels.size());
using namespace std; using namespace std;
transform(channels.begin(), channels.end(), back_inserter(streams), transform(channels.begin(), channels.end(), back_inserter(streams),
[](const TrackHolders &holders) { [](const NewChannelGroup &holders) {
Channels channels; Channels channels;
channels.reserve(holders.size()); channels.reserve(holders.size());
transform(holders.begin(), holders.end(), back_inserter(channels), transform(holders.begin(), holders.end(), back_inserter(channels),
mem_fn(&TrackHolders::value_type::get) mem_fn(&NewChannelGroup::value_type::get)
); );
return channels; return channels;
} }

View File

@ -31,7 +31,8 @@ public:
using Channels = std::vector < WaveTrack* >; using Channels = std::vector < WaveTrack* >;
using Streams = std::vector < Channels >; using Streams = std::vector < Channels >;
static Streams FromList(const std::list<TrackHolders> &channels); static Streams FromList(
const std::vector< std::vector< std::unique_ptr<WaveTrack> > > &channels);
/// Constructs an ODTask /// Constructs an ODTask
ODDecodeFFmpegTask(const ScsPtr &scs, Streams &&channels, const std::shared_ptr<FFmpegContext> &context, int streamIndex); ODDecodeFFmpegTask(const ScsPtr &scs, Streams &&channels, const std::shared_ptr<FFmpegContext> &context, int streamIndex);