2 Copyright (C) 2000-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #define __STDC_FORMAT_MACROS
23 #include "pbd/error.h"
24 #include "pbd/boost_debug.h"
26 #include "ardour/session.h"
28 #include "ardour/region_factory.h"
29 #include "ardour/region.h"
30 #include "ardour/audioregion.h"
31 #include "ardour/audiosource.h"
32 #include "ardour/midi_source.h"
33 #include "ardour/midi_region.h"
34 #include "ardour/utils.h"
38 using namespace ARDOUR
;
41 PBD::Signal1
<void,boost::shared_ptr
<Region
> > RegionFactory::CheckNewRegion
;
42 Glib::StaticMutex
RegionFactory::region_map_lock
;
43 RegionFactory::RegionMap
RegionFactory::region_map
;
44 PBD::ScopedConnectionList
RegionFactory::region_list_connections
;
45 Glib::StaticMutex
RegionFactory::region_name_map_lock
;
46 std::map
<std::string
, uint32_t> RegionFactory::region_name_map
;
48 boost::shared_ptr
<Region
>
49 RegionFactory::create (boost::shared_ptr
<const Region
> region
)
51 boost::shared_ptr
<Region
> ret
;
52 boost::shared_ptr
<const AudioRegion
> ar
;
53 boost::shared_ptr
<const MidiRegion
> mr
;
55 if ((ar
= boost::dynamic_pointer_cast
<const AudioRegion
>(region
)) != 0) {
57 AudioRegion
* arn
= new AudioRegion (ar
, 0, true);
58 boost_debug_shared_ptr_mark_interesting (arn
, "Region");
60 boost::shared_ptr
<AudioRegion
> arp (arn
);
61 ret
= boost::static_pointer_cast
<Region
> (arp
);
63 } else if ((mr
= boost::dynamic_pointer_cast
<const MidiRegion
>(region
)) != 0) {
65 MidiRegion
* mrn
= new MidiRegion (mr
, 0, true);
66 boost::shared_ptr
<MidiRegion
> mrp (mrn
);
67 ret
= boost::static_pointer_cast
<Region
> (mrp
);
70 fatal
<< _("programming error: RegionFactory::create() called with unknown Region type")
78 /* pure copy constructor - no property list */
79 /* pure copy constructor - no CheckNewRegion emitted */
85 boost::shared_ptr
<Region
>
86 RegionFactory::create (boost::shared_ptr
<Region
> region
, frameoffset_t offset
, const PropertyList
& plist
, bool announce
)
88 return create (region
, offset
, true, plist
, announce
);
91 boost::shared_ptr
<Region
>
92 RegionFactory::create (boost::shared_ptr
<Region
> region
, const PropertyList
& plist
, bool announce
)
94 return create (region
, 0, false, plist
, announce
);
97 boost::shared_ptr
<Region
>
98 RegionFactory::create (boost::shared_ptr
<Region
> region
, frameoffset_t offset
, bool offset_relative
, const PropertyList
& plist
, bool announce
)
100 boost::shared_ptr
<Region
> ret
;
101 boost::shared_ptr
<const AudioRegion
> other_a
;
102 boost::shared_ptr
<const MidiRegion
> other_m
;
104 if ((other_a
= boost::dynamic_pointer_cast
<AudioRegion
>(region
)) != 0) {
106 AudioRegion
* ar
= new AudioRegion (other_a
, offset
, offset_relative
);
107 boost_debug_shared_ptr_mark_interesting (ar
, "Region");
109 boost::shared_ptr
<AudioRegion
> arp (ar
);
110 ret
= boost::static_pointer_cast
<Region
> (arp
);
112 } else if ((other_m
= boost::dynamic_pointer_cast
<MidiRegion
>(region
)) != 0) {
114 MidiRegion
* mr
= new MidiRegion (other_m
, offset
, offset_relative
);
115 boost::shared_ptr
<MidiRegion
> mrp (mr
);
116 ret
= boost::static_pointer_cast
<Region
> (mrp
);
119 fatal
<< _("programming error: RegionFactory::create() called with unknown Region type")
122 return boost::shared_ptr
<Region
>();
126 ret
->set_properties (plist
);
130 CheckNewRegion (ret
);
137 boost::shared_ptr
<Region
>
138 RegionFactory::create (boost::shared_ptr
<Region
> region
, const SourceList
& srcs
, const PropertyList
& plist
, bool announce
)
140 boost::shared_ptr
<Region
> ret
;
141 boost::shared_ptr
<const AudioRegion
> other
;
143 /* used by AudioFilter when constructing a new region that is intended to have nearly
144 identical settings to an original, but using different sources.
147 if ((other
= boost::dynamic_pointer_cast
<AudioRegion
>(region
)) != 0) {
149 // XXX use me in caller where plist is setup, this is start i think srcs.front()->length (srcs.front()->timeline_position())
151 AudioRegion
* ar
= new AudioRegion (other
, srcs
);
152 boost_debug_shared_ptr_mark_interesting (ar
, "Region");
154 boost::shared_ptr
<AudioRegion
> arp (ar
);
155 ret
= boost::static_pointer_cast
<Region
> (arp
);
158 fatal
<< _("programming error: RegionFactory::create() called with unknown Region type")
165 ret
->set_properties (plist
);
169 CheckNewRegion (ret
);
177 boost::shared_ptr
<Region
>
178 RegionFactory::create (boost::shared_ptr
<Source
> src
, const PropertyList
& plist
, bool announce
)
181 srcs
.push_back (src
);
182 return create (srcs
, plist
, announce
);
185 boost::shared_ptr
<Region
>
186 RegionFactory::create (const SourceList
& srcs
, const PropertyList
& plist
, bool announce
)
188 boost::shared_ptr
<Region
> ret
;
189 boost::shared_ptr
<AudioSource
> as
;
190 boost::shared_ptr
<MidiSource
> ms
;
192 if ((as
= boost::dynamic_pointer_cast
<AudioSource
>(srcs
[0])) != 0) {
194 AudioRegion
* ar
= new AudioRegion (srcs
);
195 boost_debug_shared_ptr_mark_interesting (ar
, "Region");
197 boost::shared_ptr
<AudioRegion
> arp (ar
);
198 ret
= boost::static_pointer_cast
<Region
> (arp
);
200 } else if ((ms
= boost::dynamic_pointer_cast
<MidiSource
>(srcs
[0])) != 0) {
201 MidiRegion
* mr
= new MidiRegion (srcs
);
202 boost_debug_shared_ptr_mark_interesting (mr
, "Region");
204 boost::shared_ptr
<MidiRegion
> mrp (mr
);
205 ret
= boost::static_pointer_cast
<Region
> (mrp
);
210 ret
->set_properties (plist
);
214 CheckNewRegion (ret
);
221 boost::shared_ptr
<Region
>
222 RegionFactory::create (Session
& session
, XMLNode
& node
, bool yn
)
224 return session
.XMLRegionFactory (node
, yn
);
227 boost::shared_ptr
<Region
>
228 RegionFactory::create (SourceList
& srcs
, const XMLNode
& node
)
230 boost::shared_ptr
<Region
> ret
;
236 if (srcs
[0]->type() == DataType::AUDIO
) {
238 AudioRegion
* ar
= new AudioRegion (srcs
);
239 boost_debug_shared_ptr_mark_interesting (ar
, "Region");
241 boost::shared_ptr
<AudioRegion
> arp (ar
);
242 ret
= boost::static_pointer_cast
<Region
> (arp
);
244 } else if (srcs
[0]->type() == DataType::MIDI
) {
246 MidiRegion
* mr
= new MidiRegion (srcs
);
248 boost::shared_ptr
<MidiRegion
> mrp (mr
);
249 ret
= boost::static_pointer_cast
<Region
> (mrp
);
254 if (ret
->set_state (node
, Stateful::loading_state_version
)) {
258 CheckNewRegion (ret
);
266 RegionFactory::map_add (boost::shared_ptr
<Region
> r
)
268 pair
<ID
,boost::shared_ptr
<Region
> > p
;
273 Glib::Mutex::Lock
lm (region_map_lock
);
274 region_map
.insert (p
);
277 r
->DropReferences
.connect_same_thread (region_list_connections
, boost::bind (&RegionFactory::map_remove
, r
));
279 r
->PropertyChanged
.connect_same_thread (
280 region_list_connections
,
281 boost::bind (&RegionFactory::region_changed
, _1
, boost::weak_ptr
<Region
> (r
))
284 update_region_name_map (r
);
288 RegionFactory::map_remove (boost::shared_ptr
<Region
> r
)
290 Glib::Mutex::Lock
lm (region_map_lock
);
291 RegionMap::iterator i
= region_map
.find (r
->id());
293 if (i
!= region_map
.end()) {
294 region_map
.erase (i
);
300 RegionFactory::map_remove_with_equivalents (boost::shared_ptr
<Region
> r
)
302 Glib::Mutex::Lock
lm (region_map_lock
);
304 for (RegionMap::iterator i
= region_map
.begin(); i
!= region_map
.end(); ) {
305 RegionMap::iterator tmp
= i
;
308 if (r
->region_list_equivalent (i
->second
)) {
309 region_map
.erase (i
);
310 } else if (r
== i
->second
) {
311 region_map
.erase (i
);
320 boost::shared_ptr
<Region
>
321 RegionFactory::region_by_id (const PBD::ID
& id
)
323 RegionMap::iterator i
= region_map
.find (id
);
325 if (i
== region_map
.end()) {
326 cerr
<< "ID " << id
<< " not found in region map\n";
327 return boost::shared_ptr
<Region
>();
334 RegionFactory::clear_map ()
336 region_list_connections
.drop_connections ();
339 Glib::Mutex::Lock
lm (region_map_lock
);
346 RegionFactory::delete_all_regions ()
350 /* copy region list */
352 Glib::Mutex::Lock
lm (region_map_lock
);
356 /* clear existing map */
359 /* tell everyone to drop references */
360 for (RegionMap::iterator i
= copy
.begin(); i
!= copy
.end(); ++i
) {
361 i
->second
->drop_references ();
364 /* the copy should now hold the only references, which will
365 vanish as we leave this scope, thus calling all destructors.
370 RegionFactory::nregions ()
372 Glib::Mutex::Lock
lm (region_map_lock
);
373 return region_map
.size ();
377 RegionFactory::update_region_name_map (boost::shared_ptr
<Region
> region
)
379 string::size_type
const last_period
= region
->name().find_last_of ('.');
381 if (last_period
!= string::npos
&& last_period
< region
->name().length() - 1) {
383 string
const base
= region
->name().substr (0, last_period
);
384 string
const number
= region
->name().substr (last_period
+ 1);
386 /* note that if there is no number, we get zero from atoi,
390 Glib::Mutex::Lock
lm (region_name_map_lock
);
391 region_name_map
[base
] = atoi (number
.c_str ());
396 RegionFactory::region_changed (PropertyChange
const & what_changed
, boost::weak_ptr
<Region
> w
)
398 boost::shared_ptr
<Region
> r
= w
.lock ();
403 if (what_changed
.contains (Properties::name
)) {
404 update_region_name_map (r
);
409 RegionFactory::region_name (string
& result
, string base
, bool newlevel
)
414 if (base
.find("/") != string::npos
) {
415 base
= base
.substr(base
.find_last_of("/") + 1);
420 snprintf (buf
, sizeof (buf
), "%d", RegionFactory::nregions() + 1);
429 string::size_type pos
;
431 pos
= base
.find_last_of ('.');
433 /* pos may be npos, but then we just use entire base */
435 subbase
= base
.substr (0, pos
);
440 Glib::Mutex::Lock
lm (region_name_map_lock
);
442 map
<string
,uint32_t>::iterator x
;
446 if ((x
= region_name_map
.find (subbase
)) == region_name_map
.end()) {
448 region_name_map
[subbase
] = 1;
451 snprintf (buf
, sizeof (buf
), ".%d", x
->second
);
462 RegionFactory::new_region_name (string old
)
464 string::size_type last_period
;
466 string::size_type len
= old
.length() + 64;
469 if ((last_period
= old
.find_last_of ('.')) == string::npos
) {
471 /* no period present - add one explicitly */
474 last_period
= old
.length() - 1;
479 number
= atoi (old
.substr (last_period
+1).c_str());
483 while (number
< (UINT_MAX
-1)) {
485 const RegionMap
& regions (RegionFactory::regions());
486 RegionMap::const_iterator i
;
491 snprintf (buf
, len
, "%s%" PRIu32
, old
.substr (0, last_period
+ 1).c_str(), number
);
494 for (i
= regions
.begin(); i
!= regions
.end(); ++i
) {
495 if (i
->second
->name() == sbuf
) {
500 if (i
== regions
.end()) {
505 if (number
!= (UINT_MAX
-1)) {
509 error
<< string_compose (_("cannot create new name for region \"%1\""), old
) << endmsg
;
514 RegionFactory::get_regions_using_source (boost::shared_ptr
<Source
> s
, std::set
<boost::shared_ptr
<Region
> >& r
)
516 Glib::Mutex::Lock
lm (region_map_lock
);
518 for (RegionMap::iterator i
= region_map
.begin(); i
!= region_map
.end(); ++i
) {
519 if (i
->second
->uses_source (s
)) {
520 r
.insert (i
->second
);