2 Copyright (C) 2002 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 #include <sigc++/retype.h>
21 #include <sigc++/retype_return.h>
22 #include <sigc++/bind.h>
24 #include <pbd/error.h>
25 #include <pbd/enumwriter.h>
27 #include <ardour/audio_track.h>
28 #include <ardour/audio_diskstream.h>
29 #include <ardour/session.h>
30 #include <ardour/io_processor.h>
31 #include <ardour/audioregion.h>
32 #include <ardour/audiosource.h>
33 #include <ardour/region_factory.h>
34 #include <ardour/route_group_specialized.h>
35 #include <ardour/processor.h>
36 #include <ardour/plugin_insert.h>
37 #include <ardour/audioplaylist.h>
38 #include <ardour/playlist_factory.h>
39 #include <ardour/panner.h>
40 #include <ardour/utils.h>
41 #include <ardour/buffer_set.h>
42 #include <ardour/audio_buffer.h>
46 using namespace ARDOUR;
49 AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode mode)
50 : Track (sess, name, flag, mode)
52 AudioDiskstream::Flag dflags = AudioDiskstream::Flag (0);
54 if (_flags & Hidden) {
55 dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Hidden);
57 dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Recordable);
60 if (mode == Destructive) {
61 dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Destructive);
64 boost::shared_ptr<AudioDiskstream> ds (new AudioDiskstream (_session, name, dflags));
66 _session.add_diskstream (ds);
68 set_diskstream (boost::dynamic_pointer_cast<AudioDiskstream> (ds), this);
71 AudioTrack::AudioTrack (Session& sess, const XMLNode& node)
74 _set_state (node, false);
77 AudioTrack::~AudioTrack ()
82 AudioTrack::set_mode (TrackMode m)
86 if (_diskstream->set_destructive (m == Destructive)) {
92 TrackModeChanged (); /* EMIT SIGNAL */
99 AudioTrack::can_use_mode (TrackMode m, bool& bounce_required)
103 bounce_required = false;
108 return _diskstream->can_become_destructive (bounce_required);
113 AudioTrack::deprecated_use_diskstream_connections ()
115 boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
117 if (diskstream->deprecated_io_node == 0) {
121 const XMLProperty* prop;
122 XMLNode& node (*diskstream->deprecated_io_node);
124 /* don't do this more than once. */
126 diskstream->deprecated_io_node = 0;
128 set_input_minimum (ChanCount::ZERO);
129 set_input_maximum (ChanCount::INFINITE);
130 set_output_minimum (ChanCount::ZERO);
131 set_output_maximum (ChanCount::INFINITE);
133 if ((prop = node.property ("gain")) != 0) {
134 set_gain (atof (prop->value().c_str()), this);
135 _gain = _desired_gain;
138 if ((prop = node.property ("input-connection")) != 0) {
139 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
142 error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
144 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
145 error << _("No input bundles available as a replacement")
149 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
154 connect_input_ports_to_bundle (c, this);
156 } else if ((prop = node.property ("inputs")) != 0) {
157 if (set_inputs (prop->value())) {
158 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
167 AudioTrack::set_diskstream (boost::shared_ptr<AudioDiskstream> ds, void *src)
170 _diskstream->set_io (*this);
171 _diskstream->set_destructive (_mode == Destructive);
173 if (audio_diskstream()->deprecated_io_node) {
175 if (!connecting_legal) {
176 ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections));
178 deprecated_use_diskstream_connections ();
182 _diskstream->set_record_enabled (false);
183 _diskstream->monitor_input (false);
185 ic_connection.disconnect();
186 ic_connection = input_changed.connect (mem_fun (*_diskstream, &Diskstream::handle_input_change));
188 DiskstreamChanged (); /* EMIT SIGNAL */
194 AudioTrack::use_diskstream (string name)
196 boost::shared_ptr<AudioDiskstream> dstream;
198 if ((dstream = boost::dynamic_pointer_cast<AudioDiskstream>(_session.diskstream_by_name (name))) == 0) {
199 error << string_compose(_("AudioTrack: audio diskstream \"%1\" not known by session"), name) << endmsg;
203 return set_diskstream (dstream, this);
207 AudioTrack::use_diskstream (const PBD::ID& id)
209 boost::shared_ptr<AudioDiskstream> dstream;
211 if ((dstream = boost::dynamic_pointer_cast<AudioDiskstream> (_session.diskstream_by_id (id))) == 0) {
212 error << string_compose(_("AudioTrack: audio diskstream \"%1\" not known by session"), id) << endmsg;
216 return set_diskstream (dstream, this);
219 boost::shared_ptr<AudioDiskstream>
220 AudioTrack::audio_diskstream() const
222 return boost::dynamic_pointer_cast<AudioDiskstream>(_diskstream);
226 AudioTrack::set_state (const XMLNode& node)
228 return _set_state (node, true);
232 AudioTrack::_set_state (const XMLNode& node, bool call_base)
234 const XMLProperty *prop;
235 XMLNodeConstIterator iter;
238 if (Route::_set_state (node, call_base)) {
243 if ((prop = node.property (X_("mode"))) != 0) {
244 _mode = TrackMode (string_2_enum (prop->value(), _mode));
249 if ((prop = node.property ("diskstream-id")) == 0) {
251 /* some old sessions use the diskstream name rather than the ID */
253 if ((prop = node.property ("diskstream")) == 0) {
254 fatal << _("programming error: AudioTrack given state without diskstream!") << endmsg;
259 if (use_diskstream (prop->value())) {
265 PBD::ID id (prop->value());
267 if (use_diskstream (id)) {
274 XMLNodeConstIterator niter;
277 nlist = node.children();
278 for (niter = nlist.begin(); niter != nlist.end(); ++niter){
281 if (child->name() == X_("recenable")) {
282 _rec_enable_control->set_state (*child);
283 _session.add_controllable (_rec_enable_control);
287 pending_state = const_cast<XMLNode*> (&node);
289 _session.StateReady.connect (mem_fun (*this, &AudioTrack::set_state_part_two));
295 AudioTrack::state(bool full_state)
297 XMLNode& root (Route::state(full_state));
298 XMLNode* freeze_node;
301 if (_freeze_record.playlist) {
304 freeze_node = new XMLNode (X_("freeze-info"));
305 freeze_node->add_property ("playlist", _freeze_record.playlist->name());
306 freeze_node->add_property ("state", enum_2_string (_freeze_record.state));
308 for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
309 inode = new XMLNode (X_("processor"));
310 (*i)->id.print (buf, sizeof (buf));
311 inode->add_property (X_("id"), buf);
312 inode->add_child_copy ((*i)->state);
314 freeze_node->add_child_nocopy (*inode);
317 root.add_child_nocopy (*freeze_node);
320 /* Alignment: act as a proxy for the diskstream */
322 XMLNode* align_node = new XMLNode (X_("Alignment"));
323 AlignStyle as = _diskstream->alignment_style ();
324 align_node->add_property (X_("style"), enum_2_string (as));
325 root.add_child_nocopy (*align_node);
327 root.add_property (X_("mode"), enum_2_string (_mode));
329 /* we don't return diskstream state because we don't
330 own the diskstream exclusively. control of the diskstream
331 state is ceded to the Session, even if we create the
335 _diskstream->id().print (buf, sizeof (buf));
336 root.add_property ("diskstream-id", buf);
338 root.add_child_nocopy (_rec_enable_control->get_state());
344 AudioTrack::set_state_part_two ()
348 LocaleGuard lg (X_("POSIX"));
350 /* This is called after all session state has been restored but before
351 have been made ports and connections are established.
354 if (pending_state == 0) {
358 if ((fnode = find_named_node (*pending_state, X_("freeze-info"))) != 0) {
361 _freeze_record.have_mementos = false;
362 _freeze_record.state = Frozen;
364 for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
367 _freeze_record.processor_info.clear ();
369 if ((prop = fnode->property (X_("playlist"))) != 0) {
370 boost::shared_ptr<Playlist> pl = _session.playlist_by_name (prop->value());
372 _freeze_record.playlist = boost::dynamic_pointer_cast<AudioPlaylist> (pl);
374 _freeze_record.playlist.reset ();
375 _freeze_record.state = NoFreeze;
380 if ((prop = fnode->property (X_("state"))) != 0) {
381 _freeze_record.state = FreezeState (string_2_enum (prop->value(), _freeze_record.state));
384 XMLNodeConstIterator citer;
385 XMLNodeList clist = fnode->children();
387 for (citer = clist.begin(); citer != clist.end(); ++citer) {
388 if ((*citer)->name() != X_("processor")) {
392 if ((prop = (*citer)->property (X_("id"))) == 0) {
396 FreezeRecordProcessorInfo* frii = new FreezeRecordProcessorInfo (*((*citer)->children().front()),
397 boost::shared_ptr<Processor>());
398 frii->id = prop->value ();
399 _freeze_record.processor_info.push_back (frii);
403 /* Alignment: act as a proxy for the diskstream */
405 if ((fnode = find_named_node (*pending_state, X_("Alignment"))) != 0) {
407 if ((prop = fnode->property (X_("style"))) != 0) {
409 /* fix for older sessions from before EnumWriter */
413 if (prop->value() == "capture") {
414 pstr = "CaptureTime";
415 } else if (prop->value() == "existing") {
416 pstr = "ExistingMaterial";
418 pstr = prop->value();
421 AlignStyle as = AlignStyle (string_2_enum (pstr, as));
422 _diskstream->set_persistent_align_style (as);
429 AudioTrack::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset,
430 bool session_state_changing, bool can_record, bool rec_monitors_input)
432 if (n_outputs().n_total() == 0) {
437 silence (nframes, offset);
441 if (session_state_changing) {
443 /* XXX is this safe to do against transport state changes? */
445 passthru_silence (start_frame, end_frame, nframes, offset, 0, false);
449 audio_diskstream()->check_record_status (start_frame, nframes, can_record);
453 if (_have_internal_generator) {
454 /* since the instrument has no input streams,
455 there is no reason to send any signal
461 if (!Config->get_tape_machine_mode()) {
463 ADATs work in a strange way..
464 they monitor input always when stopped.and auto-input is engaged.
466 if ((Config->get_monitoring_model() == SoftwareMonitoring) && (Config->get_auto_input () || _diskstream->record_enabled())) {
467 send_silence = false;
473 Other machines switch to input on stop if the track is record enabled,
474 regardless of the auto input setting (auto input only changes the
475 monitoring state when the transport is rolling)
477 if ((Config->get_monitoring_model() == SoftwareMonitoring) && _diskstream->record_enabled()) {
478 send_silence = false;
485 apply_gain_automation = false;
489 /* if we're sending silence, but we want the meters to show levels for the signal,
493 if (_have_internal_generator) {
494 passthru_silence (start_frame, end_frame, nframes, offset, 0, true);
496 if (_meter_point == MeterInput) {
497 just_meter_input (start_frame, end_frame, nframes, offset);
499 passthru_silence (start_frame, end_frame, nframes, offset, 0, false);
504 /* we're sending signal, but we may still want to meter the input.
507 passthru (start_frame, end_frame, nframes, offset, 0, (_meter_point == MeterInput));
514 AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset, int declick,
515 bool can_record, bool rec_monitors_input)
520 nframes_t transport_frame;
521 boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
524 Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
526 // automation snapshot can also be called from the non-rt context
527 // and it uses the redirect list, so we take the lock out here
528 automation_snapshot (start_frame, false);
533 if (n_outputs().n_total() == 0 && _processors.empty()) {
538 silence (nframes, offset);
542 transport_frame = _session.transport_frame();
544 prepare_inputs( nframes, offset );
546 if ((nframes = check_initial_delay (nframes, offset, transport_frame)) == 0) {
547 /* need to do this so that the diskstream sets its
548 playback distance to zero, thus causing diskstream::commit
551 return diskstream->process (transport_frame, 0, 0, can_record, rec_monitors_input);
555 apply_gain_automation = false;
557 if ((dret = diskstream->process (transport_frame, nframes, offset, can_record, rec_monitors_input)) != 0) {
559 silence (nframes, offset);
564 /* special condition applies */
566 if (_meter_point == MeterInput) {
567 just_meter_input (start_frame, end_frame, nframes, offset);
570 if (diskstream->record_enabled() && !can_record && !Config->get_auto_input()) {
572 /* not actually recording, but we want to hear the input material anyway,
573 at least potentially (depending on monitoring options)
576 passthru (start_frame, end_frame, nframes, offset, 0, true);
578 } else if ((b = diskstream->playback_buffer(0)) != 0) {
581 XXX is it true that the earlier test on n_outputs()
582 means that we can avoid checking it again here? i think
583 so, because changing the i/o configuration of an IO
584 requires holding the AudioEngine lock, which we hold
585 while in the process() tree.
589 /* copy the diskstream data to all output buffers */
591 size_t limit = n_process_buffers().n_audio();
592 BufferSet& bufs = _session.get_scratch_buffers ();
593 const size_t blimit = bufs.count().n_audio();
598 if (limit > blimit) {
600 /* example case: auditioner configured for stereo output,
601 but loaded with an 8 channel file. there are only
602 2 passthrough buffers, but n_process_buffers() will
605 arbitrary decision: map all channels in the diskstream
606 to the outputs available.
609 float scaling = limit/blimit;
611 for (i = 0, n = 1; i < blimit; ++i, ++n) {
613 /* first time through just copy a channel into
617 Sample* bb = bufs.get_audio (i).data();
619 for (nframes_t xx = 0; xx < nframes; ++xx) {
620 bb[xx] = b[xx] * scaling;
623 if (n < diskstream->n_channels().n_audio()) {
624 tmpb = diskstream->playback_buffer(n);
631 for (;i < limit; ++i, ++n) {
633 /* for all remaining channels, sum with existing
634 data in the output buffers
637 bufs.get_audio (i%blimit).accumulate_with_gain_from (b, nframes, 0, scaling);
639 if (n < diskstream->n_channels().n_audio()) {
640 tmpb = diskstream->playback_buffer(n);
651 for (i = 0, n = 1; i < blimit; ++i, ++n) {
652 memcpy (bufs.get_audio (i).data(), b, sizeof (Sample) * nframes);
653 if (n < diskstream->n_channels().n_audio()) {
654 tmpb = diskstream->playback_buffer(n);
662 /* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
664 if (!diskstream->record_enabled() && _session.transport_rolling()) {
665 Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
667 if (am.locked() && gain_control()->automation_playback()) {
668 apply_gain_automation = gain_control()->list()->curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
672 process_output_buffers (bufs, start_frame, end_frame, nframes, offset, (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick, (_meter_point != MeterInput));
675 /* problem with the diskstream; just be quiet for a bit */
676 silence (nframes, offset);
683 AudioTrack::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset,
684 bool can_record, bool rec_monitors_input)
686 if (n_outputs().n_total() == 0 && _processors.empty()) {
691 silence (nframes, offset);
696 apply_gain_automation = false;
698 silence (nframes, offset);
700 return audio_diskstream()->process (_session.transport_frame() + offset, nframes, offset, can_record, rec_monitors_input);
704 AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes)
706 gain_t gain_automation[nframes];
707 gain_t gain_buffer[nframes];
708 float mix_buffer[nframes];
709 ProcessorList::iterator i;
710 bool post_fader_work = false;
711 gain_t this_gain = _gain;
712 boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
714 Glib::RWLock::ReaderLock rlock (_processor_lock);
716 boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist());
719 assert(buffers.get_audio(0).capacity() >= nframes);
721 if (apl->read (buffers.get_audio(0).data(), mix_buffer, gain_buffer, start, nframes) != nframes) {
725 assert(buffers.count().n_audio() >= 1);
727 Sample* b = buffers.get_audio(0).data();
728 BufferSet::audio_iterator bi = buffers.audio_begin();
730 for ( ; bi != buffers.audio_end(); ++bi, ++n) {
731 if (n < diskstream->n_channels().n_audio()) {
732 if (apl->read (bi->data(), mix_buffer, gain_buffer, start, nframes, n) != nframes) {
738 /* duplicate last across remaining buffers */
739 memcpy (bi->data(), b, sizeof (Sample) * nframes);
744 /* note: only run processors during export. other layers in the machinery
745 will already have checked that there are no external port processors.
748 for (i = _processors.begin(); i != _processors.end(); ++i) {
749 boost::shared_ptr<Processor> processor;
751 if ((processor = boost::dynamic_pointer_cast<Processor>(*i)) != 0) {
752 switch (processor->placement()) {
754 processor->run_in_place (buffers, start, start+nframes, nframes, 0);
757 post_fader_work = true;
763 if (gain_control()->automation_state() == Play) {
765 gain_control()->list()->curve().get_vector (start, start + nframes, gain_automation, nframes);
767 for (BufferSet::audio_iterator bi = buffers.audio_begin(); bi != buffers.audio_end(); ++bi) {
768 Sample *b = bi->data();
769 for (nframes_t n = 0; n < nframes; ++n) {
770 b[n] *= gain_automation[n];
776 for (BufferSet::audio_iterator bi = buffers.audio_begin(); bi != buffers.audio_end(); ++bi) {
777 Sample *b = bi->data();
778 for (nframes_t n = 0; n < nframes; ++n) {
784 if (post_fader_work) {
786 for (i = _processors.begin(); i != _processors.end(); ++i) {
787 boost::shared_ptr<PluginInsert> processor;
789 if ((processor = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
790 switch ((*i)->placement()) {
794 processor->run_in_place (buffers, start, start+nframes, nframes, 0);
804 boost::shared_ptr<Region>
805 AudioTrack::bounce (InterThreadInfo& itt)
807 vector<boost::shared_ptr<Source> > srcs;
808 return _session.write_one_track (*this, _session.current_start_frame(), _session.current_end_frame(), false, srcs, itt);
811 boost::shared_ptr<Region>
812 AudioTrack::bounce_range (nframes_t start, nframes_t end, InterThreadInfo& itt)
814 vector<boost::shared_ptr<Source> > srcs;
815 return _session.write_one_track (*this, start, end, false, srcs, itt);
819 AudioTrack::freeze (InterThreadInfo& itt)
821 vector<boost::shared_ptr<Source> > srcs;
822 string new_playlist_name;
823 boost::shared_ptr<Playlist> new_playlist;
826 boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
828 if ((_freeze_record.playlist = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist())) == 0) {
834 while (n < (UINT_MAX-1)) {
838 candidate = string_compose ("<F%2>%1", _freeze_record.playlist->name(), n);
840 if (_session.playlist_by_name (candidate) == 0) {
841 new_playlist_name = candidate;
849 if (n == (UINT_MAX-1)) {
850 error << string_compose (X_("There are too many frozen versions of playlist \"%1\""
851 " to create another one"), _freeze_record.playlist->name())
856 boost::shared_ptr<Region> res;
858 if ((res = _session.write_one_track (*this, _session.current_start_frame(), _session.current_end_frame(), true, srcs, itt)) == 0) {
862 _freeze_record.processor_info.clear ();
863 _freeze_record.have_mementos = true;
866 Glib::RWLock::ReaderLock lm (_processor_lock);
868 for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) {
870 boost::shared_ptr<Processor> processor;
872 if ((processor = boost::dynamic_pointer_cast<Processor>(*r)) != 0) {
874 FreezeRecordProcessorInfo* frii = new FreezeRecordProcessorInfo ((*r)->get_state(), processor);
876 frii->id = processor->id();
878 _freeze_record.processor_info.push_back (frii);
880 /* now deactivate the processor */
882 processor->deactivate ();
883 _session.set_dirty ();
888 new_playlist = PlaylistFactory::create (DataType::AUDIO, _session, new_playlist_name, false);
890 _freeze_record.gain = _gain;
891 _freeze_record.gain_automation_state = _gain_control->automation_state();
892 _freeze_record.pan_automation_state = _panner->automation_state();
894 region_name = new_playlist_name;
896 /* create a new region from all filesources, keep it private */
898 boost::shared_ptr<Region> region (RegionFactory::create (srcs, 0, srcs[0]->length(),
900 (Region::Flag) (Region::WholeFile|Region::DefaultFlags),
903 new_playlist->set_orig_diskstream_id (diskstream->id());
904 new_playlist->add_region (region, _session.current_start_frame());
905 new_playlist->set_frozen (true);
906 region->set_locked (true);
908 diskstream->use_playlist (boost::dynamic_pointer_cast<AudioPlaylist>(new_playlist));
909 diskstream->set_record_enabled (false);
911 /* reset stuff that has already been accounted for in the freeze process */
913 set_gain (1.0, this);
914 _gain_control->set_automation_state (Off);
915 _panner->set_automation_state (Off);
917 _freeze_record.state = Frozen;
918 FreezeChange(); /* EMIT SIGNAL */
922 AudioTrack::unfreeze ()
924 if (_freeze_record.playlist) {
925 audio_diskstream()->use_playlist (_freeze_record.playlist);
927 if (_freeze_record.have_mementos) {
929 for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
935 Glib::RWLock::ReaderLock lm (_processor_lock); // should this be a write lock? jlc
936 for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
937 for (vector<FreezeRecordProcessorInfo*>::iterator ii = _freeze_record.processor_info.begin(); ii != _freeze_record.processor_info.end(); ++ii) {
938 if ((*ii)->id == (*i)->id()) {
939 (*i)->set_state (((*ii)->state));
946 _freeze_record.playlist.reset ();
947 set_gain (_freeze_record.gain, this);
948 _gain_control->set_automation_state (_freeze_record.gain_automation_state);
949 _panner->set_automation_state (_freeze_record.pan_automation_state);
952 _freeze_record.state = UnFrozen;
953 FreezeChange (); /* EMIT SIGNAL */