|
|
This class provides an editable MidiData area. It is the mechanism used to generate Phrase objects.
The PhraseEdit object can be used as an area into which MidiEvent data is recorded in real time (it is used by the Transport class), or as the basic data structure for a GUI Phrase editor, for example.
For this latter mode of usage, the PhraseEdit class provides a number of callbacks (see PhraseEditListener) that can be used to keep the display updated.
The state of the PhraseEdit area can be one of:
It is up to the user to know if a PhraseEdit area may be untidy and to deal with it appropriately (i.e. make sure it is never played). After having tidied the data (by calling tidy()) the only way to make the data untidy is to write a MidiEvent directly using operator[]().
When the PhraseEdit is tidy, the safest way of modifying a MidiEvent is to remove it and the reinsert the modified MidiEvent.
The PhraseEdit object can manage the selection status of it's MidiEvent contents. This will be useful for GUI editors that use the PhraseEdit as the underlying data buffer.
Selections are denoted by the selected
bit in the MidiCommand
data type. You can use select() and deselect() to alter
selection states.
For convenience the PhraseEdit class remembers the index of the first and last selected MidiEvent.
Working with selections only really makes sense when the data area is tidy. You can still use the selection facilities with an untidy data area, however.
As an extra utility for GUI uses, the PhraseEdit class manages a 'modification' status. It allows the user to find out whether the data has been modified since the last reset(), and also fires an event off the first time it is modified.
Changing the selection does not affect the modified status.
Use the following command classes to manipute this object in a undo/redo environment.
See also: MidiData, Phrase
explicit PhraseEdit (int noEvents = defaultSize)
| PhraseEdit |
Create a PhraseEdit with the given number of events space reserved.
It is not really necessary to specify this size unless you know at least how many events will be inserted and reserving them will result in a worthwhile performance increase.
The PhaseEdit is initially created in an unmodified state (see modified()).
Parameters:
noEvents | Ignorable PhraseEdit size |
~PhraseEdit ()
| ~PhraseEdit |
[virtual]
void reset (const MidiData *source = 0)
| reset |
Resets the PhraseEdit area to be a copy of the given MidiData.
If the source
pointer is zero, the PhraseEdit area will be
blank.
The modified status value will be cleared (see modified()) which may result in the modified event being raised.
Parameters:
source | MidiData to copy |
void tidy (Clock stopTime = -1)
| tidy |
Tidies the MidiData (usually used after recording has stopped) This does a number of things, including adding any missing MidiCommand_NoteOffs and the conversion of sustain pedal usage into elongated notes. It removes all events before time zero (with a small tollerance)
The data in the PhraseEdit at this point could be in any state. MidiCommand_NoteOffs may be collated into the correct MidiEvent, or they may be in their own event (which they will be when just recorded). Events may be in time order, or in some completely random order.
It also collates all MidiCommand_NoteOffs into the appropriate MidiCommand_NoteOns so that the PhraseEdit area will contain valid data that can be streamed out through a Playable interface.
Prior to using tidy, you may need to apply timeShift().
This may cause the modified event to be raised.
Parameters:
stopTime | The time of the end of this MidiData (e.g. the time recording stopped). If no stopTime is specified then it is inferred from the last event in the MidiData. |
See also: tollerance
void timeShift (Clock delta)
| timeShift |
Shift the time of every event in the PhraseEdit by delta
(the new event times are originalTime + delta
).
This operation can be applied to tidy() or untidy PhraseEdit data.
You might want to use this method when recording MidiEvent data from an external source (using the Transport class) and you haven't started recording at the time zero. Once recording has finished you can "normalise" the recorded data to a reference start time of zero by calling
timeShift(-recordingStartTime); |
If you do this, you will want to timeShift BEFORE calling tidy(), so that you won't get a whole slew of events with minus times (which would not be "tidy" data).
In order for a Phrase to play in a Part correctly, you must ensure that it has a reference start time of zero, so you should take care to perform this operation. (Alternatively, use the App::Record class which does all this for you).
If you apply this method before calling tidy, don't forget
to add the delta time to the tidy()'s stopTime
parameter
as well.
Note that this operation can leave data untidy.
This will cause the modified event to be raised.
Parameters:
delta | Clock value to add to every event |
Phrase * createPhrase (PhraseList *pl,
const std::string &title = "")
| createPhrase |
[const]
Creates a Phrase from this MidiData and inserts it into the specified PhraseList. Make sure that you have done a tidy() first.
If you don't specify a title for the new Phrase then it will automatically be given a name that is guaranteed not to be used by any other Phrase in the PhraseList (you can find out what it is with Phrase::title()).
If a Phrase with the supplied title
already exists in
the PhraseList then a PhraseListError is thrown, and
no new Phrase is created.
Parameters:
pl | PhraseList to insert the new Phrase into (and from which to source a new unique name, if required) |
title | New Phrase's title - leave blank to have one automatically generated |
Returns: New Phrase object spawned from the data in this PhraseEdit
Throws: PhraseListError
See also: tidy, Phrase, PhraseList
MidiEvent & operator[] (size_t n)
| operator[] |
Returns the nth MidiEvent in this MidiData object.
Note that, unlike the base MidiData class, this object is modifiable.
The value returned for an index that is out of range is undefined. The size() method describes the valid values.
If you set the event directly using this method you run the risk of leaving the PhraseEdit object 'untidy'.
Any data manipulation performed via this operator will not affect the modified status, and so no modified event will be raised.
In simple terms, use this method at your own risk!
Parameters:
n | Index |
Returns: MidiEvent at index n
Reimplemented from MidiData.
void insert (MidiEvent event)
| insert |
Insert a MidiEvent into the MidiData in time order.
If this is a MidiCommand_NoteOn then you really want the MidiEvent to also hold the ballancing MidiCommand_NoteOff in its 'second half'.
If it does then you can be assured that adding the MidiEvent to a 'tidied' PhraseEdit object will leave the object still 'tidy'. If you only add a MidiCommand_NoteOn/ MidiCommand_NoteOff without the ballancing MIDI command then the PhraseEdit is left 'untidy' and any use of it to create a Phrase and/or have it's data streamed out of a Playable interface is invalid.
This restriction is important in the use of the TSE3 library, if you don't use 'tidy' MidiData then playback will produce 'undefined' (very probably wrong) output.
This may cause the modified event to be raised.
Parameters:
MidiEvent | to insert |
See also: tidy
void erase (size_t n)
| erase |
Remove a MidiEvent from the MidiData. The result
is undefined if the index n
is invalid.
This may cause the modified event to be raised.
Parameters:
n | Index of MidiEvent to remove |
void erase (MidiEvent event)
| erase |
Remove a MidiEvent from the MidiData. If there isn't a MidiEvent * matching this one then no change occurs.
This may cause the modified event to be raised.
Parameters:
event | MidiEvent to remove |
void select (size_t index)
| select |
Selects the MidiEvent at the specified index.
See also: deselect, selectRange
void selectRange (size_t from, size_t to)
| selectRange |
Selects every MidiEvent between the specified indexes.
See also: select, deselect
void deselect (size_t index)
| deselect |
Deselects the MidiEvent at the specified index.
See also: select
void clearSelection ()
| clearSelection |
Clears any selection.
void invertSelection ()
| invertSelection |
Inverts the selection status of every MidiEvent.
bool selection ()
| selection |
[const]
Returns true if any MidiEvent is selected.
Returns: Whether any MidiEvent is selected
size_t firstSelectionIndex ()
| firstSelectionIndex |
[const]
Returns the index of the first selected MidiEvent. If no MidiEvent has been selected, returns the value of size().
Returns: The index of the first selected MidiEvent
size_t lastSelectionIndex ()
| lastSelectionIndex |
[const]
Returns the index of the last selected MidiEvent. If no MidiEvent has been selected, returns the value of size().
Returns: The index of the last selected MidiEvent
void eraseSelection ()
| eraseSelection |
Erases any MidiEvent that has been selected.
This may cause the modified event to be raised.
bool modified ()
| modified |
[const]
Returns true if the PhraseEdit has been modified since creation or the last reset().
Returns: Whether PhraseEdit has been modified
void setModified (bool m)
| setModified |
Allows you to manually set the modified status.
This may cause the modified event to be raised.
Parameters:
m | New modified status. |
static const int defaultSize | defaultSize |
static const int tollerance | tollerance |