1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7     See the AUTHORS file for more details.
8 
9     This program is free software; you can redistribute it and/or
10     modify it under the terms of the GNU General Public License as
11     published by the Free Software Foundation; either version 2 of the
12     License, or (at your option) any later version.  See the file
13     COPYING included with this distribution for more information.
14 */
15 
16 #ifndef RG_CONTROLBLOCK_H
17 #define RG_CONTROLBLOCK_H
18 
19 #include "base/Device.h"  // DeviceId
20 #include "base/MidiProgram.h"  // InstrumentId, MidiFilter
21 #include "base/Track.h"  // TrackId
22 
23 namespace Rosegarden
24 {
25 
26 class RosegardenDocument;
27 class Studio;
28 
29 struct InstrumentAndChannel
30 {
31     // Default to an invalid value.
InstrumentAndChannelInstrumentAndChannel32     InstrumentAndChannel() :
33         id(0),
34         channel(-1)
35     { }
InstrumentAndChannelInstrumentAndChannel36     InstrumentAndChannel(InstrumentId idIn, int channelIn) :
37         id(idIn),
38         channel(channelIn)
39     { }
40 
41     InstrumentId id;
42     int channel;
43 };
44 
45 struct TrackInfo
46 {
47 public:
48     /// This should be the ctor.
49     void clear();
50 
51     /// Get instrument and channel, preparing the channel if needed.
52     /**
53      * Return the instrument id and channel number that this track plays on,
54      * preparing the channel if needed.  If impossible, return an invalid
55      * instrument and channel.
56      *
57      * @author Tom Breton (Tehom)
58      */
59     InstrumentAndChannel getChannelAsReady(Studio &studio);
60 
61     /// Make track info conformant to its situation.
62     /**
63      * In particular, acquire or release a channel for thru events to
64      * play on.
65      *
66      * @author Tom Breton (Tehom)
67      */
68     void conform(Studio &studio);
69 
70     /// Release the channel that thru MIDI events played on.
71     /**
72      * @author Tom Breton (Tehom)
73      */
74     void releaseThruChannel(Studio &studio);
75 
76     /// Make the channel ready to play on.  Send the program, etc.
77     /**
78      * @author Tom Breton (Tehom)
79      */
80     void makeChannelReady(Studio &studio);
81 
82     /// Adjust channel based on fixed/auto mode change.
83     void instrumentChangedFixity(Studio &studio);
84 
85     /*******************************************************
86      * !!! ONLY PUT PLAIN DATA HERE - NO POINTERS EVER !!! *
87      *******************************************************/
88 
89     /// Track is no longer in the Composition.
90     bool m_deleted;
91 
92     bool m_muted;
93     bool m_archived;
94     bool m_armed;
95     bool m_solo;
96 
97     /// Recording filters: Device
98     DeviceId m_deviceFilter;
99     /// Recording filters: Channel
100     char m_channelFilter;
101     /// Recording filters: Thru Routing
102     Track::ThruRouting m_thruRouting;
103 
104     InstrumentId m_instrumentId;
105 
106     /// The channel to play thru MIDI events on, if any.
107     /**
108      * For unarmed unselected tracks, this will be an invalid channel.  For
109      * fixed-channel instruments, this is the instrument's fixed channel.
110      */
111     int m_thruChannel;
112     /// Whether the thru channel is ready - the right program has been sent, etc.
113     bool m_isThruChannelReady;
114     /// Whether we have allocated a thru channel.
115     bool m_hasThruChannel;
116     /**
117      * This duplicates information in ControlBlock.  It exists so that
118      * we can check if we need a thru channel using just this class.
119      */
120     bool m_selected;
121     /**
122      * This is usually the same as Instrument's fixedness, but can
123      * disagree briefly when fixedness changes.  Meaningless if no channel.
124      */
125     bool m_useFixedChannel;
126 
127 private:
128     void allocateThruChannel(Studio &studio);
129 };
130 
131 // should be high enough for the moment
132 #define CONTROLBLOCK_MAX_NB_TRACKS 1024
133 
134 /// Control data passed from GUI thread to sequencer thread.
135 /**
136  * This class contains data that is being passed from GUI threads to
137  * sequencer threads.  It used to be mapped into a shared memory
138  * backed file, which had to be of fixed size and layout (with no
139  * internal pointers).  The design reflects that history to an extent,
140  * though nowadays it is a simple singleton class with no such
141  * constraint.
142  *
143  * SequenceManager monitors the Composition and updates the data here.
144  * RosegardenSequencer and the mappers (e.g. InternalSegmentMapper) use
145  * the data found here.
146  *
147  * ??? It seems strange that this class/object is used for communication
148  *     between threads, yet it is lock free.  I suspect this is OK since
149  *     we never move more than a word at a time.  The only issue might
150  *     be inconsistency across fields.  And in that case, there is little
151  *     that can really go wrong.
152  *
153  * @see SequencerDataBlock
154  */
155 class ControlBlock
156 {
157 public:
158     static ControlBlock *getInstance();
159 
160     void setDocument(RosegardenDocument *doc);
161 
162     //unsigned int getMaxTrackId() const { return m_maxTrackId; }
163 
164     /// Update m_trackInfo for the track.
165     void updateTrackData(Track *);
166 
167     void setInstrumentForTrack(TrackId trackId, InstrumentId);
168     InstrumentId getInstrumentForTrack(TrackId trackId) const;
169     bool isInstrumentUnused(InstrumentId instrumentId) const;
170 
171     void setTrackArmed(TrackId trackId, bool armed);
172     //bool isTrackArmed(TrackId trackId) const;
173 
174     void setTrackMuted(TrackId trackId, bool muted);
175     bool isTrackMuted(TrackId trackId) const;
176     bool isInstrumentMuted(InstrumentId instrumentId) const;
177 
178     void setTrackArchived(TrackId trackId, bool archived);
179     bool isTrackArchived(TrackId trackId) const;
180 
181     void setSolo(TrackId trackId, bool solo);
182     bool isSolo(TrackId trackId) const;
183     bool isAnyTrackInSolo() const;
184 
185     void setTrackDeleted(TrackId trackId, bool deleted);
186     //bool isTrackDeleted(TrackId trackId) const;
187 
188     /// Recording filters: Device
189     void setTrackDeviceFilter(TrackId trackId, DeviceId);
190     //DeviceId getTrackDeviceFilter(TrackId trackId) const;
191 
192     /// Recording filters: Channel
193     void setTrackChannelFilter(TrackId trackId, char channel);
194     //char getTrackChannelFilter(TrackId trackId) const;
195 
196     /// Recording filters: Thru Routing
197     void setTrackThruRouting(TrackId trackId, Track::ThruRouting thruRouting);
198 
setInstrumentForMetronome(InstrumentId instId)199     void setInstrumentForMetronome(InstrumentId instId)
200         { m_metronomeInfo.m_instrumentId = instId; }
201     //InstrumentId getInstrumentForMetronome() const
202     //    { return m_metronomeInfo.m_instrumentId; }
203 
setMetronomeMuted(bool mute)204     void setMetronomeMuted(bool mute) { m_metronomeInfo.m_muted = mute; }
isMetronomeMuted()205     bool isMetronomeMuted() const     { return m_metronomeInfo.m_muted; }
206 
207     void setSelectedTrack(TrackId track);
getSelectedTrack()208     TrackId getSelectedTrack() const     { return m_selectedTrack; }
209 
setThruFilter(MidiFilter filter)210     void setThruFilter(MidiFilter filter) { m_thruFilter = filter; }
getThruFilter()211     MidiFilter getThruFilter() const { return m_thruFilter; }
212 
setRecordFilter(MidiFilter filter)213     void setRecordFilter(MidiFilter filter) { m_recordFilter = filter; }
getRecordFilter()214     MidiFilter getRecordFilter() const { return m_recordFilter; }
215 
216     /// Get the output instrument and channel for an incoming event.
217     InstrumentAndChannel getInstAndChanForEvent(
218             bool recording, DeviceId deviceId, char channel);
219 
220     void vacateThruChannel(int channel);
221     void instrumentChangedProgram(InstrumentId instrumentId);
222     void instrumentChangedFixity(InstrumentId instrumentId);
223 
224 private:
225     // Singleton.  Use getInstance().
226     ControlBlock();
227 
228     void clearTracks();
229 
230     RosegardenDocument *m_doc;
231 
232     unsigned int m_maxTrackId;
233 
234     bool m_isSelectedChannelReady;
235     MidiFilter m_thruFilter;
236     MidiFilter m_recordFilter;
237 
238     TrackId m_selectedTrack;
239 
240     TrackInfo m_metronomeInfo;
241 
242     TrackInfo m_trackInfo[CONTROLBLOCK_MAX_NB_TRACKS];
243 };
244 
245 }
246 
247 #endif
248