Thread: [Audacity-devel] refactoring
A free multi-track audio editor and recorder
Brought to you by:
aosiniao
From: Joshua H. <jo...@re...> - 2003-10-26 05:41:03
|
I've been working a lot today on the beginning stages of what will become the long-discussed Track rewrite. I don't have anything ready to show yet, but I wanted to throw some ideas out that I've been thinking about through these initial changes. My first task has been reworking TrackList. The two main changes are that it now uses wxList so we don't have to maintain our own linked list implementation, and we get the benefit of more methods already being written. The more beneficial change is a new type-safe interface to getting specific kinds of tracks from the TrackList: WX_DEFINE_ARRAY(WaveTrack*, WaveTrackArray) WX_DEFINE_ARRAY(NoteTrack*, NoteTrackArray) WX_DEFINE_ARRAY(LabelTrack*, LabelTrackArray) WaveTrackArray GetWaveTracks(bool selectedOnly); NoteTrackArray GetNoteTracks(bool selectedOnly); LabelTrackArray GetLabelTracks(bool selectedOnly); Not only does this make code simpler since you don't have to iterate over a list of tracks checking t->GetKind(), but it's safer because you no longer have to statically downcast from Track* to the more specific type. This will actually become crucial once we create the new hierarchy we have planned, because for some reason (that I don't yet understand) the compiler won't let me statically downcast from a base to a virtually derived class. As a refresher, we are planning to virtually derive from Track so that GuiTrack and WaveTrack both share the same copy of Track. You may wonder how we can downcast at all if not statically. Well the answer is to introduce dynamic_cast. We haven't used any RTTI to this point (AFAIK) but I think we are beginning to need it. I know it's supported on both VC++ and g++, so there's no reason to avoid it that I know of. In reality we were using a sort of ad-hoc RTTI already by having the virtual GetKind() method for GetTrack; now we're just letting the compiler do the work for us, and benefiting from the extra safety. Back to TrackList for a second, the intention is that TrackList (as opposed to {Wave,Note,Label}TrackArray) is still the primary structure for passing around lists of tracks, but that it is easy to select the more specific tracks at any time. For example, I think passing a WaveTrackArray to AudioIO is a bad idea, because (for example) the AudioIO may want different kinds of tracks also. It already wants the TimeTrack, and in the future it may want NoteTracks. So prefer TrackList for parameters to functions, using {Wave,Note,Label}TrackArray temporarily in localized algorithms. --------- A shortcoming of our current approach that has been clear for a while is the way we deal with stereo tracks. Making all code that deals with lists of tracks be aware of the "linked" flag is not great abstraction and it makes for some ugly code. We've discussed having a StereoTrack that simply contains two WaveTracks and calls methods on both of them. However I am beginning to think this is the wrong approach. First of all, it introduces more complexity into what will already be a plenty complex inheritance graph. Also, it just doesn't make sense based on the way we look at tracks: a track: * has one label area and set of controls to control it * is the smallest selectable entity * is the unit of exchange between core functions of the infrastructure Based on these characteristics, it doesn't make any sense to have one track "contain" another. For example, the two GuiWaveTracks contained by a GuiStereoTrack are both going to want to draw the label and receive label mouse clicks, because that's what GuiWaveTracks do. What I think makes sense is to have only one kind of WaveTrack, that can contain one, two (stereo) or more complex arrangements (5.1) of channels. Each channel is then a sequence. While we're at it, we could get even more ambitious and make Audacity region-capable. Then the model would be: WaveTrack HAS MANY Channel(s) HAVE MANY Region(s) at arbitrary (but nonoverlapping) offsets This would make each region a Sequence. How fortunate that Sequence has already been separated from WaveTrack! :) To consider for a second the effect this would have on other parts of the program: AudioIO would get a list of WaveTracks to play, and would break them apart into their channels to play them. It already has to do about the same amount of work, because it has to iterate over the list and make decisions based on whether each track is a LeftChannel, RightChannel or MonoChannel and whether or not it is linked. Exporters would also get a list of WaveTracks to export, and would break them down to decide what kind of file to write (some output formats may actually support things like 5.1) and proceed accordingly. Effects are the part I'm the least sure about because I'm the least familiar with that code. Thoughts? Josh |
From: James C. <cr...@in...> - 2003-10-27 20:19:26
|
Joshua Haberman wrote: > I've been working a lot today on the beginning stages of what will > become the long-discussed Track rewrite. I don't have anything ready to > show yet, but I wanted to throw some ideas out that I've been thinking > about through these initial changes. [..snip..] > Thoughts? > > Josh I'd welcome these refactoring changes. They sound good and will make the code easier to work with for us all. --James |
From: Dominic M. <do...@mi...> - 2003-10-28 08:29:56
|
Looks like this one never made it to the list. Weird. --- Hi Josh, Looks like you've made some great progress. I'm still behind on catching up on your Ogg progress; I've been working on 1.2.0 issues and playing with Mac OS X 10.3 "Panther" and XCode (both of which totally rock, BTW). On Oct 25, 2003, at 10:34 PM, Joshua Haberman wrote: > I've been working a lot today on the beginning stages of what will > become the long-discussed Track rewrite. I don't have anything ready > to > show yet, but I wanted to throw some ideas out that I've been thinking > about through these initial changes. > > My first task has been reworking TrackList. The two main changes are > that it now uses wxList so we don't have to maintain our own linked > list > implementation, and we get the benefit of more methods already being > written. That sounds good. Before it's too late, what would you think about making it a dynamic array instead of a list? Conceptually a list seems okay but realistically certain operations, like move up/down, are a pain to implement for lists. > The more beneficial change is a new type-safe interface to > getting specific kinds of tracks from the TrackList: > > WX_DEFINE_ARRAY(WaveTrack*, WaveTrackArray) > WX_DEFINE_ARRAY(NoteTrack*, NoteTrackArray) > WX_DEFINE_ARRAY(LabelTrack*, LabelTrackArray) > WaveTrackArray GetWaveTracks(bool selectedOnly); > NoteTrackArray GetNoteTracks(bool selectedOnly); > LabelTrackArray GetLabelTracks(bool selectedOnly); Those are great. The fact that all of these methods return arrays makes me even more sure that it would be better if TrackList is really TrackArray. > Not only does this make code simpler since you don't have to iterate > over a list of tracks checking t->GetKind(), but it's safer because you > no longer have to statically downcast from Track* to the more specific > type. This will actually become crucial once we create the new > hierarchy we have planned, because for some reason (that I don't yet > understand) the compiler won't let me statically downcast from a base > to > a virtually derived class. As a refresher, we are planning to > virtually > derive from Track so that GuiTrack and WaveTrack both share the same > copy of Track. > > You may wonder how we can downcast at all if not statically. Well the > answer is to introduce dynamic_cast. We haven't used any RTTI to this > point (AFAIK) but I think we are beginning to need it. I know it's > supported on both VC++ and g++, so there's no reason to avoid it that I > know of. In reality we were using a sort of ad-hoc RTTI already by > having the virtual GetKind() method for GetTrack; now we're just > letting > the compiler do the work for us, and benefiting from the extra safety. > > Back to TrackList for a second, the intention is that TrackList (as > opposed to {Wave,Note,Label}TrackArray) is still the primary structure > for passing around lists of tracks, but that it is easy to select the > more specific tracks at any time. For example, I think passing a > WaveTrackArray to AudioIO is a bad idea, because (for example) the > AudioIO may want different kinds of tracks also. It already wants the > TimeTrack, and in the future it may want NoteTracks. So prefer > TrackList for parameters to functions, using > {Wave,Note,Label}TrackArray > temporarily in localized algorithms. > > --------- > > A shortcoming of our current approach that has been clear for a while > is > the way we deal with stereo tracks. Making all code that deals with > lists of tracks be aware of the "linked" flag is not great abstraction > and it makes for some ugly code. We've discussed having a StereoTrack > that simply contains two WaveTracks and calls methods on both of them. > However I am beginning to think this is the wrong approach. First of > all, it introduces more complexity into what will already be a plenty > complex inheritance graph. Also, it just doesn't make sense based on > the way we look at tracks: > > a track: > * has one label area and set of controls to control it > * is the smallest selectable entity > * is the unit of exchange between core functions of the > infrastructure > > Based on these characteristics, it doesn't make any sense to have one > track "contain" another. For example, the two GuiWaveTracks contained > by a GuiStereoTrack are both going to want to draw the label and > receive > label mouse clicks, because that's what GuiWaveTracks do. What I think > makes sense is to have only one kind of WaveTrack, that can contain > one, > two (stereo) or more complex arrangements (5.1) of channels. Each > channel is then a sequence. > > While we're at it, we could get even more ambitious and make Audacity > region-capable. Then the model would be: > > WaveTrack HAS MANY > Channel(s) HAVE MANY > Region(s) at arbitrary (but nonoverlapping) offsets > > This would make each region a Sequence. How fortunate that Sequence > has > already been separated from WaveTrack! :) I like that idea, it would keep WaveTrack simpler. I also think there's no question that we should move towards support for regions. For the short term, I'd suggest that we have one region per channel, and get all of that logic working (but go ahead and create data structures for multiple regions per channel, just don't worry about the UI or the logic at this time). > To consider for a second the effect this would have on other parts of > the program: > > AudioIO would get a list of WaveTracks to play, and would break them > apart into their channels to play them. It already has to do about the > same amount of work, because it has to iterate over the list and make > decisions based on whether each track is a LeftChannel, RightChannel or > MonoChannel and whether or not it is linked. Agreed. Perhaps that should be a method of TrackList (or TrackArray), to return a WaveChannelArray of all of the WaveChannels. > Exporters would also get a list of WaveTracks to export, and would > break > them down to decide what kind of file to write (some output formats may > actually support things like 5.1) and proceed accordingly. Sounds good - keep in mind that most of the logic for this is in Mix.cpp - both Audio I/O and all exporters make heavy use of this class to figure out what to do with a collection of WaveTracks. So just make Mix smart enough to handle this and you're basically done. > Effects are the part I'm the least sure about because I'm the least > familiar with that code. About half of the effects, plus all of the plug-in effects, are pretty straightforward in the way they access tracks - they just read in chunks to be processed and write back the same size chunks. But the other effects do thinks like copy Sequence Blocks around (Repeat), output a different amount of audio than they input (Change Pitch/Tempo), access special methods (Amplify), etc. and they would need to be rewritten. - Dominic > Thoughts? > > Josh > > > ------------------------------------------------------- > This SF.net email is sponsored by: The SF.net Donation Program. > Do you like what SourceForge.net is doing for the Open > Source Community? Make a contribution, and help us add new > features and functionality. Click here: http://sourceforge.net/donate/ > _______________________________________________ > Audacity-devel mailing list > Aud...@li... > https://lists.sourceforge.net/lists/listinfo/audacity-devel |
From: Joshua H. <jo...@re...> - 2003-10-28 16:44:04
|
On Tue, 2003-10-28 at 00:28, Dominic Mazzoni wrote: > Looks like this one never made it to the list. Weird. > --- > Hi Josh, > > Looks like you've made some great progress. I'm still behind on > catching up on your Ogg progress; I've been working on 1.2.0 issues > and playing with Mac OS X 10.3 "Panther" and XCode (both of which > totally rock, BTW). Nice. I don't know if I've mentioned this to you, but I've been thinking about perhaps getting a PowerBook sometime this year. > On Oct 25, 2003, at 10:34 PM, Joshua Haberman wrote: > > I've been working a lot today on the beginning stages of what will > > become the long-discussed Track rewrite. I don't have anything ready > > to > > show yet, but I wanted to throw some ideas out that I've been thinking > > about through these initial changes. > > > > My first task has been reworking TrackList. The two main changes are > > that it now uses wxList so we don't have to maintain our own linked > > list > > implementation, and we get the benefit of more methods already being > > written. > > That sounds good. > > Before it's too late, what would you think about making it a > dynamic array instead of a list? Conceptually a list seems okay > but realistically certain operations, like move up/down, are a > pain to implement for lists. I did consider this, but what it came down to was that you can't derive from wxArray because its destructor is not virtual. Since move up/down will be methods of TrackList, at least the client routines won't be exposed to the complexity. > > The more beneficial change is a new type-safe interface to > > getting specific kinds of tracks from the TrackList: > > > > WX_DEFINE_ARRAY(WaveTrack*, WaveTrackArray) > > WX_DEFINE_ARRAY(NoteTrack*, NoteTrackArray) > > WX_DEFINE_ARRAY(LabelTrack*, LabelTrackArray) > > WaveTrackArray GetWaveTracks(bool selectedOnly); > > NoteTrackArray GetNoteTracks(bool selectedOnly); > > LabelTrackArray GetLabelTracks(bool selectedOnly); > > Those are great. The fact that all of these methods return > arrays makes me even more sure that it would be better if TrackList > is really TrackArray. One way to see the difference is that the TrackArrays returned above are "snapshots" of the actual list. The List may own the tracks, but the arrays never do. The Arrays are not meant to be modified, whereas the list gets modified all the time. The arrays have short life-spans and are not passed between procedures, whereas the list is. Thanks for your comments. Josh |
From: Dominic M. <do...@au...> - 2003-10-28 17:40:40
|
Joshua Haberman wrote: > On Tue, 2003-10-28 at 00:28, Dominic Mazzoni wrote: > >>Looks like this one never made it to the list. Weird. >>--- >>Hi Josh, >> >>Looks like you've made some great progress. I'm still behind on >>catching up on your Ogg progress; I've been working on 1.2.0 issues >>and playing with Mac OS X 10.3 "Panther" and XCode (both of which >>totally rock, BTW). > > Nice. I don't know if I've mentioned this to you, but I've been > thinking about perhaps getting a PowerBook sometime this year. Awesome! >>On Oct 25, 2003, at 10:34 PM, Joshua Haberman wrote: >> >>>I've been working a lot today on the beginning stages of what will >>>become the long-discussed Track rewrite. I don't have anything ready >>>to >>>show yet, but I wanted to throw some ideas out that I've been thinking >>>about through these initial changes. >>> >>>My first task has been reworking TrackList. The two main changes are >>>that it now uses wxList so we don't have to maintain our own linked >>>list >>>implementation, and we get the benefit of more methods already being >>>written. >> >>That sounds good. >> >>Before it's too late, what would you think about making it a >>dynamic array instead of a list? Conceptually a list seems okay >>but realistically certain operations, like move up/down, are a >>pain to implement for lists. > > > I did consider this, but what it came down to was that you can't derive > from wxArray because its destructor is not virtual. Since move up/down > will be methods of TrackList, at least the client routines won't be > exposed to the complexity. OK, I can see the reasoning for wxList, but do you think it would make sense to support the [] operator? There are times when this would be quite handy. Either way we should support STL-style iterators, rather than the lame ones I added. >>>The more beneficial change is a new type-safe interface to >>>getting specific kinds of tracks from the TrackList: >>> >>>WX_DEFINE_ARRAY(WaveTrack*, WaveTrackArray) >>>WX_DEFINE_ARRAY(NoteTrack*, NoteTrackArray) >>>WX_DEFINE_ARRAY(LabelTrack*, LabelTrackArray) >>>WaveTrackArray GetWaveTracks(bool selectedOnly); >>>NoteTrackArray GetNoteTracks(bool selectedOnly); >>>LabelTrackArray GetLabelTracks(bool selectedOnly); >> >>Those are great. The fact that all of these methods return >>arrays makes me even more sure that it would be better if TrackList >>is really TrackArray. > > One way to see the difference is that the TrackArrays returned above are > "snapshots" of the actual list. The List may own the tracks, but the > arrays never do. The Arrays are not meant to be modified, whereas the > list gets modified all the time. The arrays have short life-spans and > are not passed between procedures, whereas the list is. OK, that makes more sense. What would you think about implementing the very early versions of the TrackList and new Track hierarchy in a little sandbox, maybe a very simple wxWindows main program that just creates some different tracks that draw themselves with a simple rectangle or something? I feel like it might be nice to play with the interface and make all of the changes we want to there first, so that we don't rip up all of the Audacity code that works with tracks before we're totally happy with the details of the rewrite. - Dominic > Thanks for your comments. > > Josh > > > ------------------------------------------------------- > This SF.net email is sponsored by: SF.net Giveback Program. > Does SourceForge.net help you be more productive? Does it > help you create better code? SHARE THE LOVE, and help us help > YOU! Click Here: http://sourceforge.net/donate/ > _______________________________________________ > Audacity-devel mailing list > Aud...@li... > https://lists.sourceforge.net/lists/listinfo/audacity-devel |
From: Markus M. <me...@me...> - 2003-10-28 18:34:02
|
Am Die, den 28.10.2003 schrieb Dominic Mazzoni um 19:44: > OK, I can see the reasoning for wxList, but do you think it would make > sense to support the [] operator? There are times when this would be > quite handy. Either way we should support STL-style iterators, rather > than the lame ones I added. Is there any reason for not using std::vector or similar here? As long as there ain't any really extraordinary features used, the supported compilers/platforms (gcc, msvc) should work with this. As much as I like the consistency provided by being wxWindows-only, wxArray et al IMHO are one of the weaker parts of the wxWindows framework. The reason they exist seems to be mostly to provide a MFC-lookalike, and because back in the days stdlib wasn't too well supported by some compilers. Just random rambling... Markus |
From: Dominic M. <do...@mi...> - 2003-10-28 20:39:50
|
Markus Meyer wrote: > Am Die, den 28.10.2003 schrieb Dominic Mazzoni um 19:44: > >>OK, I can see the reasoning for wxList, but do you think it would make >>sense to support the [] operator? There are times when this would be >>quite handy. Either way we should support STL-style iterators, rather >>than the lame ones I added. > > Is there any reason for not using std::vector or similar here? As long > as there ain't any really extraordinary features used, the supported > compilers/platforms (gcc, msvc) should work with this. As much as I like > the consistency provided by being wxWindows-only, wxArray et al IMHO are > one of the weaker parts of the wxWindows framework. The reason they > exist seems to be mostly to provide a MFC-lookalike, and because back in > the days stdlib wasn't too well supported by some compilers. It'd be worth considering. Of course, we'd have to subclass std::vector, since the whole point of a TrackList is to provide lots of track-specific functionality that isn't provided by any generic class. I agree that wxList and wxArray don't have a lot of fancy features, but then again, what exactly does std::vector provide that we need? For algorithm development, there are a lot of STL features that could come in handy, but for a GUI application, maybe not as much. One thing that's always bugged me about std::vector is the choice of names: for example, push_back is just not intuitive to me. Maybe if I've got a stack, but a stack to me is a special case of a list or dynamic array. It's a weird dilemma, because STL classes are more flexible and clean from a C++ point of view (using templates instead of macros, etc). But from an aesthetic point of view, I don't like STL at all - I much prefer wxWindows-style method names and overall conventions. Part of it's just what you're used to, but I feel that wxWindows has put a lot of thought into clear method and variable names. Another that comes to mind is that wxWindows has switched from names like GetNumElements() to GetElementCount(), since "Num" is confusing to non-native English speakers. Contrast this with std::vector's method size(), which is quite ambiguous (is it the amount of size it takes on disk? the number of elements? the maximum number of elements?) - Dominic > Just random rambling... > > > Markus > > > > > ------------------------------------------------------- > This SF.net email is sponsored by: SF.net Giveback Program. > Does SourceForge.net help you be more productive? Does it > help you create better code? SHARE THE LOVE, and help us help > YOU! Click Here: http://sourceforge.net/donate/ > _______________________________________________ > Audacity-devel mailing list > Aud...@li... > https://lists.sourceforge.net/lists/listinfo/audacity-devel |
From: Joshua H. <jo...@re...> - 2003-10-29 08:02:43
|
On Tue, 2003-10-28 at 12:37, Dominic Mazzoni wrote: > It's a weird dilemma, because STL classes are more flexible and > clean from a C++ point of view (using templates instead of macros, > etc). But from an aesthetic point of view, I don't like STL at > all - I much prefer wxWindows-style method names and overall > conventions. Part of it's just what you're used to, but I feel > that wxWindows has put a lot of thought into clear method and > variable names. Another that comes to mind is that wxWindows > has switched from names like GetNumElements() to GetElementCount(), > since "Num" is confusing to non-native English speakers. Contrast > this with std::vector's method size(), which is quite ambiguous > (is it the amount of size it takes on disk? the number of elements? > the maximum number of elements?) I fully agree about STL, and I would add that in addition to being somewhat nonintuitive, there doesn't seem to be any really good documentation for it anywhere! Josh |
From: Dominic M. <do...@au...> - 2003-10-29 09:34:07
|
Joshua Haberman wrote: > On Tue, 2003-10-28 at 12:37, Dominic Mazzoni wrote: > >>It's a weird dilemma, because STL classes are more flexible and >>clean from a C++ point of view (using templates instead of macros, >>etc). But from an aesthetic point of view, I don't like STL at >>all - I much prefer wxWindows-style method names and overall >>conventions. Part of it's just what you're used to, but I feel >>that wxWindows has put a lot of thought into clear method and >>variable names. Another that comes to mind is that wxWindows >>has switched from names like GetNumElements() to GetElementCount(), >>since "Num" is confusing to non-native English speakers. Contrast >>this with std::vector's method size(), which is quite ambiguous >>(is it the amount of size it takes on disk? the number of elements? >>the maximum number of elements?) > > I fully agree about STL, and I would add that in addition to being > somewhat nonintuitive, there doesn't seem to be any really good > documentation for it anywhere! Anywhere online. There's a plethora of books written about it. - Dominic > Josh > > > ------------------------------------------------------- > This SF.net email is sponsored by: SF.net Giveback Program. > Does SourceForge.net help you be more productive? Does it > help you create better code? SHARE THE LOVE, and help us help > YOU! Click Here: http://sourceforge.net/donate/ > _______________________________________________ > Audacity-devel mailing list > Aud...@li... > https://lists.sourceforge.net/lists/listinfo/audacity-devel |
From: Jonas B. <jo...@bi...> - 2003-10-29 22:19:55
|
On Wed, Oct 29, 2003 at 01:32:47AM -0800, Dominic Mazzoni wrote: > Joshua Haberman wrote: > >On Tue, 2003-10-28 at 12:37, Dominic Mazzoni wrote: > > > >>It's a weird dilemma, because STL classes are more flexible and > >>clean from a C++ point of view (using templates instead of macros, > >>etc). But from an aesthetic point of view, I don't like STL at > >>all - I much prefer wxWindows-style method names and overall > >>conventions. Part of it's just what you're used to, but I feel > >>that wxWindows has put a lot of thought into clear method and > >>variable names. Another that comes to mind is that wxWindows > >>has switched from names like GetNumElements() to GetElementCount(), > >>since "Num" is confusing to non-native English speakers. Contrast > >>this with std::vector's method size(), which is quite ambiguous > >>(is it the amount of size it takes on disk? the number of elements? > >>the maximum number of elements?) > > > >I fully agree about STL, and I would add that in addition to being > >somewhat nonintuitive, there doesn't seem to be any really good > >documentation for it anywhere! >=20 > Anywhere online. There's a plethora of books written about it. > To be part of the debate, I am using the documentation at: http://www.sgi.com/tech/stl/ which is IMHO a good reference documentation. And it is available online... just a tips (maybe this is no news for you and then I apologize). Whether it is really good or not is for the reader to decide... /Jonas - who hates that the spam filter captures these mails because of the SF-banner... --=20 Jonas Birm=E9 (jo...@bi...) Jabber: bi...@ja... http://home.birme.se/~birme/ ICQ: 12030785 | IRC: birme@GIMPNET +-----< Abandon the search for Truth; settle for a good fantasy >-- |
From: <jo...@jo...> - 2003-10-30 07:14:06
|
>I fully agree about STL, and I would add that in addition to being >somewhat nonintuitive, there doesn't seem to be any really good >documentation for it anywhere! > >Josh > > If you are used to c++, SGI's docs are quite good. http://www.sgi.com/tech/stl/ (or if you are a Debian user just aptitude install stl-manual). Also http://www.ge.infn.it/geant4/training/stl.html contains some useful information (part of which is actually obsolette, but still useful). Also on Bjarne Stroustroup web page http://www.research.att.com/~bs/C++.html is a chunk of docs and papers, but actually that's all one can find (if you know what you are trying to find). Joe |
From: Joshua H. <jo...@re...> - 2003-10-29 08:00:04
|
On Tue, 2003-10-28 at 10:44, Dominic Mazzoni wrote: > Joshua Haberman wrote: > > I did consider this, but what it came down to was that you can't derive > > from wxArray because its destructor is not virtual. Since move up/down > > will be methods of TrackList, at least the client routines won't be > > exposed to the complexity. > > OK, I can see the reasoning for wxList, but do you think it would make > sense to support the [] operator? There are times when this would be > quite handy. That's definitely possible, though I can't think of any situations where operator[] is significantly more useful than just iterating. > Either way we should support STL-style iterators, rather > than the lame ones I added. Actually the wxList interface doesn't use iterators at all, it uses a Node structure. The basic iteration algorithm is: for(TrackList::Node *node = someList.GetFirst(); node != NULL; node = node->GetNext()) { Track *t = node->GetData(); // ... } > >>>The more beneficial change is a new type-safe interface to > >>>getting specific kinds of tracks from the TrackList: > >>> > >>>WX_DEFINE_ARRAY(WaveTrack*, WaveTrackArray) > >>>WX_DEFINE_ARRAY(NoteTrack*, NoteTrackArray) > >>>WX_DEFINE_ARRAY(LabelTrack*, LabelTrackArray) > >>>WaveTrackArray GetWaveTracks(bool selectedOnly); > >>>NoteTrackArray GetNoteTracks(bool selectedOnly); > >>>LabelTrackArray GetLabelTracks(bool selectedOnly); > >> > >>Those are great. The fact that all of these methods return > >>arrays makes me even more sure that it would be better if TrackList > >>is really TrackArray. > > > > One way to see the difference is that the TrackArrays returned above are > > "snapshots" of the actual list. The List may own the tracks, but the > > arrays never do. The Arrays are not meant to be modified, whereas the > > list gets modified all the time. The arrays have short life-spans and > > are not passed between procedures, whereas the list is. > > OK, that makes more sense. > > What would you think about implementing the very early versions of the > TrackList and new Track hierarchy in a little sandbox, maybe a very > simple wxWindows main program that just creates some different tracks > that draw themselves with a simple rectangle or something? That's an interesting idea that I will keep in mind. Unfortunately I'm coming to the realization that it's really not prudent for me to be working on this for the rest of the semester. As painful as that is (I'm *really* enjoying it, and it really need to be done), I have school, GREs, grad school applications, and lots of music stuff that's going to keep me really busy. So I'm afraid I'm going to have to back-burner it for while. Josh |
From: Dominic M. <do...@au...> - 2003-10-29 09:37:49
|
Joshua Haberman wrote: >>Either way we should support STL-style iterators, rather >>than the lame ones I added. > > Actually the wxList interface doesn't use iterators at all, it uses a > Node structure. The basic iteration algorithm is: > > for(TrackList::Node *node = someList.GetFirst(); node != NULL; node = node->GetNext()) > { > Track *t = node->GetData(); > // ... > } STL-style would look like this: for(TrackList::iterator i = someList.begin(); i!=someList.end(); i++) { Track *t = *i; } While I don't like STL method names, I've grown to like the idea of an iterator that overrides the ++ increment and * dereference operators. We could probably just support these as aliases of the wxList methods. - Dominic |
From: Dominic M. <do...@mi...> - 2003-10-29 02:40:59
|
Hi Josh, Looks like you've made some great progress. I'm still behind on catching up on your Ogg progress; I've been working on 1.2.0 issues and playing with Mac OS X 10.3 "Panther" and XCode (both of which totally rock, BTW). On Oct 25, 2003, at 10:34 PM, Joshua Haberman wrote: > I've been working a lot today on the beginning stages of what will > become the long-discussed Track rewrite. I don't have anything ready > to > show yet, but I wanted to throw some ideas out that I've been thinking > about through these initial changes. > > My first task has been reworking TrackList. The two main changes are > that it now uses wxList so we don't have to maintain our own linked > list > implementation, and we get the benefit of more methods already being > written. That sounds good. Before it's too late, what would you think about making it a dynamic array instead of a list? Conceptually a list seems okay but realistically certain operations, like move up/down, are a pain to implement for lists. > The more beneficial change is a new type-safe interface to > getting specific kinds of tracks from the TrackList: > > WX_DEFINE_ARRAY(WaveTrack*, WaveTrackArray) > WX_DEFINE_ARRAY(NoteTrack*, NoteTrackArray) > WX_DEFINE_ARRAY(LabelTrack*, LabelTrackArray) > WaveTrackArray GetWaveTracks(bool selectedOnly); > NoteTrackArray GetNoteTracks(bool selectedOnly); > LabelTrackArray GetLabelTracks(bool selectedOnly); Those are great. The fact that all of these methods return arrays makes me even more sure that it would be better if TrackList is really TrackArray. > Not only does this make code simpler since you don't have to iterate > over a list of tracks checking t->GetKind(), but it's safer because you > no longer have to statically downcast from Track* to the more specific > type. This will actually become crucial once we create the new > hierarchy we have planned, because for some reason (that I don't yet > understand) the compiler won't let me statically downcast from a base > to > a virtually derived class. As a refresher, we are planning to > virtually > derive from Track so that GuiTrack and WaveTrack both share the same > copy of Track. > > You may wonder how we can downcast at all if not statically. Well the > answer is to introduce dynamic_cast. We haven't used any RTTI to this > point (AFAIK) but I think we are beginning to need it. I know it's > supported on both VC++ and g++, so there's no reason to avoid it that I > know of. In reality we were using a sort of ad-hoc RTTI already by > having the virtual GetKind() method for GetTrack; now we're just > letting > the compiler do the work for us, and benefiting from the extra safety. > > Back to TrackList for a second, the intention is that TrackList (as > opposed to {Wave,Note,Label}TrackArray) is still the primary structure > for passing around lists of tracks, but that it is easy to select the > more specific tracks at any time. For example, I think passing a > WaveTrackArray to AudioIO is a bad idea, because (for example) the > AudioIO may want different kinds of tracks also. It already wants the > TimeTrack, and in the future it may want NoteTracks. So prefer > TrackList for parameters to functions, using > {Wave,Note,Label}TrackArray > temporarily in localized algorithms. > > --------- > > A shortcoming of our current approach that has been clear for a while > is > the way we deal with stereo tracks. Making all code that deals with > lists of tracks be aware of the "linked" flag is not great abstraction > and it makes for some ugly code. We've discussed having a StereoTrack > that simply contains two WaveTracks and calls methods on both of them. > However I am beginning to think this is the wrong approach. First of > all, it introduces more complexity into what will already be a plenty > complex inheritance graph. Also, it just doesn't make sense based on > the way we look at tracks: > > a track: > * has one label area and set of controls to control it > * is the smallest selectable entity > * is the unit of exchange between core functions of the > infrastructure > > Based on these characteristics, it doesn't make any sense to have one > track "contain" another. For example, the two GuiWaveTracks contained > by a GuiStereoTrack are both going to want to draw the label and > receive > label mouse clicks, because that's what GuiWaveTracks do. What I think > makes sense is to have only one kind of WaveTrack, that can contain > one, > two (stereo) or more complex arrangements (5.1) of channels. Each > channel is then a sequence. > > While we're at it, we could get even more ambitious and make Audacity > region-capable. Then the model would be: > > WaveTrack HAS MANY > Channel(s) HAVE MANY > Region(s) at arbitrary (but nonoverlapping) offsets > > This would make each region a Sequence. How fortunate that Sequence > has > already been separated from WaveTrack! :) I like that idea, it would keep WaveTrack simpler. I also think there's no question that we should move towards support for regions. For the short term, I'd suggest that we have one region per channel, and get all of that logic working (but go ahead and create data structures for multiple regions per channel, just don't worry about the UI or the logic at this time). > To consider for a second the effect this would have on other parts of > the program: > > AudioIO would get a list of WaveTracks to play, and would break them > apart into their channels to play them. It already has to do about the > same amount of work, because it has to iterate over the list and make > decisions based on whether each track is a LeftChannel, RightChannel or > MonoChannel and whether or not it is linked. Agreed. Perhaps that should be a method of TrackList (or TrackArray), to return a WaveChannelArray of all of the WaveChannels. > Exporters would also get a list of WaveTracks to export, and would > break > them down to decide what kind of file to write (some output formats may > actually support things like 5.1) and proceed accordingly. Sounds good - keep in mind that most of the logic for this is in Mix.cpp - both Audio I/O and all exporters make heavy use of this class to figure out what to do with a collection of WaveTracks. So just make Mix smart enough to handle this and you're basically done. > Effects are the part I'm the least sure about because I'm the least > familiar with that code. About half of the effects, plus all of the plug-in effects, are pretty straightforward in the way they access tracks - they just read in chunks to be processed and write back the same size chunks. But the other effects do thinks like copy Sequence Blocks around (Repeat), output a different amount of audio than they input (Change Pitch/Tempo), access special methods (Amplify), etc. and they would need to be rewritten. - Dominic > Thoughts? > > Josh > > > ------------------------------------------------------- > This SF.net email is sponsored by: The SF.net Donation Program. > Do you like what SourceForge.net is doing for the Open > Source Community? Make a contribution, and help us add new > features and functionality. Click here: http://sourceforge.net/donate/ > _______________________________________________ > Audacity-devel mailing list > Aud...@li... > https://lists.sourceforge.net/lists/listinfo/audacity-devel |