* Add SysEx Support to MidiModel / SMF
[ardour.git] / libs / ardour / audio_port.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
3
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.
8
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.
13
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.
17 */
18
19 #include <cassert>
20 #include <ardour/audio_port.h>
21 #include <ardour/audioengine.h>
22 #include <ardour/data_type.h>
23 #include <ardour/audio_buffer.h>
24
25 using namespace ARDOUR;
26 using namespace std;
27
28 AudioPort::AudioPort (const std::string& name, Flags flags, bool ext, nframes_t capacity)
29         : Port (name, DataType::AUDIO, flags, ext)
30         , _has_been_mixed_down (false)
31         , _buffer (0)
32         , _internal_buffer (false)
33 {
34         assert (name.find_first_of (':') == string::npos);
35
36         if (external ()) {
37                 
38                 /* external ports use the external port buffer */
39                 _buffer = new AudioBuffer (0);
40
41         } else {
42
43                 /* internal ports need their own buffers */
44                 _buffer = new AudioBuffer (capacity);
45         }
46
47         check_buffer_status ();
48         
49 }
50
51 AudioPort::~AudioPort()
52 {
53         delete _buffer;
54 }
55
56 void
57 AudioPort::cycle_start (nframes_t nframes, nframes_t offset)
58 {
59         /* caller must hold process lock */
60
61         /* For external (JACK) ports, get_buffer() must only be run 
62            on outputs here in cycle_start().
63
64            Inputs must be done in the correct processing order, which 
65            requires interleaving with route processing. that will 
66            happen when Port::get_buffer() is called.
67         */
68         
69         if (!receives_input() && external ()) {
70                 _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes) + offset, nframes);
71         }
72
73         if (receives_input()) {
74                 _has_been_mixed_down = false;
75         } else {
76                 _buffer->silence (nframes, offset);
77         }
78 }
79
80 AudioBuffer &
81 AudioPort::get_audio_buffer (nframes_t nframes, nframes_t offset)
82 {
83         /* caller must hold process lock */
84
85         if (receives_input () && !_has_been_mixed_down) {
86
87                 /* external ports use JACK's memory unless otherwise noted */
88                 
89                 if (external()) {
90                         if (!using_internal_data()) {
91                                 _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes) + offset, nframes);
92                         } else {
93                                 _buffer->silence (nframes, offset);
94                         }
95                 }
96
97                 mixdown (nframes, offset, !external ());
98         } 
99         
100         return *_buffer;
101 }
102
103 void
104 AudioPort::cycle_end (nframes_t nframes, nframes_t offset)
105 {
106         _has_been_mixed_down = false;
107 }
108
109 void
110 AudioPort::mixdown (nframes_t cnt, nframes_t offset, bool first_overwrite)
111 {
112         /* note: this is only called for input ports */
113
114         if (_connections.empty()) {
115
116                 /* no internal mixing to do, so for internal ports
117                    just make sure the buffer is silent.
118                 */
119                 
120                 if (!external()) {
121                         _buffer->silence (cnt, offset);
122                 } 
123
124         } else {
125
126                 set<Port*>::const_iterator p = _connections.begin();
127
128                 /* mix in internally-connected ports. if this is an external port
129                    then it may already have data present from JACK. in that case, we 
130                    do not want to overwrite that data, so we skip the initial ::read_from()
131                    call and do everything with accumulate_from()
132                  */
133
134                 if (!external()) {
135                         _buffer->read_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset);
136                         ++p;
137                         
138                 }
139
140                 for (; p != _connections.end (); ++p) {
141                         _buffer->accumulate_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset);
142
143                 }
144         }
145
146         /* XXX horrible heuristic designed to check that we worked the whole buffer.
147            Needs fixing but its a hard problem.
148         */
149
150         if (cnt && offset == 0) {
151                 _has_been_mixed_down = true;
152         }
153 }
154
155 void
156 AudioPort::reset ()
157 {
158         Port::reset ();
159         
160         if (_buffer->capacity () != 0) {
161                 _buffer->resize (_engine->frames_per_cycle ());
162                 _buffer->clear ();
163         }
164 }
165
166 bool
167 AudioPort::using_internal_data () const
168 {
169         return _internal_buffer;
170 }
171
172 void
173 AudioPort::use_internal_data ()
174 {
175         _buffer->replace_data (_buffer->capacity());
176         _internal_buffer = true;
177 }
178
179 void
180 AudioPort::use_external_data ()
181 {
182         _internal_buffer = false;
183         _buffer->drop_data ();
184 }