1 /*
2  * @(#)Destination.h 3.00 21 August 2000
3  *
4  * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org)
5  *
6  * This file is part of TSE3 - the Trax Sequencer Engine version 3.00.
7  *
8  * This library is modifiable/redistributable under the terms of the GNU
9  * General Public License.
10  *
11  * You should have received a copy of the GNU General Public License along
12  * with this program; see the file COPYING. If not, write to the Free Software
13  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
14  *
15  */
16 
17 #include "tse3/ins/Destination.h"
18 
19 #include "tse3/ins/Instrument.h"
20 #include "tse3/Midi.h"
21 
22 #include <vector>
23 #include <algorithm>
24 #include <map>
25 
26 using namespace TSE3::Ins;
27 
28 /******************************************************************************
29  * DestinationImpl class
30  *****************************************************************************/
31 
32 namespace
33 {
34     struct DestinationInfo
35     {
DestinationInfo__anonb921deb50111::DestinationInfo36         DestinationInfo() : allChannels(false)
37         {
38             for (int n = 0; n < 16; ++n) instruments[n] = 0;
39         }
40         bool        allChannels;
41         Instrument *instruments[16];
42     };
43 }
44 
45 class TSE3::Ins::DestinationImpl
46 {
47     public:
48 
49         Instrument                 *defaultInstrument;
50         std::vector<Instrument *>   ilist;
51 
52         typedef std::map<int, DestinationInfo> dmap_type;
53         dmap_type dmap;
54 };
55 
56 
57 /******************************************************************************
58  * Destination class
59  *****************************************************************************/
60 
Destination()61 Destination::Destination()
62 : pimpl(new DestinationImpl)
63 {
64     pimpl->defaultInstrument = 0;
65 }
66 
67 
~Destination()68 Destination::~Destination()
69 {
70     delete pimpl;
71 }
72 
73 
defaultInstrument() const74 Instrument *Destination::defaultInstrument() const
75 {
76     return pimpl->defaultInstrument;
77 }
78 
79 
setDefaultInstrument(Instrument * instrument)80 void Destination::setDefaultInstrument(Instrument *instrument)
81 {
82     pimpl->defaultInstrument = instrument;
83 }
84 
85 
allChannels(int port)86 bool Destination::allChannels(int port)
87 {
88     DestinationImpl::dmap_type::iterator i = pimpl->dmap.find(port);
89     if (i != pimpl->dmap.end())
90     {
91         return i->second.allChannels;
92     }
93     else
94     {
95         return true;
96     }
97 }
98 
99 
port(int port)100 Instrument *Destination::port(int port)
101 {
102     DestinationImpl::dmap_type::iterator i = pimpl->dmap.find(port);
103     if (i != pimpl->dmap.end())
104     {
105         Instrument *instrument = i->second.allChannels
106                                ? i->second.instruments[0]
107                                : 0;
108         return instrument ? instrument : pimpl->defaultInstrument;
109     }
110     else
111     {
112         return pimpl->defaultInstrument;
113     }
114 }
115 
116 
setPort(int port,Instrument * instrument)117 void Destination::setPort(int port, Instrument *instrument)
118 {
119     if (instrument)
120     {
121         pimpl->dmap[port].allChannels    = true;
122         pimpl->dmap[port].instruments[0] = instrument;
123     }
124     else
125     {
126         pimpl->dmap.erase(port);
127     }
128     notify(&DestinationListener::Destination_Altered,
129            TSE3::MidiCommand::AllChannels, port, instrument);
130 }
131 
132 
channel(int channel,int port)133 Instrument *Destination::channel(int channel, int port)
134 {
135     DestinationImpl::dmap_type::iterator i = pimpl->dmap.find(port);
136     if (i != pimpl->dmap.end() && channel >= 0 && channel < 16)
137     {
138         if (i->second.allChannels) channel = 0;
139         Instrument *instrument = i->second.instruments[channel];
140         return instrument ? instrument : pimpl->defaultInstrument;
141     }
142     else
143     {
144         return pimpl->defaultInstrument;
145     }
146 }
147 
148 
setChannel(int channel,int port,Instrument * instrument)149 void Destination::setChannel(int channel, int port,
150                              Instrument *instrument)
151 {
152     if (channel < 0 || channel >= 16) return;
153 
154     DestinationImpl::dmap_type::iterator i = pimpl->dmap.find(port);
155     if (i != pimpl->dmap.end())
156     {
157         if (i->second.allChannels)
158         {
159             for (int n = 1; n < 16; n++)
160             {
161                 i->second.instruments[n] = i->second.instruments[0];
162                 if (n != channel)
163                 {
164                     notify(&DestinationListener::Destination_Altered, n, port,
165                            i->second.instruments[0]);
166                 }
167             }
168         }
169     }
170     pimpl->dmap[port].allChannels          = false;
171     pimpl->dmap[port].instruments[channel] = instrument;
172 
173     notify(&DestinationListener::Destination_Altered, channel, port,
174            instrument);
175 }
176 
177 
178 /******************************************************************************
179  * Destination class: managing the ilist
180  *****************************************************************************/
181 
numInstruments() const182 size_t Destination::numInstruments() const
183 {
184     return pimpl->ilist.size();
185 }
186 
187 
instrument(size_t index)188 Instrument *Destination::instrument(size_t index)
189 {
190     if (index < pimpl->ilist.size())
191     {
192         return pimpl->ilist[index];
193     }
194     else
195     {
196         return 0;
197     }
198 }
199 
200 
instrument(const std::string & title)201 Instrument *Destination::instrument(const std::string &title)
202 {
203     std::vector<Instrument*>::iterator i = pimpl->ilist.begin();
204     while (i != pimpl->ilist.end() && (*i)->title() != title)
205     {
206         ++i;
207     }
208     return (i == pimpl->ilist.end()) ? 0 : *i;
209 }
210 
211 
addInstrument(Instrument * instrument)212 void Destination::addInstrument(Instrument *instrument)
213 {
214     std::vector<Instrument*>::iterator i = pimpl->ilist.begin();
215     while (i != pimpl->ilist.end() && (*i)->title() < instrument->title())
216     {
217         ++i;
218     }
219 
220     if (i == pimpl->ilist.end() || instrument->title() != (*i)->title())
221     {
222         pimpl->ilist.insert(i, instrument);
223         notify(&DestinationListener::Destination_InstrumentAdded, instrument);
224     };
225 }
226 
227 
removeInstrument(Instrument * instrument)228 void Destination::removeInstrument(Instrument *instrument)
229 {
230     // Check its in the managed list
231     std::vector<Instrument*>::iterator i
232         = find(pimpl->ilist.begin(), pimpl->ilist.end(), instrument);
233     if (i == pimpl->ilist.end()) return;
234 
235     // Check every destination
236     DestinationImpl::dmap_type::iterator di = pimpl->dmap.begin();
237     while (di != pimpl->dmap.end())
238     {
239         int maxc = (di->second.allChannels) ? 1 : 16;
240         for (int channel = 0; channel < maxc; channel++)
241         {
242             if (di->second.instruments[channel] == instrument)
243             {
244                 di->second.instruments[channel] = 0;
245                 notify(&DestinationListener::Destination_Altered,
246                        channel, di->first, (Instrument*)0);
247             }
248         }
249         ++di;
250     }
251     if (pimpl->defaultInstrument == instrument)
252     {
253         pimpl->defaultInstrument = 0;
254     }
255 
256     pimpl->ilist.erase(i);
257     notify(&DestinationListener::Destination_InstrumentRemoved, instrument);
258 }
259 
260