tse3-0.3.1/0000777000175700017570000000000010310240000007370 500000000000000tse3-0.3.1/doc/0000777000175700017570000000000010310240000010135 500000000000000tse3-0.3.1/doc/src/0000777000175700017570000000000010310240000010724 500000000000000tse3-0.3.1/doc/src/Trouble.html.in0000644000175700001440000000471710271145632013572 00000000000000 Troubleshooting

Troubleshooting

Below are listed some commonly found problems. If you can't get TSE3 working then look here. If you don't find the answer, then just ask!


I can't get any output
When you run tse3play do you get any errors? If so then look for a description below.

If not, do you have your soundcard installed correctly? You can run tse3play with the --verbose parameter to get some diagnostics about the setup of your soundcard. If no soundcard is listed then try reinstalling it.
If you do have a soundcard installed and setup properly, is it's volume raised, and have you got your speaker cable in the correct socket?

Does the soundcard support both MIDI and audio output - the --verbose output will tell you which output TSE3 uses by default; trying forcing it to another port with --force-port.

I get the message "Opening FM patch file failed"
You have an FM soundcard and so TSE3 tries to load the FM patches file on your computer to put sounds into your soundcard. The files are commonly found in /etc/midi, however on your system the files are not here.
The files TSE3 is looking for are: std.o3, std.sb, drums.o3 and drums.sb. If you locate this file, try running tse3play with the --patches-dir parameter.
I get the message "Opening GUS patch file failed"
You have a GUS soundcard and so TSE3 tries to load the GUS patches files on your compueter to put sounds into your soundcard. The files are commonly found in /etc/midi, however on your system the files are not here.
The files TSE3 is looking for are *.pat, which includes, for example, acpiano.pat and epiano1.pat. If you locate this file, try running tse3play with the --patches-dir parameter.
tse3-0.3.1/doc/src/Examples.html.in0000644000175700001440000000467410271145632013736 00000000000000 TSE3 code examples

TSE3 code examples

These are a few simple examples of using the TSE3 library to show how easy it really is to use. There are some more example programs in the TSE3 source tree, look in tse3/src/examples for more information.

First, this is how you load a standard MIDI file:

    void loadAMidiSong(const std::string &filename)
    {
        TSE3::MidiFileImport mfi(filename);
        TSE3::Song *song = mfi.load();
    }
    

The song variable now contains a TSE3 Song class with the contents of this MIDI file. In fact, if you just want to play the MIDI file, and don't want to work on the data in it, you don't even need to convert it to a TSE3 Song - you can just play it directly. The Transport class is used to perform playback:

    void playAMidiSong(const std::string &filename, TSE3::Transport &transport)
    {
        TSE3::MidiFileImport mfi(filename);
        transport.play(mfi);
        while (transport.status() == Playing)
        {
            transport.poll();
            // Delay for a bit here to prevent processor hogging
        }
        // Playback has now finished
    }
    

Of course, there are more elegant ways of waiting for playback to stop than a clumsy loop, and TSE3 provides them to you. (See the TransportListener class for details).

Perhaps you want to send the different channels of the MIDI file to different MIDI ports (perhaps one to an external MIDI device, and one to the internal soundcard). We can use the MidiMapper to do this easily. This is how you would set it up (baring in mind the MIDI file will by default play from port 0):

    void setUpMidiMapper(TSE3::Transport &transport)
    {
        // Set channel 0 port 0 to go to channel 1, port 2
        transport.midiMapper()->setMap(0, 0, 1, 2);

        // Set channel 1 port 0 to go to channel 0, port 1
        transport.midiMapper()->setMap(1, 0, 0, 1);
    }
    

When you next play the MIDI file, the output will be routed accordingly. Facilities exist to find out what physical port is represented by each number. You can hide the numbers from the user and work with port names, too.

These are a few very simple examples of using TSE3 - it can do a whole lot more! tse3-0.3.1/doc/src/Playable.html.in0000644000175700001440000002011510271145632013675 00000000000000 MIDI data and the Playable Interface

MIDI data and the Playable interface

MIDI data handling in TSE3

The TSE3 library has a single header file providing definitions for the elements of the standard MIDI specification. This is the file Midi.h (see the reference at the bottom of this page).

It defines the following elements:

The Clock data value type.
Describes a time value in a song, as a number of ticks. These ticks are in units of a pulse. There is a fixed number of pulses per quarter note (PPQN) defined in Clock::PPQN. (A quarter note is another name for a crotchet.)
The Event template data value type.
Provides a standard way to generate object which associate a data value (for example, a tempo change) with a time in Clocks.
The MidiCommands and other similar definitions.
Definitions of all the MIDI status bytes (e.g. MidiCommand_NoteOn, system commands, controller values etc. These are: MidiCommands, MidiSystemCommands, and MidiControlChanges.
The MidiCommand data value class.
This is the basic value type used to describe a single MIDI command, including it's statub byte, channel and port pair (which describe where the MIDI command should be sent), and any data bytes.
The MidiEvent data value class.
This is built upon the MidiCommand class, but associates it with an event time in Clocks.
Note that here we do not use the Event template class as a definition. This is because the MidiEvent contains a second MidiCommand, used if the first is a MidiCommand_NoteOn. If so, the second command holds the related MidiCommand_NoteOff event. This can be used by the TSE3 library to ensure that all MIDI note off events are sent for any scheduled note on event.
The TSE3MetaMidiCommand definitions.
These are a number of extension status bytes only understood by the TSE3 library which are used internally.

Used together, these definitions describe standard MIDI data, scheduled to some clock source. The TSE3 song components generate musical data in this format.

The kdoc documentation describes these classes. You can find further information about them there.

The playable interface

Each component that comprises a Song can produce some sort of stream of MIDI data that needs to be scheduled to a timed output. To simplify this process they implement the Playable interface. This makes the Song structure use a form of the composite design pattern (GoF book).

The PlayablePlayableIterator that can iterate over the MIDI data in the output stream. This is a form of the iterator design pattern.

Each different kind of Playable object provides it's own implementation of the PlayableIterator interface that knows how to generate the MIDI events.

The user can ignore the individual song components Playable interface, and meerly use the Song's PlayableIterator that will in turn use the Playable iterators of all sub components to create a MIDI data stream for the whole song.


+------------\     +------------+      creates +--------------------+
| Interface  |_\   |  Playable  |--------------|  PlayableIterator  |
|              |   +------------+              +--------------------+
+------------- +         ^                               ^
                         |                               |
+------------\           |                               |
|   Example  |_\   +------------+              +--------------------+
| Implemenation |  |    Song    |              |    SongIterator    |
+---------------+  +------------+              +--------------------+

The data generated by a PlayableIterator object is in the form described above, as defined by the Midi.h header file.

Streaming system exclusive MIDI data

System exclusive MIDI data is a particular nuisance. All sequencer systems have this problem. If you don't care about, or know about system exclusive MIDI data (or sysex data) then you can skip this section.

Any other form of MIDI data, for example MidiCommand_NoteOn events and the like, can be interspersed in any order. They are sent in whole atomic units (the MidiEvent or MidiCommand classes). They are easy to handle and stream around the system in PlaybaleIterator objects.

However, sysex events break this simple atomic data structure. They can be of arbitrary size, with a single start of sysex system byte at the start, and an end of sysex status byte at the end.

So how do we stream these around using the PlayableIterator class? Carefully, is the answer.

Sysex data has been designed to fit into the Playable architecture rather than be handled as a special case. However, there are certain restrictions involved in their use.

The start of a sysex block is naturally defined by a MidiCommand with MidiComand_System status byte and reason code MidiSystem_SysExStart. The data1 byte contains the first data byte. data2 is not used. If the event is held in a MidiEvent (rather than a single MidiCommand - this will be true if it is streamed from a PlayableIterator) then the second (note off) field is not used to hold extra values.

The next MidiCommand may need to be another sysex data byte. In this case the same status information is put in the MidiComand - although the playing MidiScheduler object knows not to send this again. data1 contains this next data byte. More sysex data bytes may follow.

The stream carries on in this manner until the end of the sysex data block, when a MidiComand containing the MidiSystem_SysExEnd status information is put in the stream.

As stated above, sysex data cannot be rearranged. Nor can other MIDI events occur in the middle of them (you cannot shove a note on in the middle of a block of sysex). For this reason any PlayableIterator must take care to give each sysex MidiCommand exactly the same clock time to ensure no other events can get into the middle of the sysex stream.

The standard TSE3 PlayableIterator objects are designed in such a way that if all events have the same event time, events from other sources will not interrupt the stream.

See also

  • Midi.h for descriptions of the TSE3 representation of MIDI data.
  • Playable.h for the definition of the Playable class.
tse3-0.3.1/doc/src/InsFiles.html.in0000755000175700001440000001413310271145632013666 00000000000000 Cakewalk .ins files

Cakewalk .ins files

Introduction

The Instrument class provides support for instrument definitions (i.e. textual representations of the program/bank/controller names). These are read from the widely available Cakewalk instrument definition format files. (Cakewalk is a PC sequencing package).

File format

These files generally have a .ins suffix and are of a textual nature.

Unfortunately, the file format is not documented anywhere by Cakewalk, so I have produced my own interpretation of the file format. If anyone knows of any better descriptions I'd love to know!


Pete's interpretation of the Cakewalk .ins instrument file format

Overview

The file conists of a number of sections which begin with the following lines (they are generally found in this order, I doubt this is important):

Section nameDescription

".Patch Names"Describes groups of patches
".Note Names"Describes note names for some patch
".Controller Names"Describes all controller names for some device
".RPN Names"Describes RPN values for some device
".NRPN Names"Describes NPRN values for some device
".Instrument Definitions"Describes instruments based on above sections

Section contents

General file conventions:

  • Within each of these sections are subsections delimited by "[" and "]".
  • Subsection names and other text values may contain spaces.
  • Comments begin with a ";" and go to the end of the line. They may occur at any point in a line.
  • Subsections may reference other subsections - case is sensitive.
  • Patch values default to "0-127" rather than "1-128".

The first 5 sections have practically identical format, and contain a number of subsections. These subsections define a mapping of number (0-127) to textual representation. All or only some of the numbers may be given a mapping. Unspecified entries default to an empty string.

  • Each subsection is introduced "[SomeSectionName]".
  • The next line may be "BasedOn=" in which case this group of values refers to the named subsection. Any values from the 'base' may be later redefined in this section. The BasedOn 'base' subsection definition may be after of before this subsection in the file.
  • There follows any number of lines of the format "X=SomeName" where X is a value 0-127 and SomeName is the text associated with that value.

There are inbuilt patch names "0..127" and "1..128" which are defined as just the numbers.

The ".Instrument Definitions" section

The ".Instrument Definitions" section is different; it describes instruments based on the information in the previous sections.

  • There is a subsection for each instrument defined, the subsection name is the instrument name. The subsection heading is in the format "[SomeInstrument]".
  • The definition consists of the following sections, which if removed have the indicated defaults. Each entry is described below.

NameDefault

"UseNotesAsControllers=1"=0
"Control="No controllers for this instrument.
"RPN="No RPNs defined
"NRPN="No NRPNs defined
"BankSelMethod="=0
"Patch[#]="No patch for #
"Key[#,%]="No key definitions for #,%
"Drum[#,%]=1"Drum[#,%]=0
Notes
  1. "#" represents a bank select value. This is a composite value based on the bank select MSB and LSB which is equal to (MSB<<7)+LSB.
  2. "%" represents a program change value.

  • The controller names definied for an instrument are given by the "Control=" line. Following the "=" is a subsection name from the ".Controller Names" section.
  • The instrument patch names for a given bank value are defined by the "Patch[#]=" line. If # is a "*" then this matches for every bank select. There may be more than one "Patch[#]=" line.
  • The "Key[#,%]=" line defines key names for a particular patch on a particular bank select.
  • If the "Drum[#,%]=" line sets the drum flag for a patch/bank select value then the editor should default to a drum editor for this voice.
  • "BankSelMethod=" takes a value from 0 to 3. These mean
ValueMeaning

0Normal - bank select MSB and LSB matter
1Only the MSB is used and defined
2Only the LSB is used and defined
3Only program changes are used and defined
  • The "UseNamesAsController=" line denotes useage as for the "Mackie OTTO-1604". I have no idea what this means ;-)
tse3-0.3.1/doc/src/Song.html.in0000644000175700001440000001171010271145632013053 00000000000000 Song class hierarchy

Song class hierarchy

TSE3 has been designed in an object oriented fashion. Hence it takes an object oriented approach to it's song structure. This provides a lot of the powerful expressive features of the system.

The follows a class diagram of the song structure, which is explained below.


              +--------+                      1+----------------+
              |  Song  |---------------+-------|   TempoTrack   |
              +--------+               |       +----------------+
               |      |                |
               |      |                |      1+----------------+
              *|      |                +-------|  TimeSigTrack  |
        +---------+   |in PhraseList   |       +----------------+
        |  Track  |   |                |
        +---------+   |                |      1+----------------+
             |        |                +-------|   FlagTrack    |
 time ordered|        +------+                 +----------------+
            *|              *|
        +----+----+     1+----------+
        |  Part   |------|  Phrase  |
        +---------+      +----------+

The Song is a description of a particular piece of music. It consists primarily of Tracks, Parts and Phrases. Tracks are the sections of a Song that play simultaneously. They correspond loosely to the different people in a band playing together. One Track can perhaps handle the melody whilst another handles the bassline and yet another the drum beat.

Phrases are (typically small) snatches of music. They are recorded by the user can stored in a PhraseList in the Song. Once a Phrase has been recorded it needs to be placed into a Track to make some sound during playback of the Song. This is achieved with a Part.

Parts represent the physical placement of a Phrase in a Track. Since you can have any number of Parts in different Tracks using the same Phrase, it is easy to edit the one Phrase and change how each Part sounds. There is no messy ghosting or memory expensive copying of data.

Both Tracks and Parts contain a number of parameters that can affect the MIDI data that they produce. For example, Parts contain a number of real time filters such as linear quantise and velocity window clipping. Both also have a set of MIDI controls (such as pan, volume, program etc) that can be sent at their start.

In addition to these Song components, there are additional tracks known as the Master Tracks. They are

The TempoTrack
This defines any tempo changes that occur in the Song. The TempoTrack can be disabled preventing tempo changes from occurring during playback.
The TimeSig Track
This defines any time signature changes that occur in the Song. A change in time signature does not effect the recorded data but does affect the metronome at playback. The TimeSigTrack can be disabled preventing time signature changes from occurring during playback.
The FlagTrack
This is a track holding a number of general purpose markers. They do not affect playback in any way, but allow the user to mark certain positions to find it easier to navigate to them.
The Left and Right Markers
The Song also contains two marker positions about which 'repeat' takes place, if enabled. When playback reaches the right marker it jumps to the position of the left one.

More on Phrases

Phrases are not an editable type: once you have created a Phrase that MIDI data it contains will remain as it is until the Phrase is deleted.

To create a Phrase you use a PhraseEdit object. This is an editable type of Phrase, which once editing is completed can be used to create a Phrase.

These classes both inherit from a base MidiData class as shown below.


              +------------+
              |  MidiData  |
              +------------+
               ^          ^
               |          |
     +----------+        +--------------+
     |  Phrase  |        |  PhraseEdit  |
     +----------+        +--------------+
     | Title    |
     +----------+

The effect of editing a Phrase is achieved by creating a new Phrase with the same name as an existing Phrase, making all Parts that use the old Phrase now use the new Phrase, deleting the old Phrase and putting the new Phrase into the PhraseList. This operation is provided in the Song class. tse3-0.3.1/doc/src/Psalm150.html.in0000644000175700001440000000326010271145632013450 00000000000000 Psalm 150

Psalm 150

150:1 Praise the Lord! Praise God in His sanctuary;
    Praise Him in His mighty firmament!
150:2 Praise Him for His mighty acts;
    Praise Him according to His excellent greatness!
150:3 Praise Him with the sound of the trumpet;
    Praise Him with the lute and harp!
150:4 Praise Him with the timbrel and dance;
    Praise Him with stringed instruments and flutes!
150:5 Praise Him with loud cymbals;
    Praise Him with crashing cymbals!
150:6 Let everything that has breath praise the Lord.
    Praise the Lord!

You can do it with the MIDI sequencer too ;-)

The New King James Version (Copyright © 1982 by Thomas Nelson, Inc. All rights reserved.) tse3-0.3.1/doc/src/TSE3MDL.html.in0000755000175700001440000003053310271145632013227 00000000000000

File Format for TSE3 Music Description Language (TSE3MDL)

Pete Goodliffe
Issue 1.01
9th June 1999


Introduction

The TSE3 Music Description Language provides an object-oriented description of a piece of music as MIDI data, in a linear sequencer form.

It is designed for use with TSE3, the Trax Sequencer Engine v3.00 and so parallels its song structure closely.

This file format is for use with TSE version 3.00 and later. Specifically, it is incompatible with the earlier format known as TSEMDL which was used with TSE v2.00.

TSE3MDL files commonly have a file extension of .tse3 although the format can be deduced from the file contents: the first eight bytes are "TSE3MDL\n"

TSE3MDL file conventions

TSE3MDL files are plain text files readable in any text editor. The data is arranged into hierarchical chunks which closely parallel the TSE3 Song class hierarchy.

Because TSE3MDL files are in text, all numbers are in ASCII decimal form. Times are represented in pulses, as integer values.

Each line of a TSE3MDL file may contain any amount of whitespace at it's start which is ignored. This is commonly used to enhance the readablilty of the chunk hierarchy. Additionally, any lines which start with a hash (#) symbol (after any whitespace) are ignored as comment lines.

Case is important when recognising identifiers.

Each file chunk follows a standard format. This is as shown below:

    
    CHUNK_TAG_IDENTIFIER
    {
        DATA_IDENTIFIER:DATA
    }
        

The CHUNK_TAG_IDENTIFIER is a single word containing any characters except ':'. If an identifier of this format is found then it signifies the beginning of a new chunk. The opening and closing braces will be on separate lines. Within the chunk data is commonly indented by four spaces, but this is not mandatory. Chunks can be hierarchically arranged - chunks can contain chunks. Chunk tag identifiers correspond the their related object names in the TSE3 Song hierarchy.

Lines other than CHUNK_TAG_IDENTIFIERs must be DATA_IDENTIFIER lines. These consist of a single word identifier which can contain any characters except ':' followed by a ':' and then the data associated with that identifier. The identifier name is local to each type of chunk. For example, there are several types of chunk with identifiers Status. In each chunk this refers to a different type of setting.

If you encounter a chunk that is not recognised then it should be ignored. You may warn the user if required. Similarly, if you encounter a data identifier that you do not recognise you should ignore it.

File header

The TSE3MDL file consists of a single chunk, with a number of sub-chunks.

The top level chunk has tag identifier

TSE3MDL
, with the rest of the file contents contained in it's pair of braces. As a special case, the first line cannot be prefixed by ant whitespace.

This first line identifies the file type as being TSE3MDL. To check whether a file is in TSE3MDL you only need to check the first eight bytes (don't forget the carriage return following the tag).

Insider this

TSE3MDL
chunk there is usually a Header chunk, followed by a Song chunk.

Header chunk

A Header chunk has chunk tag identifier Header and is defined to contain the following identifiers.

IdentifierDescriptionDefault if not present
Version-MajorMajor version number of this file * 100100
Version-MinorMinor version number of this file * 100100
OriginatorIdentity of the program that created this file.n/a
PPQNPPQN resolution timestamps in this file are based upon.96

Song chunk

A Song chunk has chunk tag identifier Song and is defined to contain the following identifiers.

IdentifierDescriptionDefault if not present
TitleString containing the title of this Songempty
AuthorString containing the author of this Songempty
CopyrightString containing the copyright message for this Songempty
DateString containing the date of this Songempty
NoTracksNumber of Tracks in the Song. ???empty

A Song is also defined to contain TempoTrack, TimeSigTrack, FlagTrack, Phrase and Track chunks.

TempoTrack chunk

A TempoTrack chunk has chunk tag identifier TempoTrack and is defined to contain the following identifiers.

IdentifierDescriptionDefault if not present
Status'On' if tempo changes are enabled, or 'Off' disabled.On

There then follows another chunk with identifier Events containing the TempoTrack events. There is one event per line in the form TIME:TEMPO where TIME and TEMPO are integer values.

TimeSigTrack chunk

A TimeSigTrack chunk has chunk tag identifier TimeSigTrack and is defined to contain the following identifiers.

IdentifierDescriptionDefault if not present
Status'On' if timesig changes are enabled, or 'Off' disabled.On

There then follows another chunk with identifier Events containing the TimeSigTrack events. There is one event per line in the form TIME:TOP/BOTTOM where TIME, TOP and BOTTOM are integer values.

FlagTrack chunk

A FlagTrack chunk has chunk tag identifier FlagTrack and is defined to contain no identifiers.

It contains another chunk with identifier Events containing the FlagTrack events. There is one event per line in the form TIME:STRING where TIME is a integer value and STRING is the associated flag string..

Phrase chunk

A Phrase chunk has chunk tag identifier Phrase and is defined to contain the following identifiers.

IdentifierDescriptionDefault if not present
TitleString containing unique reference name of this Phrase.n/a

There then follows another chunk with identifier Events containing the Phrase events.

There is one event per line in the form TIME:STATUS/DATA1/DATA2/CHANNEL/PORT where all values are integers. STATUS contains the MidiCommand status nybble, DATA1 and DATA2 contain the data bytes (which will not have bit 7 set), CHANNEL contains a value from 0-15 and PORT the computer MIDI port number to send the data on.

If the MidiCommand is a MidiCommand_NoteOn (STATUS == 9) then the line is followed by -OFFTIME:OFFSTATUS/OFFDATA1/OFFDATA2/OFFCHANNEL/OFFPORT which contains the balancing MidiCommand_NoteOff. All values are as for the previous MidiCommand_NoteOn.

Track chunk

A Track chunk has chunk tag identifier Track and is defined to contain the following identifiers.

IdentifierDescriptionDefault if not present
TitleString containing name of this Track.empty
NoPartsNumber of Parts in this Track ???empty

The Track chunk is defined to contain MidiFilter, MidiParams and Part chunks.

MidiFilter chunk

A MidiFilter chunk has chunk tag identifier MidiFilter and is defined to contain the following identifiers.

IdentifierDescriptionDefault if not present
Status'On' to allow events to be generated by parent, false to mute the parent.On
ChannelChannel to force MIDI events to be produced on. -1 to disable.-1
PortPort to force MIDI events to be produced on. -1 to disable.-1
QuantiseLinear quantise value to snap events to. 0 has no effect.0
TransposeTranspose value (added to note values, -127-127).0
MinVelocityMin velocity clip window value.0
MaxVelocityMax velocity clip window value.127
VelocityScaleVelocity scale percentage, 1 - 200. 0 disables0

MidiParams chunk

A MidiParams chunk has chunk tag identifier MidiParams and is defined to contain the following identifiers. These identifiers have values 0-127, or -1 to disable.

IdentifierDescriptionDefault if not present
BankLSBBank LSB byte sent at beginning of parent.-1
BankMSBBank MSB byte sent at beginning of parent.-1
ProgramProgram change sent at beginning of parent.-1
PanPan controller sent at beginning of parent.-1
ReverbReverb controller sent at beginning of parent.-1
ChorusChorus controller sent at beginning of parent.-1
VolumeVolume controller sent at beginning of parent.-1

Part chunk

A Part chunk has chunk tag identifier Part and is defined to contain the following identifiers.

IdentifierDescriptionDefault if not present
PhraseTitle of Phrase used by this Part.n/a
StartStart time of Partn/a
EndEnd time of Partn/a
RepeatRepeat time value of Partn/a
OffsetOffset time value of Partn/a

The Part chunk is defined to contain MidiFilter and MidiParams chunks.

See also

The MIDI Specification Level 1.0 for descriptions of MIDI commands.

Revision history

9 June 19991.00First version. Implemented in TSE3.
1 September 20001.01Changed SimpleMidiEventFilter to MidiFilter.
29 January 20011.02Whole file is one big chunk. Comments.
tse3-0.3.1/doc/src/Notifier.html.in0000644000175700001440000001231310271145632013724 00000000000000 The Notifier/Listener Framework

The Notifier/Listener Framework

The TSE3 library uses a version of the "Observer" design pattern (GoF book), both as a part of it's public API and for internal implementation.

This design pattern is a framework for publishing information about events of interest. These events are multicast to every interested object. Objects can register an interest and revoke this at any time.

In the TSE3 implementation, the object which multicasts the events is of the Notifier class. Object which listen to these events are Listener classes.

These classes are documented fully in the tse3/Notifier.h header file. The system is flexible, and type safe. The multicast 'events' are implemented as callbacks on member functions. These member functions may have any number of parameters of any type. These methods are defined in abstract 'listener interfaces' (e.g. SongListener).

How to use the Notifier framework

Essentially, for each specific Notifier type an interface class is defined. This interface describes each of the possible events that may be emitted by that Notifier. Let's call this interface interface_type.

Now a class that can emit events inherits from Notifier<interface_type>. The implementation of the class can emit events by calling it's protected notify method.

A class that listens to these events inherits from Listener<interface_type>. This means that it also inherits the interface_type, and so implements the member functions that recieve events.

Now, a Listener can register an interest in events by calling Listener::attachTo for the appropriate Notifier, and revoke this interest with Listener::detachFrom.

What you can do in an event handler

Note that callback handlers are called synchronously by the TSE3 library. This means that as soon as an event occurs (i.e. Notifier::notify is called) every attached listener's handler function gets called immediately (well, one after the other). Following this, the code that called notify regains control.

This has some repurcussions on what you can/cannot do in an event handler. Since you are called in the context of the TSE3 library is best not to do too much processor intensive activity - you may cause TSE3 performance to drop.

The Notifier framework allows you to safely attach or detach from Notifier objects in an event handler. This can be the currently notifying object.

Note that if you perform an operation that will itself raise an event (i.e. perform a call to Notifier::notify) in your event handler, the new event will be passed around and handled completely before processing returns control to the original event handler.

Calling TSE3 modifying methods (e.g. most methods whose name starts with 'set') may therefore be unwise since they will probably perform a notify.

If the Transport polling is run in a background thread, some of your callbacks will be called in that thread's context. It may therefore be unsafe to perform certain operations, GUI updating for example.

Listener header files

The Listener interface classes for each of the TSE3 classes is in the listen subdirectory. For example the Transport class is defined in tse3/Transport.h. However, it's Listener interface class is defined in tse3/listen/Transport.h.

Each Listener class header both defines the callback interface and forward declares the relevant Notifier type. Using these headers you can therefore avoid large include file depenancy in your own project header files.

History

In TSE3 versions 0.0.12 and later the Notifier framework is considerably improved. The system is now a lot more safe, elegant and above all easy to use.

TSE3 version 0.0.22 saw some fixes to the Notifer framework that allows you to safely call attach and detach in event handlers.

See also

Notifier.h for definitions of the notifier framework classes.

The classes are described in the KDOC class documentation:

tse3-0.3.1/doc/src/Bugs.html.in0000644000175700001440000000176210271145632013053 00000000000000 Known bugs and issues

Known bugs and issues

The TSE3 library is constantly under development. All feedback is welcomed to help improve the library.

There follows a list of the known bug and issues. If you can inform me of any other problems then I will be grateful.

  • A number of integer size checks need to be added to the build process. If your machine has int < 32 bits then the library will not work.
  • The DeMIDIfy utility class is not proven to work properly (this will wait until the graphical visualisation).
  • The application and commands classes are not very complete yet. These will be added as and when I need them whilst writing the Anthem sequencer, which uses this library.
tse3-0.3.1/doc/src/tse3logo.png.verbatim.in0000755000175700001440000000221310271145632015335 00000000000000‰PNG  IHDRLGšŽQÚPLTE"""333DUf""w33DU""f33wDDUUf"fw3wˆ™ª""»33ÌÝî""ÿ33ˆD™Uª"f»3wÌDÝUî"fÿ3wDU"f"3w3DDUUff"ww3DDUU"ff3wwDDDUUUfffwwwˆD™Uªf"»w3ÌDÝUîf"ÿw3ˆDD™UUªff»wwÌDDÝUUîffÿwwˆ™"ª"3»3DˆU™fª"w»3ˆD™U"ªf3»wDˆDU™Ufªfw»wˆˆ™™ªª"»»3̈ݙîª"ÿ»3ˆˆD™™Uªªf»»ẅDÝ™Uîªfÿ»wÌÝ"î"3ÿ3DÌUÝfî"wÿ3ÌDÝU"îf3ÿwDÌDUÝUfîfwÿwˆÌ™Ýªî"»ÿ3ÌÌÝÝîî"ÿÿ3ˆÌD™ÝUªîf»ÿwÌÌDÝÝUîîfÿÿwˆ™""ª33»DˆU™f"ªw3»ÌÝ""î33ÿDÌUÝf"îw3ÿˆˆ™™ª"ª»3»ÌˆÝ™î"ªÿ3»ˆÌ™ݪ"î»3ÿÌÌÝÝî"îÿ3ÿDˆU™"fª3w»DDˆUU™ffªww»DÌUÝ"fî3wÿDDÌUUÝffîwwÿˆDˆ™U™ªfª»w»ÌDˆÝU™îfªÿw»ˆDÌ™Uݪfî»wÿÌDÌÝUÝîfîÿwÿˆˆ™™"ªª3»»DˆˆU™™fªªw»»ˆÌ™Ý"ªî3»ÿDˆÌU™Ýfªîw»ÿˆˆˆ™™™ªªª»»»ÌˆˆÝ™™îªªÿ»»ˆˆÌ™™Ýªªî»»ÿ̈ÌÝ™Ýîªîÿ»ÿ̈Ý™"îª3ÿ»D̈UÝ™fîªwÿ»ÌÌÝÝ"îî3ÿÿDÌÌUÝÝfîîwÿÿˆÌˆ™Ý™ªîª»ÿ»Ì̈ÝÝ™îîªÿÿ»ˆÌÌ™Ýݪîî»ÿÿÌÌÌÝÝÝîîîÿÿÿsÏ4¤GIDATxœíØAƒ0CÑ9âH9Go•–@H<·t×° _oI,ì¡ TSE3 library history

TSE3 library history

TSE is an acronym for the Trax Sequencer Engine. The developer, Pete Goodliffe releases software under the moniker 'Trax Software'. TSE was originally developed for a sequencing project provisionally titled TraxSequencer.

TSE technology dates from 1996. The first version took a pattern based approach to the song structure which limited it's flexibility.

TSE1 lead rapidly to TSE2 which was developed and improved between 1997-1999. This was targetted at the Acorn RISC OS architecture only, although in theory should have been fairly portable. TSE2 is a linear sequencer engine. You record snatches of music called Phrases, and then place them inside Parts which are further put into the Tracks of a Song. This approach was considerably more flexible and powerful that the TSE1 approach.

TSE2 found its way into several RISC OS products. The first generation of TSE2 powered the TraxSequencer product. Later revisions to TSE2 and the user interface lead to the product Anthem. At its release Anthem was acclaimed as a new powerful way of sequencing, challenging the accepted norm.

TSE2 based products were only available commercially. See the R-Comp website for more information.

TSE3 is a third generation project based on the experience of TSE2. It includes the same revolutionary functionality but takes it into a new generation of implementation. Based on experience with TSE2, TSE3 provides a robust and powerful engine with greater extensability and portability. It draws on experience with TSE2 use in it's partitioning of the sequencer engine logic, the application support logic, the platform specific interfaces and the application itself in the most appropriate manner.

The C++ code has been brought up to a much more modern standard, leveraging the STL and other appropriate language features.

The other major difference between TSE2 and TSE3 is the release conditions. TSE3 is an open source project, allowing it to be used with few restrictions. It has been designed to be used by as large an audience as possible; indeed to be the defacto open source sequencer engine. tse3-0.3.1/doc/src/Build.html.in0000644000175700001440000000744310271145632013214 00000000000000 Building the TSE3 library

Building the TSE3 library

If you haven't yet built the TSE3 library, then this page describes how to do so.

Simple instructions

See the INSTALL file in the root of the source package for detailed instructions on how to install TSE3.

As you'd expect it is a simple case of typing:

        ./configure
        make
        make install
    

To install or not to install?

You may not want to install TSE3 on your system; it is still possible to use without installing. Once you have done a make you can type

        make tse3-lib-local
    
to create a lib directory with symlinks to all the built library files. Using this you can easily link other programs to your non-installed TSE3 libraries by specifying the lib directory to the linker.

You may want to see the documentation for your TSE3-aware application for more information on doing so.

You can remove this local directory by typing

        make tse3-lib-local-clean
    

Advanced options

It is possible to supply extra parameters to the ./configure command to customise how the TSE3 library is built. You can type ./configure --help to get a summary of these options. You will see a lot of standard configure options as well as the TSE3 specific ones.

New users may safely ignore these extra advanced options.

The TSE3 specific options are listed below. They all have an opposite version. The opposite is the default value. --with-mutex is the default so you don't need to specify it, for example.

  • --without-mutex Disables the support for multiple threads in TSE3. You may find that this makes the TSE3 library run with slightly better performance. However TSE3 will not safeguard it's internal data structures against access by multiple threads. You are advised to only use this option if you know what you are doing, or don't care what you're doing!
  • --without-oss Disables support for the Open Sound System (OSS) (and/or OSS/Free). This is the most common MIDI interface standard on modern Linux (and most other Unix) distributions. If you disable this the OSSMidiScheduler class will still be built, however it will do nothing, and you will not be able to create an object of this type (an exception will be thrown).
  • --without-alsa Disables support for the Advanced Linux Sound Architecture (ALSA). This is a popular new, developing, sound interface standard. However, it is still at an experimental stage. If you disable this the AlsaMidiScheduler class will still be built, however it will do nothing, and you will not be able to create an object of this type (an exception will be thrown).
  • --without-arts Disables support for the aRts, KDE soundserver MIDI interface.
If your Unix platform does not support either OSS/Alsa then the corresponding MidiScheduler facility will not be built into the TSE3 library.

Building documentation

There is a set of online programmer's reference documents that can be built automatically, using the KDOC program.

See the KDOC page for more information. tse3-0.3.1/doc/src/Article.html.in0000644000175700001440000003744210271145632013542 00000000000000 Linux, MIDI and Anthem

Linux, MIDI and Anthem

This article originally appeared at the Linux MusicStation.
It appeared as a feature article for October 2000.

Pete Goodliffe talks about the Anthem project, bringing usable MIDI sequencing to the Linux community.

Introduction

The Linux and free software communities are currently enjoying rapid growth, quickly gaining in popularity. However, the music composition arena seems to lag somewhere behind this surge. In many ways this is quite normal, the musician community is much smaller than the hordes of desktop Linux users. However, we are beginning to see a critical mass of musical developers and users which is beginning to redress this balance.

There are now a number of projects devoted to bringing music composition tools to Linux (just have a quick glance at the multimedia section of sourceforge). However, they're all fairly immature, and many have not yet produced any useful code whatsoever.

There have always been audio editing tools of sorts for Linux, nothing that the average Windows user would find easy to use, though. And for a long time there have been MIDI sequencing packages - but again not up to the quality of the quality of the famous Windows sequencers.

So will we ever get there? Will any of these projects see fruition? The answer is yes - and in this article I'll describe one of our routes to the open source music paradise we seek.

The Anthem project

One of the many new projects developing MIDI sequencing functionality is Anthem.

OK, so now a disclaimer - I'm the guy who's written Anthem. I hope you don't find that this article turns into a banal marketing speil, but is able to give you a clear overview of where this project is going. In fact, I'd like to see other sequencers than just Anthem appear on Linux - the competition and choice is what will encourage computer musicians to the Linux platform.

So what of Anthem?

The aim of the project is to create a fully-fledged and top quality MIDI sequencing studio with audio capabilities, that is capable of rivalling products found on any other platform. Those are lofty goals.

Any project can claim to be something it's not, and many do. So why should we believe that this will ever happen? The most important factor should surely be, what state is Anthem in now? In a nutshell:

  • It's a long way into development. There is real code there. Working.
  • All the MIDI playback and song structure functionality exists, (there's a lot of it, and it's very advanced)
  • No audio implementation exists at all
  • Not all the low-level editors (e.g. piano-roll) exist yet

That is to say, a lot of Anthem is there, but it's certainly not complete yet! So if the program's not finished, why should you care about it?

  • 1. The code is there

    Well, for a start, the code is not only written, but a lot of it is already being used in a number of other music projects (see below for the reasons why).

    Secondly, one of the great things about the open source movement is the release early/release often mentality. You can go and download development versions of the Anthem sequencer and see how well it works, and feed back your comments about it.

  • 2. The code is mature

    The project is based on mature technology, with years of experience. A version of Anthem already exists. I wrote it. However, this original version is proprietary and closed source. It runs on the Acorn RISC OS platform. If you're really curious have a look at www.rcomp.co.uk/rci/sound/anthem/anthem.htm. [1]

    However, this is a new, completely rewritten, much improved version of this original program. Its full title is therefore: "Anthem Open Source Edition".

    Experience is key - the main problems have already been identified and solved once. The ride is a lot smoother this time around. Of course, experience is no guarantee that the final program will materialise...

    It will, though!

  • 3. The project is well directed

    Now here's the interesting techie clincher: the project has been split into two parts. In the past (both on Linux and other platforms) I've seen far too many MIDI sequencer projects started the wrong way round: from the top downwards.

    You simply cannot write a GUI and then try to hack in a song structure and MIDI playback framework underneath. It doesn't fit. The program will never get off the ground. But you may end up with a nice looking set of windows.

    In this project the actual driving-force sequencer engine part has been written first; with careful consideration to the GUI aspects of the project (drawing on my experience having done this once already) but without the straight jacket of the quick-hack GUI mentality.

    The goal isn't so much to get a sequencer on your screen rapidly as to produce the best, most flexible, most powerful sequencer possible.

  • 4. The project is being worked on

    The important thing to bear in mind about the Anthem project is that is is developing very quickly. In comparison to the vast majority of sequencing projects you can find out there, this one is being updated. Many projects have appeared to lie stagnant for many many months.

    Other, older, sequencers are certainly functional now; but they still aren't developing so rapidly, and most Windows users would take one look at them a shudder. [2]

So Anthem comprises two main sections, the TSE3 library and the Anthem program. Both are released under the terms of the GNU public license. Both are written in C++. But what are they and what do they mean to the open source music community?

The TSE3 library

TSE3 is a third generation sequencer engine core. That is, it handles playback, and recording. It provides an advanced object-oriented song structure. It provides real-time effects (transpose, etc) and allows you to edit music on-the-fly. However, there is not a window in sight.

All the necessary functionality has been designed in from the start, where it needs to be thought out properly:

  • It's portable - not Linux specific, it doesn't rely on any non-standard C++ or C features or libraries
  • It abstracts the playback system, so it could be OSS, it could be ALSA or it could be something completely different (Timidity, anyone?)
  • It is designed in such a way that a song can be safely edited as it is played
  • It has intimate support for a GUI - using the MVC pattern to inform of changes
  • It supports multi-level undo/redo

It was developed first, before any flashy GUI stuff. It's been under development for a year and a half already. It's been carefully tweaked and honed, and is now a very powerful and rounded library. It's easy to use, fully documented and suitable for programs as simple as a MIDI file player to a fully featured MIDI sequencer (which is, of course, why it was written).

The library is mature - it's based on the TSE2 library which was in use in the original Anthem. However, it has many many improvements over TSE2 and is a complete rewrite from scratch.

So what does TSE3 give us? Here's a simple (and not comprehensive) summary:

  • An object oriented data structure for a "Song". This structure was acclaimed as an innovate and truly superior way of working when it first appeared on the Acorn platform.
  • File saving and loading based on this song type, as well as import/export of industry standard MIDI files.
  • Advanced playback system, with clever facilities such as synchro start, punch-in recording, midi echo, GS/GM/XG support and tonnes more...
  • A lot of application support, for example a command framework that allows you to provide unlimited undo/redo, support for Cakewalk instrument definition files for controller/program change information, and other important application support facilities.

An application can use a little or as much of this library as it requires. A few examples of using TSE3 are included at the end of this article.

TSE3 is stable and at a beta stage of development now.

About Anthem

The part of this project that most end users will be interested in is the Anthem sequencer. This is the main program. Using the TSE3 library, the Anthem sequencer delivers the power of TSE3's advanced features to the desktop in a user-friendly manner. So that sounds like a load of old marketing rubbish? Is it true?

Well, see for yourself. Many users will back up that statement.

Anthem is built using the KDE2 environment. Of course, that doesn't mean that you have to run all of KDE2 to use the program; you can just as easily run it under Gnome, or any X11 window manager as long as you install the base KDE2 libraries. However, it does fully exploit the available KDE2 facilities where available.

What state is it in now?

So I've said that Anthem isn't finished yet. I guess it will be hard to ever say when the project's finished because there will always be new features to add. However as it stands, the program allows you to create your music, arrange it, load it, save it, everything you would expect.

The low-level music editors are not all implemented, though. There is a 'list editor', but the 'piano-roll' editor is still under development. It will come! Score editing will be provided too, however this will be provided via a third-party plugin.

The audio-editing facilities have not even been began though. This will disappoint a number of readers. However, I do not want to embark on this and get it wrong. I need to coordinate my work with experts in this field to ensure that the audio facilities are as powerful and efficient as they can be. (See "How can you help", below.)

Anthem will see a 'plug-in' framework where a number of different types of editors and capabilities can be added according to taste. Audio is an example of this, perhaps we can incorporate video functionality as well.

When will it be finished?

There is no answer to this question. I guess the more important question is "when will it be usable?" To a large extent it already is. As more editors are added the usefulness of the program will increase. However, since I'm not working to a timetable and develop the program as a spare-time activity I can't answer fully.

How can you help?

So we've seen that Anthem is an ambitious and technically advanced project. It is already shown to work and is already in use. However, there are still areas needing work that volunteers may be interested in:

  1. Audio/video integration

    As I stated above, I'm not going to this on my own. Authors of HD recording systems and audio editing suites may like to coordinate our work.

  2. Use TSE3!

    A number of sequencer developers have told me that they are using TSE3. Since its so flexible TSE3 can be used in more than one way. Anthem is being developed as the sort of sequencer that I want to use. Other developers may prefer a more Cakewalk-like style of working. There is a plenty of scope for other Linux sequencers. However, TSE3 provides a solid base for them all to be built on.

    Likewise other multimedia projects which need MIDI playback support may consider using TSE3 for its stability and feature set.

  3. Use Anthem and feed back

    A self explanatory way to help - I will always need feedback to improve the program. Also a large number of good quality demonstration songs would be useful.

  4. Sponsor the project

    The last, but not the least, on this list.

    Currently TSE3 and Anthem are being developed on a machine pulled out of a skip. In bits. Literally. Processing power greater than a P100, and a soundcard with more capabilities than an old ISA AWE32 would greatly enhance what can be done.

Examples of using TSE3

I have been asked for a few simple examples of using the TSE3 library to show how easy it really is to use. So here they are...

First, this is how you load a standard MIDI file:

    void loadAMidiSong(const std::string &filename)
    {
        TSE3::MidiFileImport mfi(filename);
        TSE3::Song *song = mfi.load();
    }
    

The song variable now contains a TSE3 Song class with the contents of this MIDI file. In fact, if you just want to play the MIDI file, and don't want to work on the data in it, you don't even need to convert it to a TSE3 Song - you can just play it directly. The Transport class is used to perform playback:

    void playAMidiSong(const std::string &filename, TSE3::Transport &transport)
    {
        TSE3::MidiFileImport mfi(filename);
        transport.play(mfi);
        while (transport.status() == Playing)
        {
            transport.poll();
            // Delay for a bit here to prevent processor hogging
        }
        // Playback has now finished
    }
    

Of course, there are more elegant ways of waiting for playback to stop than a clumsy loop, and TSE3 provides them to you.

Perhaps you want to send the different channels of the MIDI file to different MIDI ports (perhaps one to an external MIDI device, and one to the internal soundcard). We can use the MidiMapper to do this easily. This is how you would set it up (baring in mind the MIDI file will by default play from port 0):

    void setUpMidiMapper(TSE3::Transport &transport)
    {
        // Set channel 0 port 0 to go to channel 1, port 2
        transport.midiMapper()->setMap(0, 0, 1, 2);

        // Set channel 1 port 0 to go to channel 0, port 1
        transport.midiMapper()->setMap(1, 0, 0, 1);
    }
    

When you next play the MIDI file, the output will be routed accordingly. Facilities exist to find out what physical port is represented by each number. You can hide the numbers from the user and work with port names, too.

These are a few very simple examples of using TSE3 - it can do a whole lot more!

Footnotes

Pete Goodliffe is a Senior Software Engineer with Pace Microsystems plc, working on TSE3 and Anthem in his <irony>"copious" spare time</irony>. He plays the keyboard, and is 'still' learning the harmonica (will someone please write a Linux device driver for it?).

You can visit the TSE3 website at TSE3.sourceforge.net and the Anthem site at anthem.sourceforge.net.

    [1] Remember this is old technology and not fully representative of this cutting-edge project.

    [2] Don't get me wrong, I'm not trying to slag off any of these programs. But I firmly believe that in these enlightened times we can do a lot better!

tse3-0.3.1/doc/src/Commands.html.in0000644000175700001440000001003410271145632013704 00000000000000 TSE3 Commands

TSE3 Commands

The TSE3::Cmd namespace contains classes that implement a GoF Command pattern. You can use this in applications that use the TSE3 library to provide a command history with undo/redo facilities.

However, in order to use these classes there are a number of provisos that you must take care to note:

  • The commands
    There is a TSE3::Cmd class for every useful operation on the Song data structure and it's subcomponents. There are not commands for alterations to the state of objects like Transport and Metronome since they are system wide settings, not Song alterations.
  • The CommandHistory class
    The CommandHistory class holds the list of commands. For any operation, you create a Command object for it (with new), call execute() on the command, and then add it to the CommandHistory class. For now on you can call undo and redo on the CommandHistory to undo/redo the history of operations. Remember that your application will be kept up to date with the resulting changes to the Song through the Notifier interface mechanism.
  • Multiple Songs
    If you support multiple Song objects in your application you can either use one CommandHistory class for all operations, or create a separate CommandHistory for each Song. It is this latter operation that is the most logical, and the TSE3_Application::Application class contains support for it.
  • If you use commands, don't directly use the TSE3 API
    If you are using TSE3 Commands then any change to a Song or it's subcomponents must be done through commands. Otherwise, if the state of the Song changes between a command being executed and undone unpredicatable results may occur.
  • Writing your own commands
    If you implement your own commands that are creational or destrutional (if that is a word ;-) you must take care. If you, for example, create a new Part in execute you should not delete it in undo and then create a different Part in a subsequent call to execute. Why? If any subsequent commands act on that Part and take a Part* parameter to identify it, by deleting the Part and creating a new different one on a 'redo' you will cause the later command to be invalid.
    Creational patterns should create objects in the constructors, put them into the Song in undo, and delete the object in the destructor only if the object is deleted after having been undone.
    Destructional commands should merely remove the object in execute and put the same object back in in undo. The object may only be deleted in the destructor if the command has not been undone.

However, despite these provisos and the extra care that you must take when using the command pattern in your application, the benefits are great: the undo/redo facility is a really user-friendly useful facility that sets a good application appart from a great one. tse3-0.3.1/doc/src/Version.html.in0000644000175700001440000002603210271145632013575 00000000000000 TSE3 version history

About TSE3 version numbers

The TSE3 library version number describes the release you are using. It is split into three components, a.b.c. For each minor release that is API compatible with the previous release, the c value increases. For any modification to a public API that may require clients to modify their code the b value is incremented. The a value is currently always zero.

TSE3 version history

This is the TSE3 library version:

This file lists the major changes between releases of TSE3. There is another much more detailed (perhaps too detailed) history file which is found in the TSE3 source package (in the file doc/History).


version 0.2.7 (2003-03-07)

  • tse3play doesn't need to open MIDI devices to just convert files
  • New MIDI recording example code
  • gcc 3.2 compatibility

version 0.2.6 (2002-10-30)

  • tse3play picks the playback port much more cleverly
  • Doxygen documentation supported
  • Bugfixes for tse3play

version 0.2.5 (2002-08-22)

  • Compiles under gcc 3.2

version 0.2.4 (2002-07-28)

  • API extensions
  • Author contact details update

version 0.2.2 (2002-05-11)

  • Essential build fixes
  • Other minor bugfixes

version 0.2.1 (2002-05-08)

  • Alsa 0.9 fixes
  • Builds under latest auto-tools
  • More documentation for command classes

Version 0.2.0 (2002-04-29)

  • Major enhancement: A new MidiScheduler framework that is more extensible, robust, and easier to use. The public API is mostly unchanged, but implementation is far easier.
  • New "magic" port/channel numbers for "all ports" "no port" etc.
  • Improved (and fixed) MidiEcho.
  • More command classes and utilities.
  • Panic objects now have a port value.

version 0.1.3 (2002-03-28)

  • alsa 0.9.x support
  • build support for more linux distributions
  • win32 platform support.
  • error exceptions api extended.
  • more example code.

Version 0.1.2 (2001-11-28)

  • MidiEvent bug fixing
  • Improved instrument file support
  • More example code and documentation
  • Imporved MidiFileExport API
  • Introduction of XML file writing
    (This is a prerelease, the files cannot be read yet)

Version 0.1.1 (2001-07-24)

  • Builds cleanly under gcc 3.0

Version 0.1.0 (2001-07-10)

  • Officially moved to beta status
  • More complete instrument file support
  • Various bug fixes

Version 0.0.25 (2001-05-16)

  • Added ArtsMidiScheduler
  • Alsa code compiles cleanly on a lot more platforms.
  • tse3play can now play legacy TSE2 files

Version 0.0.24 (2001-03-30)

  • Sysex handling has been implemented fully.
  • Panic class now does GM/GS/XG MIDI resets.
  • Bugfixes.

Version 0.0.23 (2001-03-23)

  • Alsa code greatly improved, with workarounds for Alsa 0.5.x bugs.
  • Tidy up of the OSS interface code.
  • Tracks now have a DisplayParams object.
  • Playback bug fixes.
  • Nicer set of PresetColours.
  • FileRecogniser handles error conditions better.
  • Forwarding events for Track, Part and Phrase subcomponent events.
  • Improved StreamMidiScheduler.

Version 0.0.22 (2001-02-22)

  • First fully operational AlsaMidiScheduler.
  • Slight rearchitecture of Phrase management - PhraseEdit now creates you a Phrase directly into a PhraseList. This will prevent a common cause of user errors - creating Phrases but not putting them in the PhraseList. This leads to an unfortunate API change, but it's worthwhile. Parts will no longer accept Phrases that aren't parented.
  • Listener classes can now safely call Notifier::attach and Notifier::detach in event handlers.
  • Added PhraseEdit::timeShift() and used this in the Record object.
  • PhraseEdit::tidy fixing - last event recorded is no longer truncated.
  • Bug fixes.
  • More API documentation.

Version 0.0.21 (2001-02-16)

  • First ALSA support.
  • All listener interfaces in separate headers in "listen" directory.
  • Documentation gets built and installed with the library now.
  • TSE3MDL file format modification.
  • MIDI file export bug fixed.

Version 0.0.20 (2001-01-24)

  • New TrackSelection class, an analog of the PartSelection. These two can work together to ensure there is only ever one object selected.
  • PhraseEdit vastly improved for use with GUI Phrase editors. Can now manage the selection of events much more intelligently and maintains a 'modified' status flag.
  • All separate tse3 libraries have been rolled together into one libtse3 library for ease of use.
  • Added buffer flushing to the CommandHistory.
  • Extended Record class that is safer when multiple instances exist.
  • PartDisplay fix for case of empty Part.

Version 0.0.19 (2001-01-16)

  • More information saved in choices files
  • Transport class method playable() added
  • Documentation building fixed

Version 0.0.18 (2001-01-09)

  • More Command classes
  • Greatly improved documentation
  • Destination and Instrument system used by Application support (can be saved in configuration files)
  • General bugfixes

Version 0.0.17 (2000-11-21)

This is a minor release which includes a missing file, Progress.h.


Version 0.0.16 (2000-11-20)

This sees a lot of work involving application support. Many issues have been addressed following application development from TSE3 users.

  • TSE3 now reports the progress of slow operations so an application can display a progress dialogue.
  • DisplayParams now has a range of PresetColours (for things such as intro/verse/bridge etc).
  • Improved Destination class, manages Instrument definitons
  • Improved MidiScheduler interface
  • Util::Modified utility.

Version 0.0.14 (2000-10-17)

This is a small delta release that removes some Alsa stuff since at the moment it is not fully operational. There have also been some documentation improvements.


Version 0.0.13 (2000-10-16)

  • Added multiple-thread support to TSE3 (see tse3/Mutex.h)
  • Beginnings of support for the ALSA library
  • New UnixMidiSchedulerFactory that chooses either OSS or ALSA depending on build flags and the system state
  • Greatly improved build configurations (select OSS, Alsa, Mutex)
  • Application class now how has a Destination object
  • More Command classes
  • Better docs
  • Bug fixes (copying Parts broken)

Version 0.0.12 (2000-09-25)

  • A much improved Notifier class. TSE3 callbacks now have different methods for different events, with arbitrary numbers of parameters. This is a great improvement.
  • Work-arounds for gcc bugs which caused errors for some people compiling 0.0.11.
  • OSSMidiScheduler can now have multiple paths specified for patches directories, separated by colons. This allows TSE3 to support Red Hat and SuSE installations straight out of the box.
  • Improved documentation.

Version 0.0.11 (2000-09-12)

  • New CommandGroup command class that can logically group a number of commands for a single undo/redo operation.
  • New Phrase_Merge utility,
  • Improved file organisation and naming.
  • The removal of the RepeatTrack for a simpler to use left/rightrepeat marker system.
  • The Song implementation of the solo track more robust.
  • Removal of all the iterator classes from public API.

Version 0.0.9 (2000-08-29)

The 0.0.9 brings better structured API documentation; as well as the comprehensive reference, you can now browse one section per namespace. Also minor improvements to the implementation.

Version 0.0.8 (2000-08-16)

The 0.0.8 release sees a tidy up of some of the API. This means that some TSE3 bits have been renamed, and some files moved. In addition there are some new namespaces, and others have been renamed. In the run up to a stable 1.0 release these issues have been addressed. (The changes should not affect any current users since they are in some of the more advanced parts of the library.)

In addition there is more application support and command class implementation.


Version 0.0.6 (2000-07-18)

  • More reliable OSS driver
  • Enhanced application support facilities
  • Standardised internationalisable error handling
  • New Part insert actions
  • Improved documentation
  • Plus other API enhancements

Version 0.0.5 (2000-06-20)

  • Rew/ff whilst resting.
  • Better event timing.
  • More application support.

Version 0.0.1 to Version 0.0.4

See the verbose doc/History file, entries 2000-05-14 to 2000-06-98. These versions comprise very much the infancy of the version 3 TSE library. tse3-0.3.1/doc/src/About.html.in0000644000175700001440000000526410271145632013226 00000000000000 About the TSE3 library

About the TSE3 library

TSE3 is a portable open source 'sequencer engine' written in C++. It provides programmers with rich and powerful sequencing capabilities. It is a 'sequencer engine' becuase it provides the actual driving force elements of a sequencer but provides no form of user interface.

TSE3 is a mature library based on a lot of experience. Versions of TSE have been in use for a number of years. Whilst not providing the user interface, it provides a lot of assistance to a UI, attempting to provide as much functionality as possible in as generic a manner as possible.

TSE3 is a product of Trax Software, written by Pete Goodliffe.

Features

TSE3 provides a feature packed system, with a simple coherent API for application useage. It's advanced sequencer engine features include:

  • Powerful linear sequencer
  • Flexible object-oriented song structure
  • Handles import and export of standard MIDI files (both type 0 and type 1)
  • Provides own extensible song format (TSE3MDL)
  • Threading support for background playback
  • Playback with real time effects (remapping, quantise, velocity window clipping, repeat, offset etc)
  • GM/GS/XG support
  • Synchro start of playback
  • Powerful utilities for song manipulation: power quantise, arpeggiator etc.
  • Highly configurable metronome
  • MIDI echo facility
  • MIDI command filters
  • Imports Cakewalk instrument definition files
  • Flag points in timeline

Addtionally, TSE3 provides a level of application support. Common tasks that a sequencing application would implement that can be taken out of the user interface logic and placed at a higher level are provided within the TSE3 library. It therefore also offers the following facilities:

  • Command pattern for operations, providing a flexible undo/redo facility.
  • Support for an extensible choices file that can be saved on program start/stop or at any other time. Common TSE3 features are saved, and the application can attach further blocks of specific choices.

tse3play - the multi-format playback utility

The TSE3 library also comes with a sample application that uses the library, tse3play. This program is a command-line TSE3MDL and MIDI file player with a host of control features. tse3-0.3.1/doc/src/Feedback.html.in0000644000175700001440000000457010271145632013637 00000000000000 Feedback

Feedback

If you have any comments, questions or contributions to TSE3 please contact me at pete@cthree.org. Feedback is always welcomed.

Bug reports

If you are submitting a bug report then please provide as much information as possible. Including the form below would be very useful.

It would also be useful if you could include the output of running tse3play --verbose.

    --------------------------------------------------------------------------


    TSE3 bug report form
    ====================


    Name:                              [e.g. Pete Goodliffe]
    Date:                              [e.g. 2000-08-21]
    Email:                             [e.g. pete@cthree.org]
    Your experience:                   [e.g. experienced programmer in C/C++
                                             experienced unix user
                                             unix user
                                             new unix user]

    TSE3 version number:               [e.g. 0.0.7]
    OS name:                           [e.g. gnu linux]
    OS distribution:                   [e.g. Redhat]
    Run "uname -a":                    [e.g. Linux solomon 2.2.12-20 #1 ...]
    Do you use OSS or ALSA:            [e.g. Alsa 0.5.1]
    Compiler name and version:         [e.g. gcc 2.95.2]

    Description of bug:
    
    [e.g. When I run tse3play my computer explodes]

    How to (repeatably) reproduce the bug:

    [e.g. Perform a clean build and install, then type tse3play. The
    computer explodes.]

    Any other comments:

    [e.g. You owe me a new computer ;-) ]

    --------------------------------------------------------------------------
    
    Please attach the output of "tse3play --verbose" below:

    [ tse3play --verbose output ]

    --------------------------------------------------------------------------

    Please attach the output of "cat /dev/sndstat" and "cat /proc/asound/devices" below:

    [ output ]

    --------------------------------------------------------------------------

    
tse3-0.3.1/doc/src/Structure.html.in0000755000175700001440000001242510271145632014154 00000000000000 TSE3 library class structure

TSE3 library class structure

Since TSE3 is a powerful and full-featured library it contains a large number of classes. These can be split into several categories of class.

These categories of class reside in a number of namespaces. This is described below.

Song classes

These are the 'data' classes in the TSE3 library. They contain the representation of the Song information. The top level class is the Song class, it contains all the other objects. These include Track, Part and Phrase.

These are described here. They reside in the TSE3 namespace.

Transport classes

These are the classes that are used to playback and record songs. This includes the following objects:
Transport Deals with the playback/redord operations
MidiScheduler Provides access to the computer's MIDI ports
Metronome Provides a configurable metronome facility
MidiEcho A software MIDI thru port
MidiFilter Configurable filter for MIDI commands

They reside in the TSE3 namespace.

Instrument classes

These classes provide the ability to read Cakewalk .ins files. See here for more information. They reside in the TSE3::Ins namespace.

Utility classes

A number of 'utilities' are provided. These are operations that are performed on Songs which are more complex than the basic object member functions (such as merging two Phrases).

They reside in the TSE3::Util namespace.

Application classes

A selection of classes that provide support for application programemers. The idea is to take as much of the generic (non-UI) application functionality and place it in the TSE3 library.

They reside in the TSE3::App namespace.

Command classes

Classes that implement a 'command' design pattern. This provides application programmers with a command history facility that allows you to provide undo/redo of commands. See the Commands documentation for more details. The command classes reside in the TSE3::Cmd namespace.

Listener classes

Many of the TSE3 objects can raise events which can be caught by client code. This is described in the Notifier documentation.

Each listener interface class resides in the namespace that it's Notifier class resides in.


Other API issues

Using TSE3 objects

Note that some TSE3 classes are 'value' classes, for instance MidiClock and MidiCommand. It is fine to create these on the stack, copy them etc. They 'behave like the ints do'.

Others must be created on the heap (i.e. via new), like Part and Phrase. This is because you will pass them into another object which will assume responsibility and ownership of them. This 'owner' will take care of deleting the object when it is no longer needed. If you created this object on the stack then such a delete will cause Undefined Behaviour.

Value classes are documented as such to avoid confusion.

Using the Transport class

The Transport class is used to perform playback of Song data. To use it you must repeatedly call it's poll() method to allow it to perform MIDI input and output.

Perhaps you might like to call sleep() or some such function inbetween calls to poll() so as not to load your system unnecessarily.

MIDI note off commands

The TSE3 library has a convention for where MIDI note off commands are stored. The MidiEvent class that is used to store MIDI data has two entries, one for the MIDI event, and a second which is used to hold a MIDI note off command if the first is a note on.

The two MIDI commands must be paired together in the one MidiEvent for the TSE3 playback system to work properly.

This will only be an issue to you if you are creating MIDI data using the TSE3 library. See the PhraseEdit class for information on how to create MIDI data. tse3-0.3.1/doc/src/index.html.in0000644000175700001440000001251710271145632013262 00000000000000 TSE3 library documentation
TSE3
TSE3 library documentation

About TSE3 version
Getting started
API reference    (see here)
Further documentation
Trax Software
Admin

tse3-0.3.1/doc/src/Porting.html.in0000644000175700001440000000232310271145632013567 00000000000000 Porting TSE3

Porting TSE3

Porting TSE3 to another platform is a relatively simple task. Since it is written in modern, standards-compliant C++ the majority of the code will compile without problem.

Whilst TSE3 was developed on Linux, it has already been sucessfully compiled on BSD, RISC OS, and Windows operating systems.

The main porting concern is to implement the MidiScheduler class. This is the library interface to the underlying MIDI platform. You will need to consult the documentation for your platform for information on how to do this, you can see the existing implementations for inspiration.

If you are compiling on a unix-based platform then the build structure should work for you already - the autotools should cope OK. Other build environments may be required for different platforms.

See also

tse3-0.3.1/doc/src/Mutex.html.in0000644000175700001440000000271110271145632013250 00000000000000 Support for multiple threads in TSE3

Support for multiple threads in TSE3

The TSE3 library provides support for multi-threaded applications and guards its internal data structures against concurrent access by more than one thread.

It is possible to disable this support by configuring the code with the --without-mutex configure flag.

The threading support is implemented in the tse3/Mutex.h header file.

Even if the multi-threading support is enabled (as per default) the library will not be thread-safe unless you supply a platform-specific implementation of a mutex (which is a data structure used to prevent concurrent access to critical sections of code). You do this by providing a subclass of the TSE3::Impl::MutexImpl class and providing it to the TSE3 library (using the TSE3::Impl::Mutex class).

The KDOC documentation contains clear details on how to do this (look at the MutexImpl and Mutex class. If you have built the TSE3 documentation (see here for details) then the following links will take you directly to the documentation:

tse3-0.3.1/doc/src/tse3.gif.verbatim.in0000644000175700001440000000343310271145632014437 00000000000000GIF89a“œô™f3™™3Ì™3ÌÌ3™™fÌ™fÌÌfÌÿfÿÿf3™3f™ÌÌ™ÿÿ™ffÌf™Ì™™Ì™ÌÌÌÌÌÿÌÌÿÿÌÌÌÿÌÿÿÿÿÿigcigcigcigcigcigcigcigc!ù,Ž—ÿà%Ždižhª®¥Å ŒÅÎtmßxξHLº pHN|H°Èl:…^{Z¯Ø‘kÊí1²àpðØ-ÿÄè4Šl63–ê88Ú®{eò|skïŸõ€c~ƒ=p‡+l„ƒUˆŽ-R‹‹ˆ‘’˜†•rŠ˜ž…›qtŸ¤>”¡X|¥«^¨X—¬¬š®P±¶I_´D·¶º»Å¿¥ÃFÅÏÇ’ÊÊÍPÏÙÑ~ËÞÌ×:¼ÙϾÛeÉßÞáâääçSÓÕêàì7ãîÚðÓôêö8øòé;–nžÁeÿî Ìg.V°ƒ…%¬pá@Rü"BœHÑâÂOòúi”È‘EEÙÿz(²e½’*N¢¼X§ Ë–0MÎôX'äÈŸ9íDYæçÍyAcE©M£@“®Y:ÓW2¨G×I=!“ª»nXÃnåê%µ¬aIŽѵ쳴b×’hëÖ'Ú¬rçÖ]m^¶{ží;ò¯ºn 5|qÙÁw2vìUqÔ¿”©B¶ìÏp楜5NœosdœžI» -r´êl¦Y»~]ŒõÆÔ´kÛîŒ9wíÓPgÓŽ œ·Ü#|ï6H@ÂÚQ=rg]ONUI^/¹ g§)ÉO/1@„‰ßË„OLþtsvØûÔ¿=À‚Y›âzÜž°}ZéIZ}h9W t«€Ö_ÿXˆ~¬ìDß‚ 0€wË/fQx“…–ßð ±^iõQ3ÀŒŒø‚%F'…€HÊ)O@£ŒäLX^°xK./îØlhÕhL‰.ddëMbS;¾aĆO–ñ[56fYŽ5`é¥]ŽiG“)ôb¦ò„¸f4ovtÖ™D:râðŽž=<%@9€"àSŸ7äS§]ÕCe–!jƒ@–˜Q?ŠŽùÔ2’Ö`Q¥Ç°©Aƒº*AÄuJQ–¢õ‘¥?©:ÃNÛ\jÔ…¯†*€Q²²0Ô©˜øøM©ýÂR¬s.åyUE˜V¯+”Eʨw …‘ÿ°Õ@«‚[ÀvÁ(pÄ΄ɱwi›f]„ÜšW+Yf. ¤uK­b¸.Õí·Ï&Kš–Ø&é–¶½{mMÙêa£èš8ïi›à› ³¶¯¡ý"ë§oäH i6\‚oìz°K¤œ­¾´el²7õ²·Ç$€,²Æß¹×ÊÀ<È*k,ÞÊ:‹ 3͆sÐðŒ³H6»<2ÒC/ ÑÍõA±Ôý´¬Ð(¿63ÖÕ4íÕÑ]«Ö³Ôóq}qn_íM]d¯2Øôˆ­àËe“Ö6Ývw¢W»}P¸Cuœw`{ Þ÷LO8ßßð‡·Ü^ ÞáŒWï¶@¸´¸ÿG)˜Ã´%NÞ{"D0ÝØËu7„¯ —ì%,æ¤{¸€ƒÎ Îî'XP@ÝTQØàŸåcûQ )‚´µeçeaêe©•é4è¹ßŠ?÷K=_žù6,°Ìè3Þ.ý‹TyÏð8>î/ç;QŸ7–Ç  pIb_¶7û…ÍLÈ ZǨ‚L``ïFRYÄ~¿CƒâÖ }äè™ ÓÐ`#|Fâ²§™ô#„ ™ ÉõÂ4ÄÐV˜Ÿ.ð1³(߀ GŒnbÔèáD¶'ED,‡ŒÉ¢·ÈÅ.zñ‹` £ÇHÆÿ2šñH€×ÈÆ6ºñpŒ£çHÇ:ÚñŽxlcòÈÇ>úñ€ dÒXG4Àˆ<ä™4t!éÈD"RŒ<$$!àLâq‘t´€(GIJFB€”¢¬€)Q9J0’•på'9GXŽR§d¥,™K]¾–´œ#(íØJFª±•žT€'yyKc²” ¨€(wIÇ`†ršÎ¥5qÙLg¾1—Ôf‹iLRR “Îì¥%—ÉH8`”ìœã6åHNF>€•ˆ§{‰Êyòñ£Ìç'ljMg:@𤬀>ùÈOR @¥@íèO8ÖÓ™ ¸§6¹)Êu˜“ŽD(îøÐkÆÒ›lTÀE÷ÙM”²±—³$èI?šÒQ>€£p);@–Š+¤4)IR.4½Üä&ÑM’ò¦•i8iËŠÞ±¡¥ $@%zÔ7–tŽ›´*žÆò]Í#Y•ªT¦5–øªÅêÒºÚõ®k|€%¹×¾òõ¯~ ,`+ØÂö°†M,b ;tse3-0.3.1/doc/src/HOWTO.html.in0000755000175700001440000000733310271145632013056 00000000000000 TSE3 library HOWTO

TSE3 library HOWTO

This document provides simple descriptions of how to use the TSE3 API to perform common tasks.


Including library headers

To use the library you should have you compiler set to point to the appropriate include directory. TSE3 header files should be included with a line like:

    #include "tse3/Midi.h"
    

Note the tse3/ section. This will ensure that TSE3 header file names do not clash with other library paths.

Where you do not need to #include a header (for example, you do not inherit directly from a TSE3 class, just use pointers to it in your class' interface) you are urged to forward declare TSE3 classes rather than pull in the header file. For example:

    namespace TSE3
    {
        class Song;
        class Track;
    }
    

Load a Song

The TSE3 library can save and load standard MIDI files as well as song files in it's own filetype (TSE3MDL). There are benefits and drawbacks of both types. MIDI files are portable - practically any other sequencing/multimedia package will be able to interpret them. However, MIDI files are not expressive enough to describe TSE3's advanced Song structure and so use of the TSE3MDL format is recommended where possible.

  • TSE3MDL files
    Use the TSE3MDL object (in TSE3MDL.h). The KDOC documentation explains how to use it. Do not use the Serializable interface of the Song class directly, you will not create a complete TSE3MDL file.
  • Standard MIDI files
    Use the MidiFileImport object (in MidiFile.h). The KDOC documentation explains how to use it.
  • TSE2MDL files
    These are files as created by the older TSE version 2 library. You use the TSE2MDL class (in TSE2MDL.h) to import these files.

Save a Song

To save as TSE3MDL or standard MIDI file is as easy as loading.

  • TSE3MDL files
    Use the TSE3MDL object.
  • Standard MIDI files
    Use the MidiFileExport object (in MidiFile.h).

Play a Song

The Transport object (in tse3/Transport.h) is used to play a Song object (or in fact, any kind of object that implements the Playable interface). To use it you must also create a MidiScheduler object that knows how to play MIDI output on your computer. For example, Linux boxes with the Open Sound System will want to create an OSSMidiScheduler object using the OSSMidiSchedulerFactory class.

As well as a MidiScheduler you must also create a Metronome object. If simply playing back a file, you may wish to switch the metronome 'tick' off using the documented API.

Playing a Song is simply a matter of calling play on the Transport object. You can either poll the Transport object to find out when the playing has stopped, or implement the TransportListener interface to be told directly.

Any other questions?

If you have any other questions, ask the author!

(The tse3play program is a good example of how to use the library - you might find your answer there). tse3-0.3.1/doc/src/trax.gif.verbatim.in0000644000175700001440000000047710271145632014544 00000000000000GIF89a"„ÌÌ33ÿ33Ì3ffffÌffÿffff™™f™Ìf™™™™ÿ™™Ì™ÌÌÌÌÿÌÌÌÌÿÿÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,"¼ Ždižhª®ì´°(B NaÃK¤ï+\d!ŠD Èa¬ ¦caP Çög /’!R%ANë–8†­ã²h<´Ž‹·Pn7õ¸}lPo"€…Š‹Œ-i.’'L8my›$#=UT(:QUuªsd#|'®uS#·Ÿ,·LI˜´o+ÀTÆ"Tqs8£*L#¹³3Í£x“u)‘˜—‘—“‡’”èéJ!;tse3-0.3.1/doc/src/KDOC.html.in0000644000175700001440000000454310271145632012673 00000000000000 TSE3 library API reference

TSE3 library API reference

The TSE3 library provides extensive on-line documentation which is extracted by the KDOC or the Doxygen tool. The format of each tool's output is different; you may prefer one to the other. The information contained in each should be identical. Doxygen output may generate inheritance hierarchy diagrams (depending on your particular installation) which you may find more useful.

You must build the TSE3 documentation to access this information.

Building Doxygen documentation

If you have Doxygen installed, you can enter the doc directory, and type make tse3-doxygen.

Building KDOC documentation

You do this by entering the doc directory and typing make tse3-kdoc. This builds the main TSE3 API reference which details every single class in TSE3. You can also build a reference for each namespace individually, type make tse3-kdoc-libs.

The easy way is to do a make tse3-kdoc-all which builds both.

You will need to have a copy of KDOC installed that correctly handles namespaces (2.0a35 or later works).

The comprehensive KDOC API reference provides the following information.

The individual namespace references are:

You can remove all of the documentation using make tse3-kdoc-clean. tse3-0.3.1/doc/src/Trax.html.in0000644000175700001440000000240310271145632013062 00000000000000 Author / About Trax Software

About Trax Software

    TSE3 is a Trax Software product.

    Trax Software is a UK based software house.

      Trax Software logo

TSE3 authors

Dedication

    To my wife, Bryony.

    In loving memory of my daughter Jessica.

Thanks

  • Software
    • Takashi Iwai of SuSE for Alsa 0.9.x MidiScheduler adaption.
    • Joerg Anders (much feedback)
    • Stefan Westerfeld (aRts MidiScheduler code)
  • Hardware
    • Rik Hemsley
    • Chris Reed
tse3-0.3.1/doc/src/htmlize.pl0000644000175700001440000000341010271145632012661 00000000000000############################################################################### # htmlize.perl # Pete Goodliffe # simple file munging to create the full set of TSE3 library documentation ############################################################################### $version=@ARGV[0]; while ($line = ) { if (index($line,"") != -1) { print $version } elsif (index($line,"") != -1) { print <<"EOB";
 TSE3 documentation Version $version Index API  Version  Structure 
EOB } elsif (index($line,"") != -1) { print <<"EOB";
 © Pete Goodliffe, 2001-2003 Copyright Psalm 150 
EOB } else { print $line; } } tse3-0.3.1/doc/src/Copyright.html.in0000644000175700001440000000237610271145632014125 00000000000000 TSE3 library copyright details

TSE3 library copyright details

TSE3 is released under the terms of the GNU General Public License. See the COPYING file included in the source package, or visit the GNU website for more information.

TSE3 is copyright © Pete Goodliffe 2000-2003.

You may freely use TSE3 under the license terms. In addition to this, I request that if you use the library you:

  1. Tell me (so I can keep a track of how much it is being used, and learn how I can improve it)
  2. Display a notice in the program (perhaps the Help->About dialogue) and also in the documentation crediting use of the library. Something like 'Uses TSE3 technology' is sufficient. You should provide access to the version strings in the TSE3.h file in the program. I also have a small logo which you may wish to use.

If you are interested in licensing TSE3 under a different conditions, then contact the author. tse3-0.3.1/doc/src/Whitepaper.html.in0000644000175700001440000001003610271145632014255 00000000000000 TSE3 Whitepaper

TSE3 Sequencer Engine

P r o d u c t   w h i t e p a p e r

TSE3 is a next generation sequencer core. Based on proven technology and implemented in a modern standard C++ library, TSE3 provides base MIDI sequencing functionality for a range of applications.

Key features

  • Powerful linear sequencer
  • Cross platform architecture
  • Strong application integration
  • Simple and coherent C++ API
  • Stable code base

Example applications

  • MIDI playback utility
  • Embedded web-based MIDI player
  • Full featured sequencer application

Availablity

SPECIFICATIONS

Version
Language C++
Platforms
  • Linux, and other Unixes
  • Acorn RISC OS
  • Win32 under development
  • Facilities The following is a non-exclusive list
    • Songs editable whilst playing
    • Command classes
      (full undo/redo capabilities)
    • Cakewalk intrument file support
      (selects voices etc by name)
    • Standard MIDI file import/export
      (type 0 and type 1)
    • Thread-aware
    • GM/XG/GS support
    • Powerful sequencer features such as syncro start, punch-in recording, real time effects
    • Command-line playback/file conversion tool
    Documentation Full API documentation plus overview documents and example code
    Interfaces
  • High level C++ API, with additional APIs for extensive application support
  • Low level MIDI hardware access APIs for easy porting to new platforms
  • Licence GPL for non commercial use
    Contact Trax Software for commercial use
    Metrics 49000 Lines of code
    177 Classes
    Typically 1.3M shared library
    tse3-0.3.1/doc/src/pete.jpeg.verbatim.in0000644000175700001440000000174610271145632014703 00000000000000ÿØÿàJFIFHHÿþCreated with The GIMPÿÛC (B+(%%(Q:=0B`Ued_U][jx™jqs[]…µ†ž£«­«g€¼Éº¦Ç™¨«¤ÿÛC(#(N++N¤n]n¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ÿÀ<P"ÿÄÿÄ.!1AQa"qB‘¡#2Cr±ðÿÄÿÄ!"1AaÿÚ ?Ç\hê)€>D¯E€&\dÑ'Žz™ù”*Ðg'SO$šrN‚ìzUÜIý€ùBýH†œ:ÄÉ©;(NØqÊò"ŸÊ¿¤,Ùñ!ç"ƒépU÷‹Äí„›>5Û{Gé#ùK¹kÄf¿9 1ïÚXðqx-ÙpÃ°ÆæŒzjÄ‘ã‰IåAl+°£Þ5E6èL¾}¦–‘$+á¸ñdȪ۪ìxÿª5>º]oÌB ‚(]Ô—ìn{liÁʯ‘r?b¹d¢Ñ¦ŠØqÜ\J£pùH@Еb4eÌ‘^ŒÑ§]¸Ó;âUÜxwûÍ:Q…¨ ®€øQòQ¤ª¶/ÒìäžÚË©.ÜÙ¾y”Šcc¿$Æëpí}Àp`c]¸÷Jòñ‚¨­äuíÏɳÄ.Hõö“9ßw4ÆiøFŠäe?WÓ‰_ ƒ ¦ñÜEbR7~‚W§¦Ö¨Ì“È’Ñ×AéÝŠ‚ÆÉæêV¤'U×Ó¯´%b­G¹û.¶¬iZæ-«u ÷Œfµ“38þ—?Ý ØQíVE8NÕ¶{HU]”ëëæb@¤¿Nbñ*#ì-~Iõ1üBÏHîÖ¾"³‡ÄÜlù"VêÊ»ªë¿´›VÕ‡‘ ›tCÑ9U¿™8ò'tÚ‚§³^b•Ë´t`dú3!^7w:¯@6W!`<ø>#ub ØOWÑûŸ¦vWd»P,.ः"úº9MÇAË×#÷žÝ¸`6#ÎÀ=‡qQÒ@Àe>_À’l›Šü5«zžŒ®„ìزÉËFkj2i©]I¿ÜæFÇ4:–jøÇÐç‰ò“VŸaÿÙtse3-0.3.1/doc/src/Error.html.in0000644000175700001440000000724210271145632013243 00000000000000 TSE3 error handling

    TSE3 error handling

    C++ exceptions

    The TSE3 library uses exceptions to indicate unrecoverable errors. The member functions which raise errors are clearly indicatated in the documentation.

    For this reason it is important that you write your application with exception handlers (at the very least, enclose your main function in a try/catch block, otherwise any errors will lead to a segfault.

    Every different TSE3 error is derived from a common base class, Error. This class in turn derives from the standard library exception class exception. It is up to you at what level you catch any exception (i.e. specific subclass like PhraseListError, all TSE3 errors with Error or all library exceptions with exception).

    The suggested format for catching errors is as shown below:

        try
        {
            // perform TSE3 activity that might throw an exception
            phraseList.insert(newPhrase);
        }
        catch (const Error &e)
        {
            // do some error handling
            cerr << "An error occured of type " << e.reason << endl;
            exit(1);
        }
        

    That is, catch by const reference. Of course, you will probably want to catch a more specific exception type; in the above example a PhraseListError.

    Error reason codes

    The base Error class includes a reason code parameter. You may therefore distinguish the cause of the error in two ways, by type of exception caught or by inspecting the reason code. Reason codes are defined by the ErrorCode enum type.

    The reason for this (seemingly redundant) reason code is simple: when writing an application it is easier to work out which internationalised error string to show to the user on reciept of an exception by indexing into a table by reason code, rather that trying to convert an exception type into a string.

    The TSE3 library provides a set of standard English string representations of each ErrorCode value.

    General information

    The error class definitions are located in the file tse3/Error.h. The other TSE3 header files do not include this directly, so if you need to handle TSE3 exceptions you will need to #include this in your own code.

    Note that some erroneous operations, like attempting to remove a Phrase from the PhraseList which was never inserted, result in no error being raised and the method returning silently. Such occurences are clearly marked in the documentation.

    Memory allocation errors

    Since TSE3 error handling is based on the C++ exception mechanism, memory allocation failure is also expected to raise an exception (std::bad_alloc). For this reason, you will not see code that checks the return value of new against the value zero in the TSE3 source.

    In fact, TSE3 does not even attempt to catch a bad_alloc since if there is a memory leak, there really is no useful work that the library can perform - it is probably too late to gracefully degrade. It is up to the library user to catch any occurance of bad_alloc and warn the application user, if possible. tse3-0.3.1/doc/History0000644000175700001440000021544310271145632011460 00000000000000=============================================================================== TSE3 History File =============================================================================== This history file documents the entire development of the TSE3 library. It includes every painstaking detail and so is ridiculously boring to read. It's only really here for my own benefit, and I haven't actually decided what that is yet. ------------------------------------------------------------------------------- Contents ------------------------------------------------------------------------------- - Daily development history - TODO list ------------------------------------------------------------------------------- Daily development history ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- May 1999 14 Decided this was a good way to learn decent C++ and the STL, so embarked on a rewrite of the proven TSE v2.00. I'll build this under Unix, and document it well. ATM I'm going to use KDOC because it looks enough like javadoc, and I can get it to work. 17 Made a ridiculous build structure somewhat like the the Java one, with separate build and src trees to try to keep things neat. 20 Put in the Notifier/Listener framework taking ideas from Java. The funny thing is that it flipping well works! 24 Over the weekend extended how I think playback will work. Quite different from TSE. I now have a Playable interface that everyhing implements: from MidiParams right up to Song. The Transport class just reads MIDI events from Song and schedules them. The implementation of this means that each object can cache it's next event which saves reevaluating them as much as in TSE2 (I think). Made this even neater by adding meta events to the MidiEvent class so that tempo and timesig chages can filter through this system too. The only thing that won't fit into this framework now is audio. Added the Tempo and TimeSigTracks. Added NoteNoConversion class and wished that I didn't have to use stdio features. 25 Added the Metronome class, and made it return values through the Playable interface. I toyed with making the TimeSigTrack responsible for producing the metronome, after all it knows what the time sig is, but decided against it since it doesn't know what the playing status is. Also even if there were no more MIDI events in the Song it would still return stuff, so Song could never return false to consume which would be a shame: as it stands an auto stop facility should be fairly easy... First stab at some of the Transport functionality including drafting a version of the playback/scheduling loop. Started to include the Part. In my quest to make everything as general as possible to beat TSE2 for sheer coolness, added the MidiEventFilter class, and the SimpleMidiEventFilter. 26 Got the Part class doing the Playable interface properly. It returns any MidiParameters first, and then steps through the Phrase. Marvellous. Work finishing off the PhraseList. Added the PhraseListener. Fixed some rubbishness in my Notifier design. Then came accross a big trip up in the notifier design: what if you have one class inheriting from a notifing class that want to add it's own notification. The use of Notifier get disgusting. 27 Got Tracks and Songs implementing the Playable interface. Sorted! Changed the Notifier design *again*. This time removed the templates altogether. Now we only have a basic type of Listener and Notifier. There is an integer code for the different types of event which means that you have to work out what sort of Notifier just send you an updated() and then switch on the event code. Not nice, but it scales a little better. 28 Added a simple version of the FileOperations class in order to load a demo song so I have data to play with. ------------------------------------------------------------------------------- June 1 Got the Playable interfaces working better for Track and Part. Put it into the EventTrack and then Tempo and TimeSig Tracks. 2 Made the PlayableIterators more robust by handling the deleting of their Playable objects. I'm not entirely sure how to test that code yet. 3 Element-14 is sold to Pace. Marvellous. Maybe work will slow down on TSE3 now ;-) 7 Got the saving mechanism working using a Saveable interface. Created a new 'TSE3MDL' which is a lot more verbose than TSEMDL, but who cares? 8 Implemented loading of TSE3MDL files. 9 Added TSE3MDL file decsripton document. It doesn't really tell you all that much, but it kept me occupied. Added Song::replacePhrase. Everything that was in SongUtilities in TSE2 belongs in appropriate classes in TSE3. If MidiParams is going to implement forceNone, then it has to be a MidiEventFilter. 10 Oo look, there's an io manipulator called ws. Nice. There's also a strstream class. I can get rid of stuff. Better. Had a first stab at the PhraseEdit::tidy method. It will probably be a while until I can test it. Fixed a core dumping bug where the MetronomeIterator couldn't cope properly with the Metronome being deleted. Started thinking about a TSE3 command design pattern implementation. 11 Got the Commands working with the CommandHistory. Added the PhraseUtilities class and implemented add/subtract. 21 Put a hook into the MidiScheduler to handle MIDI remote control. Added the Panic class drawing the information from TSE2. Started implementing the PanicIterator class. 22 Autostop flag in Transport class (it always did autostop, it's just now configurable!) FileOperations.cpp wasn't using the istrstream class. Does now. Added saving and loadng to the Panic class. Implemented everything that doesn't require sysex messages. Not sure how to do those yet. Added a RepeatTrack to replace the left/right markers. Made the SongIterator generate these, and the Transport act on them. Scheduler had to implement moveTo, and Transport react to move updates from the Scheduler. Fixed various bugs on the way. 25 Spent some time looking for a segmentation fault. Didn't find the cause. D'oh! However, a few minor things fixed, TrackIterators detach themselves from Tracks etc. 28 Added a status flag to Repeat events. *** UNTESTED *** 30 Added the MidiFileImport class with code taken from TSE2 MidiImport. ------------------------------------------------------------------------------- July 1 Still investigating that segmentation fault. When a Track is deleted a deleted callnack is being sent that is for a deleted object and so the program crashes. 2 Found out why the segmentation fault occurs. The MidiParamsIterator didn't have a dtr that detached it from the object. So when the Track was deleted, and it's MidiParams object a callback to the non existent iterator caused a crash. Fixed now. 5 Made the TempOTrack and the TimeSigTrack attach themselves to their appropriate EventTrack. Put some notify()s in the EventTrack class. Added copy constructors where relevant: some are just inline empty and private. The Part has a decent copy constructor that attaches the new Part to any used Phrase. ------------------------------------------------------------------------------- July 19 Added the MidiSchedulerFactory class and converted the meat of MidiScheduler to a StreamMidiScheduler. 20 Added a riscos (hypothetical) and linux MidiSchedulers and factories. Added a NullMidiScheduler for when things go badly. Added a Makefile.common that should do much of the mundane makefile stuff. ------------------------------------------------------------------------------- August 3 Started trying to write a Cakewalk .ins file parser in a moment of boredom. I've done it already for Anthem but wanted to do it properly - I even found a document that sort of describes them rather than try to work it out myself. I'm using a state machine style parser. ...23 Got the parser working. It loads the whole file and allows you to select an Instrument from the hierarchy. Realised this was far too heavy weight - we only need to create a few of the many objects created for the whole of a file like Yamaha.ins so in my clean up phase I decided to work the parser into the Anthem form - only get from the file what we need to. 24 Finished off this work. The Instrument parser is now complete - it can save .ins files as well as create them. 25 Fixed STL list bug in new Instrument code. 26 Started work on the MidiFileExport class. Couldn't play back things trhough Playable interfaces. It's down to an error in some load methods that don't test string::compare(..) == 0. Twit. next discovered bug: the priority_queue in Transport that I've copied into MidiFileExport::writeMTrk_outputLoop is the wrong way up. 31 Finished off MidiExport for type 0 files. It works nicely. Implemented the type 1 format. Works. Good. Just need to slot in the code that actually saves tempo/timesig events and it should be done... ------------------------------------------------------------------------------- September 1 Finally got the MidiExpoty working well. Not bad. The output seems to be correct which is good - it proves that MidiExport works, but also that my output iterator system works too. Marvellous! Added a compact facility to shorten the file size. Removed old code from MidiImport constructor. 7 Finally I have managed to get the soundcard spitting out MIDI commands! This is a big step forward (this is using the AWE32 that Rik has donated to the cause.) 14 First time that I've got Linux to spit some MIDI output! I've got song.tse3mdl playing (somewhat stutteringly, but it some form of output). Hurrah! My big problem is returning the current clock time - I can't see a way of polling /dev/sequencer to get it - and I can't see any other MIDI programs that do it nicely (kooBase, for example, just seems to return the time of the last scheduled note. Yuck). 23 PhraseEdit.insert() is ridiculously slow. Hurray for the STL (and probably my dodgy use of it). I've tried to add an insert position cache to the class. 24 Tidied up the code so that it compiles quietly under GCC with -Wall. 27 Added the MidiMapper object. 29 Gave TSE3Play the ability to produce snappy VU bar textual output. Cool! ------------------------------------------------------------------------------- October 6 Moved public data members out of Song. 7 Extended FileOperations_TSE2 (which was FileOperations_2) to be able to load all of the TSE2MDL filetype. Made the FileRecogniser know about old TSEMDL files. Made FileOperations_TSE2 into TSE2FileImport and gave it a MidiFileImport-like interface. Moved public data members out of Track and Part. ------------------------------------------------------------------------------- November 9 Moved the build tree into an autoconf/automake system. This will make it easier for other people to build and install the libraries. I still haven't figured out how to do shared libraries in this system; I don't appear to libtool (which appears to be favoured) but do have ranlib. I'll work it out. This work involved moving the directories around a bit. Now the commands are in TSE3/commands and the different platforms' schedulers are in TSE/platform. I think that overall this is more sensible. 10 Fixed the MidiMapper - the defaults weren't being set in the constructor so everything was just getting mapped to (0,0). Put tempo handling into the Transport meta event handler. 11 Moved the inline stuff from CommandHistory.h into .cpp and forced setLimit to shorten the lists if necessary. Also added an 'infinity' choice. 17 Added the application subdirextory of TSE3 with application support classes. First ones in are the Application class and the ChoicesManager, ChoiceHandler and implementations for Metronome and Application. This is a neat way of trying to pull application logic out of the GUI front end. Interestingly you can't create a ostream for "~/.anthem", you can for "/home/pete/.anthem". I don't like that... 18 ChoiceHandler for Transport class. 19 Moved some of the stuff in the Saveable base class out into helper functions so that I could more easily implement the choices saving - the ChoiceHandler classes don't beong inherting from Saveable since they don't care about the current Song. Put in the framework that allows the choices file chunks to be regognised. Just need to actually prod the settings now. 23 When implementing load for the ChoiceHandlers is became aparent that I'm continually writing block parsing code. This checks for the closing }, sometimes checks for sub-blocks (when it always should) and parses data lines. Created the FileBlockParser utility class to do the spade work for me. This involved a lot of moving things around. Redesigned the layout of te FileOperations classes to suit it better. The interface is now a lot more logical. There is one entry point for file operations: the TSE3MDL class. Nice. I created the Serializable base class to replace the Saveable. A little more than just a name change, I'm trying to work out how to remove the extra data (e.g. song pointer) that's passed around the load calls - when loading choices there isn't a Song reference so it's redundant. I'm trying to generalise the Serializeable mechanism as much as possible. Created lots of nice little helper FileItemParsers that are generic so that you don't have to do too much tedious typing. 24 Finished off the new FileOperations system. It works pretty nicely all things considered. Or so it would seem. It's only really strange data lines that you have to write explicit parsing code for now, and even then you get given all the standard stuff (sub-blocks, closing brace). In order to make the system better I added a catch-all FileItemParser to the FileBlockParser. Next step is to completely remove the Saveable interface and make all classes use Serializable. Big job. 26 Finally I beilieve that I have finished adding the new Serializable interface to the whole TSE3 Song hierarchy in place of the Saveable. Various twiddles to bits such as the ChoicesManager::ChoicesChanceHandler and so on, and some code reformatting, plus removing some methods which were inline when they really shouldn't be (must have been when I started and we too into Java ;-) 27 Added a midi, gm, gs, and xg reset facility to tse3play. 28 Fiddled the MidiEvent structure. I was never really happy using the two Event because e.event.data.data1 is messier than e.data.data1 which is what you'd write now. It was always a 'special' kind of Event so now it's an easier to use special type of Event. Added --oss and --stream to tse3play. 30 Added a Win32 platform. It's not finished, but I was reading the docs. ------------------------------------------------------------------------------- December 1 Took out that nasty global stuff from OSS.h and made it a little neater. The OSS API really does suck. 4 At SYMS - added a lot of new stuff for soundcard support, AWE/GUS/FM stuff. Added a VoicesManager - this code is based on the playmidi and kooBase sources since the OSS documentation is sadly lacking. It's a real shame, really - the API itself sucks, so working it out from (oddly formatted) code and not documentation is a pain. Added a start facility to tse3play so you can play from a given position. 13 (On a plane over the US ;-) I've been working on FM support in the OSSMidiScheduler (I've mainly been seeing how kooBase does it). The code is looking a bit complex now - I'll have to sort that out. The patches aren't perfect yet, but I get noise out. Time to sleep... 17 During the Western Carble Show I've rejigged the OSSMidiScheduler class heirarchy. I was incorporating all the different types of OSS device into the one OSSMidiScheduler class since they have to share the nasty OSS API macros. This system used a pointer to member jump table for each OSS device available. This design smells to much like virtual function calls for comfort the only reason they weren't being the need to share the data OSS buffer. My alteration to this is to really make each driver a separate class and to share the data using references. This is almost certainly the Right Way to do it. It kept me occupied, anyway. ------------------------------------------------------------------------------- January 2000 17 Whilst waiting for the Pace exec to do anything interesting, played about a bit with the command objects. Added a new VariableSetCommand to save all the hard work with Song_SetTitle, Song_SetAuthor etc. Added new Song commands for all the other things you can do with Songs. Added Song::searchForPhrase to make undoing replacePhrase work. 21 Changed the ugly src/TSE3 to tse3. ------------------------------------------------------------------------------- February 7 Fixes to the FileBlockParser, access to the amount of lookAhead in the Transport class and a usleep in tse3play which takes processor usage down from ~60% to very little. Harrah. 14 Altered the build process to use libtool and install properly. .. Working on the website to upload to wherever I find. 22 Added support for the solo track to the SongIterator. Added --solo-track to tse3play to test it. 24 Added a MidiEcho object (like TSE2). 25 First stab at reading from /dev/sequencer - success! If only OSS was documented... same old story. 28 Tidied up the recording stuff, fixed MidiEcho. Bugfixes here and there. Implemented Transport::ff and rew methods. Made the OSS scheduler take the OSS timing rate into account in timing calculations. Added channel and port filters to the SimpleEventFilter, plus a time scaling factor: it's anything but 'Simple' now. 29 Implemented the recording mute facility. It's not as nice as in TSE2. In the later you said 'record on channel 2'. In TSE3 you have to give the SimpleMidiEventFilter for the Track that's being recorded on, so that it can be muted. Euchy, but it works. ------------------------------------------------------------------------------- March 1 Wanted to sort out how to do the OSS immediate playback so that I can do the MIDI echo sucessfully. The OSS documentation sucks. As ever. The new PDF docs helpfully say (p70-1) there is an ioctl to do it. They don't tell you what it is. Poured our the driver source until I worked out what it is and how to use it. Say hello to SNDCTL_SEQ_OUTOFBAND. There appears to be massive delays between input and output, though. Hmm. Ha! Fixed the delay. I hadn't enclosed OSS:readInput in a loop, so it was getting called many times for a single event (i.e. read time, read status byte, read time, read data 1, read time, read data 2 and return an event). It works very nicely now, and OSS tech support has still not bothered to reply to me. Added --sleep switch to tse3play. Doesn't seem to make the vu bars update more responsively, though. 3 Added the -ansi flag to the build. Fixed some minor things. Giving egcs the -pedantic flag make it guff up on inline functions in the EventTrack template class. I think that it shouldn't. Shame. 8 Started on the KDE2 UI application. Serious problems: qt doesn't seem to coexist with the STL at all. Hmm. Also, the KDE libs use the -pedantic switch, so the EventTrack really screws up. Grr. 9 Changed the bracket matching to exdented style, since I've been meaning to do this for ages. Now my eyes hurt. Fixed the nasty -pedantic problem. The introduction of a 'typename' was what was needed. 13 The 'Rule of Three' (RO3) needed following properly in TSE3, so added a whole tonne of private copy constructors and operator= declarations. Added somei more docs to constructors here and there. 15 Fixed a really nasty timing bug in the OSS driver - if you say SEQ_WAIT_TIME with the same value as the last one, it actually waits for a bit more, which can skew playback royally. Added colour to the tse3play application. Cheesy. Also added a flush to the end of updateBars() which means that they redraw in real-time again now. 16 Altered some function9f names and made documentation about objects taking ownership clear - for example Track 'owns' inserted Parts, as does the PhraseList for Phrases, etc. 17 Created the tse3/adaptor directory and started working on the ListenerAdaptor framework. Created a SongListenerAdaptor. 18 A little work on the ListenerAdaptor idea. 20 Integrated the ListenerAdaptor class into TSE3 and made a SongListener. 21 Added a --mute-track flag to tse3play to help Joerg Anders diagnose dodgy AWE64 playback. Finished off the ListenerAdaptor work, and made the Song class use it. 22 Added all of the ListenerAdaptor classes. Laborious but necessary. 23 Added const to all the save methods. 25 (At the JaCC conference) incorporated an 'adaptive look ahead' calculation into the Transport class which works out the best lookAhead value according to the frequency that poll is called. Also added the ability to record the number of Transport break ups, and added a minimumLookAhead value to stop it being set to zero (frightening). Altered tse3play to show the current lookAhead value, and the number of break ups. Also fixed the bug which meant that some vu bars got stuck on the screen (the callback sets next[channe] to now[channel]. Got anal about const correctness and size_t. 26 Finished off the size_t fixes - I had to add a couple of static_casts to TrackIterator which is distasteful. Ho hum. Added lastClock to Playable and implemented it in each Playable class. 27 Fixed another const foible, and removed the \es from tse3play.cpp, replacing them with a escChar static const - that removes all those nasty warnings. (I wanted to remove them earlier, but couldn't find out what \e was!) Created a simple progress bar in tse3play so you can see how far through the Song you are. Altered the adaptive look ahead formula slightly so that it doesn't break up on my desktop machine (which is more heavily loaded than the laptop). Fixed AWE drums bug: hurrah for undocumented OSS! AWE_DRUM_CHANNELS can only set *one* channel, and you pass it (1< end (and v.v.) if the Part is in a Track. Also added a ctor that takes time parameters. ------------------------------------------------------------------------------- July 3 Added the PartDisplay application class to help handle the dual source of DisplayParams (in the Part and the Phrase). Added DisplayParams loading to the Phrase. 6 Added PhraseList::index. 7 Implemented Application::addSong and Application::history. I'm now actually using some of the command stuff which is nice. Made the Song info methods send a notification. Added notifications to the CommandHistory class so I can grey out buttons when there are no undo/redos left. 8 Added the Track_SetInfo command. 9 Finished the Track_SetInfo command. Added the Part_SetInfo command. 12 Added the Track_Snip command. Added Track::remove(size_t index). I hadn;t notice this up to now: the SimpleMidiEventFilter offset was being applied incorrectly - it should be subtracted, not added to times. This only showed up when redrawing the contents of Parts! Fixed some badly behaved uses of SEQ_BENDER in OSS.cpp, a bug found by Joerg Anders. 13 Fixed bug in PartSelection - didn't attach to Parts. Added some docs on the TSE3_Commands. Found a pretty difficult to spot bug: if a Listener gets an updated message and decided to detach from the Notifier (e.g. PartSelection when Part is unparented) then the Notifier's iterator is invalidated. This can cause nasty crashes. I don't like the solution, but it's to copy the Listener list and then iterator over this 'safe' copy. Euch. Finally succame to the tempation to create Notifier.cpp. 14 Added min and max Track index to PartSelection. Added the reparented stuff to the Track class so that it has the same good stuff as the Part class. 17 Fixed the PartSelection stuff which wasn't perfect. 18 0.0.6 release 19 Added a tse3-lib-local target to the top level Makefile, so it's easier to link to a non-installed library. I wish I could get the libs to build here straight out, but I can't see how to bully automake into it. I also discover that TSE3 only builds on my box - some autoconf weirdness. 26 Took out the Part::InsertAction and placed it into the utlities/Track.h file - it was making the API to clumsy, and the commands too hard to implement. The simple and sufficient API approach is better. Renamed Track::indexAtTime to just Track::index - it's more logical (the 'at time' bit is indicated by the Clock parameter, after all). 31 Moved the TSE3_* namespaces into the TSE3 namespace and renamed them. Maybe a gratutitous changes, but it's more logical for them to be contained, and it's easier to use if they have shorter names. ------------------------------------------------------------------------------- August 2 Move the App/Plt/Cmd/Util subdirs to app/plt/cmd/util, to be consistent with my file naming conventions. The StreamMidiScheduler TSE3 class had a dependancy on the util lib which sucks. The neat solution is to move the Stream and Null MidiSchedulers into the Util namespace/lib. Moved the concrete MidiSchedulers to a Plt namespace. Removed redundant "Commands" from the cmd/*Commands.* filenames. Did some source formatting and added some more docs. 16 Altered FileBlockParser::parse by simplifiying the code ("find" is your friend ;-). Finally moved the Instrument classes to somewhere more logical, a new Ins sub-namespace. 0.0.8 release 17 Added operator= and copy ctr to PartSelection and docs on how to use to avoid iterator invalidation. 21 Added the Destination utility class. 22 Added erase(int) to the EventTrack template for convenience. Also altered the insert method so you can't insert two events at the same time - when loading I was getting two timesigs at the same time, which mucked up my redraw code. (The code currently stands at 30692 lines and is 914k of source.) Added barBeatPulse to the TimeSigTrack. 29 Moved all that PartInsertAction stuff from util/Track.h to cmd/Part.h. 0.0.9 release 30 Added Phrase_Merge for Joerg and took all the other Phrase bobbins out of the silly class (that was a TSE2 hang-over). Some code tidying and alteration of foo++ in ++foo all over the place. In an attempt to decrease header dependancies and generally tidy up split FileOperations.* into Serializable.* and TSE3MDL.*. Turned TSE2Import to TSE2MDL and changed filename. I want to get any nasty lingering code-changing bobbins out of the way quickly, ensure that the entire library is consistent and correct and then move out of alpha ASAP. Moved search and replace methods from Song to Util namespace. Put Pimpls into Song, Track and Part. Split EventFilter.* into MidiEventFilter.* and SimpleMidiEventFilter.*. Loads of repercussions from these changes and other tidies. 31 More of the same. Goodness - the MidiCommandFilter was never used or compiled. Builds now. SimpleMidiEventFilter was always a really unweildy name. So converted it to MidiFilter. The base MidiEventFilter class is now just Filter. Nicer. ------------------------------------------------------------------------------- September 1 Release 0.0.10 (private) 5 Added the CommandGroup class. Added CommandHistory::undoCommand(size_t) and redoCommand(size_t) so I can have a menu of recent commands. 6 It seems as if the RepeatTrack was probably too grand an idea. You'd only really ever use a left/right marker like TSE2, so took out the RepeatTrack and put from/to/repeat into Song. Had to munge the SongIterator quite a bit. 7 Removed some cout diagnostics from App stuff. Alterered the way SongIterator implements the soloTrack - now sets commands to MidiCommand_Invalid rather than removing them completely. This means that auto stop still works as you'd expect (otherwise if you soloed to an empty Track the playback would stop). 11 Removed all the *Iterator classes from the public API, since they're all used via the PlayableIterator base class anyway. This makes the headers smaller, and the KDOC nicer ;-) 12 @bf in kdoc -> As it turns out, that doesn't work either. Sigh. 0.0.11 Release First bits of work at putting the new sexier Notifier framework in. It's really much nicer, and safer. libtse3.so.0.0.0 size before hand is 5044711 for the record. The stuff gets a little messy around EventTrack but that has alwasy been a notifier nightmare. Touched 20 files. 13 More conversion to the new Notifier framework - it's a lot of hard work. 14 Finally finished the conversion to the new Notifier framework. Seems to work really well. libtse3.so.0.0.0 is now 16522254. Erk. Stupid change because gcc < 2.93.0 is broken. The XxxImpl structs in Song.cpp, Part.cpp and Track.cpp should have members that default to public, as C++ specifies. gcc defaults them to private so the compile screws up. Duh. It wouldn't be too bad if the standard compiler versions for RedHat 6.2 and SuSE 7.0 (at least) are included in this. 15 Having been frightened by the huge template code bloat, implemented a much simpler Notifier framework. That's a real shame, but can't be helped. As it happens it's still much nicer than the original system (and more type safe) so it's still a win. A lot of conversion work (but not as much as before). KDOC bobbins: added @reimplemented in every conceivably unseful place. After these major alterations the size of libtse3.so.0.0.0 is 809919. Phew. Oh! No they're not - its still 16303602 bytes. Grr. 18 Over the weekend did some investigation into this dumb sizing. It turns out that it's all about link names. The 16m is due to use of the std::set data type in a template base class. If I turn it into list, it does down to about 8m and with vector lower than that. Sigh. The solution was to create a hacky void_list Impl class and cast all Notifier and Listener pointers to void* so store then in it, casting them back when they're needed (need to be careful when passing c_notifier_types that the recast type is correct ;-) So put back in all the good Event stuff that means listener functions can have any number of parameters. Things are nice again; good functionality and it only costs arounf 5749141 bytes. Put muldiv in the Impl namespace. 0.0.12 Pre-release 22 Added a path delimiter to the OSSMidiScheduler patches directories so you can have multiple search paths. This means I should be able to accomodate SuSE and Redhat users better... 0.0.12 Release 28 The Part copy ctor did evil things to the pimpl. Fixed. ------------------------------------------------------------------------------- October 2 Added the Mutex class and the related classes to provide TSE3 with thread-safety. Added a bit of extra water-tightness to the Notifier class by making void_list::attach return a boolean. 11 Put a Destination class into the Application class. 12 Massaged the Song_EraseTrack and Song_InsertTrack commands. Renamed Song_EraseTrack to Song_RemoveTrack for consistency. Added Track_RemovePart. Added Track::index(Part*p) for consistency (and because I needed it). 13 Added threading support to the main TSE3 library; using the Impl::CritSec class. 14 Added TSE3_WITHOUT_MUTEX #define to the Mutex class so I can disable the whole shown if needed. Added a check in configure.in for whether Mutex support is needed. 15 Started the UnixMidiSchedulerFactory, which can be used to create both OSS and Alsa schedulers. Work on autoconf malarky to determine whether OSS/ALSA support is either wanted, or possible. Largely guesswork to see how to do it! 16 Made the configure.in stuff /much/ nicer. Mmm. Also, used the TSE3_WITH_OSS macro in the plt/OSS.* files. Implemented the UnixMidiSchedulerFactory. Made tse3play use this, and updated the documentation. Added new Mutex and Build docs, plus some examples (ripped from my article). At home much more of the Alsa implementation. * Release 0.0.13 17 Jigged around with the docs somewhat, and relayed out this file for laughs. Several minor doc changes. Fixed the make "tse3-lib-local" target. src/tse3/Makefile.am still used an old libtse3oss for the test prog, which has now gone. D'oh. 18 Many people have complained that Alsa support won't work (when the configure file clearly says at the end to build --without-alsa. I guess that was being a bit hopeful. Hacked it out completely ATM. * Release 0.0.14 20 Added Instrument class management to the Destination class. 23 Gratuituous change of Track::song() and Part::track() names, both to parent() since it is much more descriptive. Fixed bugs in Instrument loading routines. 25 More error handling for save/load operations. 26 Changes to the MidiScheduler interface: added portReadable and portWriteable. Changed std::strings to const char *. Removed txByte and added txSysEx. Added event in MidiSchedulerListener for when the number of ports changes. * Release 0.0.15 27 Added the App::Modified object. 30 Hid MidiMapper data behind a pimpl and made it a MidiSchedulerListener. 31 Application class handles Songs being deleted. ------------------------------------------------------------------------------- November 3 Fixed bug in new MidiMapper - scheduler wasn't being stored. 7 Modified Part_Move so you can set the end and the start. 8 Added a whole load of new selection mechanisms to the PartSelection class (i.e. select all, invert etc). Also made a PartSelectionListener class. 9 Fixed Modified class if you initially specify no song. 10 Moved Modified into Util and altered Part_Move to it can also name itself "resize part". 13 Added the Progress class. Linked it to the Demidify utility, instead of the DemidifyProgress class. Linked this info the FileBlockParser and TSE3MDL classes. Added Application::numSongs. Added Progress to the TSE2MDL and MidiFileImport classes. 14 Added Progress to the Ins::Instrument classes. 15 The Instrument class remember's its filename - useful for the Application choices stuff. Added a preset colour capability to the DisplayParams object, and added the PresetColours class. The Application now also manages one of these objects. 16 Updated the PartDisplay to cope with the new PresetColours stuff. Changed the API slightly. 17 Added DisplayParams::presetColourString(). 20 Modified's setModified goes public. * Release 0.0.16 21 D'oh! Progress.h was missing from src/tse/Makefile.am * Release 0.0.17 Gave Phrase a parent() method to shadow Track and Part. You now can't insert a previously inserted Phrase into a PhraseList. Record now copes with start() being called when reset() isn't. Implemented Cmd::Phrase_Insert. Added Util::Phrase_Search, and used it to implement Cmd::Phrase_Remove. 23 Removed Phrase_Search again, since there is already Song_SearchForPhrase. More implementation of Phrase commands, including Phrase_Replace. Now the App::Record object uses commands. Improved Cmd namespace docs. 25 Fixed Modified.setSong(0); it detached from s, not _song. Phrase didn't save its DisplayParams. 27 Merged the two PhraseEdit::reset methods. 30 Improved documentation and added the Version file. ------------------------------------------------------------------------------- December 1 Added Destination class Instrument lookup by name. This is used by the App choices file save/load mechanism. Began to implement Destination choices file stuff. 4 Destination defaults weren't set up. 6 Got the Destination stuff saved in the App choices files. Now the Instruments are saved and loaded properly. Also fixed the Choices loading mechanism which didn't work properly. 14 Bugfixed Destination choices saving. 15 Transferred the build across computers - from solomon to a new beefy machine, the build time is much faster! However this is a Red Hat 7.0 machine and there are a number of build problems - autoconf/automake both behave a little differently. PACKAGE and VERSION strings don't work, and libtool is set up incorrectly by autoconf. Finally go the build into a sane state with autoconf. I now know how to check out the pristine sources and run the correct commands to make the whole thing build OK. 17 Fixed bug in Destination saving for when instrument pointer is zero. Added Progress to MidiFileExport. 18 Fized grevious bug in TimeSigTempoKeyTrackIterator ctor which prevented MidiFile export working. 22 Updated tse3play verbose dignaostic MidiScheduler output. ------------------------------------------------------------------------------- January 2001 3 Fixed bug in Destination class - instruments array was not the correct size leading to surreal application crashes. 4 Added .cvsignore files to make "cvs -nq update" a lot less noisy. 6 Lots of doc tidying and a few extra bits. Added consts to the Application and Record classes where they were missing and ensured that all channel/port params are in the same order. Converted TSE3_Version/TSE3_Copyright to return a "const char *". Moved App::ChoicesManager::ChoicesChoiceHandler from protected to private. 8 A big shakeup in the documentation, it is now "built" which means that I can put a standard header and footer onto it. Haven't worked out how to install the docs yet. Changed the licence to pure GPL (rather than library version). 9 Moved CommandHistory internal data from protected to private. * Release 0.0.18 10 Added a version number to the Application class, and made the choices file save both the application name and version - may be useful in the future. Added a ThisFileCreatedOn to the Application choices block too. It's cute. It's also probably going to be useful for debug. If it it aint, well, wibble! 16 Added Transport::playable(). Added htmlize.pl to doc/Makefile.am EXTRA_DIST. * Release 0.0.19 Altered the RecordListener API so listeners can work out whether or not they were recording (in case there are two both listening to the one Recording object). 17 Fixed PartDisplay for empty Parts (i.e. with no Phrases). Added the TrackSelection class, an analogue of the PartSelection class. Tidied the PartSelection and TrackSelection together, this required some horrible nastiness in the the respective header files that I am not proud of. 22 Improved Notifier documentation. Rolled the libtse3util and libtse3plt into the main libtse3, since they are almost always used together anyway (you'd practically need one of either plt and util for a MidiScheduler, anyway, and neither are /that/ big). Library structure changed: now TSE3 is one big libtse3.so rather than many smaller libraries. 23 Added buffer flushing methods to CommandHistory. Fixed bug where TrackSelection could dereference a 0 minTrack pointer after recalculateEnds mucked the object state up. Added a whole pile of stuff to PhraseEdit to handle selections more gracefully and gave it good documentation. 24 Implemented the good PhraseEdit selection caching. Added PhraseEdit::eraseSelection. Put a whole load of modification status stuff into PhraseEdit and created a callback event for it. * Release 0.0.20 25 Forgot to remove some references to old libraries in tse3play makefile. * Release 0.0.20a A lot of investigation to see if I could get the Notifier framework any better - not possible! It was interesting, though :-) 26 Moved all Listener interfaces into the "listen" subdirectory. This prevents class users from having to include a whole class and everything that it depends on when using the Listener interface. 27 Tidied up some more arthermath of the restructuring. Now the documentation gets installed properly with the rest of the library. 28 More tidying. Moved Modified into TSE3::App. Moved TransportCallback into listen/Transport.h 29 More tidying. File loading may throw exceptions for bad format. The TSE3MDL load is now safe if an exception is thrown (no memory leak for the Song). It also uses a FileBlockParser for the top level. Altered TSE3MDL slightly: now everything is inside a chunk. Now it's completely orthogonal. Modified app/Choices.cpp similarly. Added noChunks to SerializableLoadInfo. Made FileBlockParser a little more tollerant - can now have comments twixt chunk name and opening brace, and empty lines too. 30 Discovered that autoconf enables debugging by default. The little critter. Put a huge warning for this in the configure.in file. This takes the combined lib size down from 6109854 to 1257958 bytes. Phew. The FileRecogniser now has a load() method to prevent the same code being written thousands of times. Made the installation of documentation a compile time option. Finished off the TSE3 spec file, I can now build an RPM of the TSE3 library. I needed to make the docs configurable 'cause otherwise the RPM installation generated two sets of documentation. ------------------------------------------------------------------------------- February 1 Installed ALSA. Ouch. I don't have a card with supported synth capabilities. 2 Imported Matt Gerassimoff's work on the Alsa driver, got it compiling and patched it properly into the build system. UnixMidiSchedulerFactory can now create Alsa devices. 5 Began to tidy up some of Matt's work, bringing the code into line with the rest of the TSE3 style. 6 A lot of rework of the Alsa stuff - reading the Alsa library API and trying to implement it in a much cleaner way. Many implementation methods have moved into the AlsaImpl class. Just discovered that TSE3 0.0.17 and Anthem have made it into SuSE 7.1 (alongside NoteEdit). The code currently stands at 42290 lines and is 1207k of source, not including documentation. 7 Alsa: Ports enumerate OK, and the timer stuff now works. No output goes to my MIDI device, though. 8 Got Alsa timing working. Got both Alsa input and output working. The original Alsa stuff that Matt wrote has now been completely ripped up and replaced. It all appears to work nicely now. 10 Fixed Alsa.cpp so it compiles queitly on a non-Alsa machine. 16 Fixed hienous bug in MidiFileExport - all files created were broken because of the tse3Message being saved with the incorrect length. This has been bust for a while, and is down to the fact I swapped a std::string for a const char *, and some accidental sizeof behaviour. * Release 0.0.21 Added some more docs to the Part class to describe more clearly the need to set the start and end times - forgetting to do this is a common mistake. Put some more cunningness into PhraseEdit::createPhrase - you can now specify a PhraseList and get the Phrase automatically named and inserted. Maybe this won't get used much, maybe it will. Either way, it emphasised the need to name a Phrase before inserting it in a PhraseList. Added some extra docs to the Phrase class too. Rearchitected some of the Phrase stuff, now Phrases CANNOT exist outside of a PhraseList which will prevent a whole class of library user error. This required changes to PhraseEdit, PhraseList and Phrase. Changed me mind slightly, allowed you to remove and reinsert Phrases from the PhraseList - but you now can't use them if you do so - all Parts will ignore a reparented Phrase and you can't Part::setPhrase for an unparented Phrase. At home, added exceptions to Phrase_SetInfo, and did more work on the other Phrase commands and the Record object. Not finished yet. Tidied up other issues. 17 New implementation of Cmd::Phrase_Replace. Used it in the App::Record class again. 18 Bugfixing the updated command. Added an extra parameter to the Song_TrackRemoved event - the old Track's index. 19 Song.cpp bugfix - insert(int) set the new Track's parent to zero. Goodness knows why. Added PhraseEdit::timeShift() so that recorded data can be normalised. Made the App::Record class use timeShift(). 20 PhraseEdit::tidy bugfix - unmatched note off removal on an empty PhraseEdit area would invalidate the data and cause weird segfaults. Doesn't now. Part::setPhrase can no longer dereference 0. Fixed Part_Move command wrt the newEnd time calculation, and fixed bug where ctor params shadow member variables. App::Record uses a CommandGroup for the insert Part section. 21 Found an alarming Notifier problem. When a Phrase::setParent call is made in one situation, not all Listeners get the event. In fact, if I send two events one after the other, one listener gets one event the first time it's sent. The other listener gets it the second time. my hair is getting pulled out... 22 PhraseList new title base names no longer include a trailing space, so the first suggestion is no longer "Phrase ". Fixed the messy Notifier problem. The issue was listeners detaching themselves in a callback - whilst the "listeners" void_list is being used. The for loop that iterates over it couldn't cope, and so had the ability to skip some listeners. The fix is a bit nasty - take a copy of the listeners list and iterate over that. Of course, some listeners might have removed themsleves, so I need to test each listener in the copy_list as it's iterated over with the real list, just to check that it still wants to receive the event. Sigh. It was a lot to get my head around, but it's working again now. Tidied up and gave more docs to the void_list. Updated the Notifer HTML docs. PhraseEdit::reset always sends a notification and always updates the selection information. Following a fault report, added #include to every header file that uses size_t. I was presuming that stl headers include it, which is somewhat bogus. Fixed Cmd::Phrase_SetInfo - if the title is the same as the old one, it was throwing an exception when it needn't. Fixed this problem. ------------------------------------------------------------------------------- March 5 Fixed PhraseEdit::tidy() - used size() in a couple of places where it should have been size()-1. This was reported by Claus-Justus Heine. Tidied up the Alsa pimpl tx method slightly. 6 Joerg has discovered the bug which made Alsa timing dodgy - I did a bad calculation to get from nanoseconds to milliseconds in AlsaMidiScheduler::tx. Fixing this makes the AlsaMidiScheduler usable for the first time. Transport ctor sets _breakUps to 0. * Release 0.0.22 Arse! I missed a zero from plt/Alsa.cpp. Fixed. * Release 0.0.22a 13 Updated the OSSMidiScheduler - hid all the nasty implementation classes from the public header file, and moved the patch setting APIs into the OSSMidiScheduler class. 19 Changed to a much nicer set of default preset colours, and coloured in the demo song. 21 Slight efficiency improvement in Notifier.h: in the Event class, the parameters are now held by reference, rather than copied. Applied a "work around" for an Alsa 0.5.x flaw in Alsa.cpp - the number of clock nanoseconds can be a ludicrous number, so its now checked by TSE3. 22 Small mod to StreamMidiScheduler so that clock() only increments the clock when it's running. I've been using it to debug Anthem, and the clock drifts when the scheduler is stopped which is quite disconcerting. Doesn't now. Joerg pointed out that my Alsa bug workaround was insufficient. The correct fix is now in place. Bugfixes for the Panic object - it now plays events properly. Still doesn't do the GM/GS/XG malarky, but that's really because I haven't got a decent streamable sysex facility in TSE3 yet... Gave the Part and Phrase listener interfaces windows into the changed events of their subcomponents (DisplayParams et al). This proved to be needed by Anthem. Added a DisplayParams object to Track. Updated Track_SetInfo. Gave the Track class the same forwarding event as I did the Phrase class. 23 Fixed annoying playback bug where the MidiParams weren't being filtered in either the Track or Part iterators. Added a whole pile more demo songs, and installed them in the Makefile. Added Type_Error to the FileRecogniser class for filenames that don't exist. Added the Melody PresetColour. The Alsa bug work around in plt/Alsa.cpp has become much more hideous. It was contributed Joerg Anders. * Release 0.0.23 27 More thoughts about sysex, as documented in Playable.html. Extended this doc file to describe the Midi.h definitons. Implemented GM resets in Panic.cpp using this new scheme. 28 Added running status to the OSSMidiScheduler so that sysex events will work. Implemented GM/GS/XG resets in the PanicIterator. Correctly handled the GS/XG device ID masks. Made the StreamMidiScheduler mention meta events (particularly invalid events). Got sysex working in the AlsaMidiScheduler. Cripes it was tedious. If only the sysex Alsa interface was documented. It turns out that even if you call it a sysex stream, you still need to include the start and end status bytes. 30 Bugfix (and semantics fix) to Cmd::Phrase_Erase. Fixed insideous little error in Song::remove(Track *t). It delegated the removal to Song::remove(size_t). However, it sent a Removed notification. Mostly worked as expected, but two notifictions got sent. This caused a very odd bit of behaviour in Anthem's TrackList and was quite tricky to find! * Release 0.0.24 ------------------------------------------------------------------------------- April 1 Made link lines in makefiles cleaner. 9 A lot of reworking of the Instrument class (and related classes) to make information access a whole bunch easier. 23 Added #define _GNU_SOURCE to the top of plt/Alsa.cpp which fixes errors in the linux headers on some platforms. ------------------------------------------------------------------------------- May 11 Made a concerted effort to incorporate Stefan Westerfeld's aRts scheduler code into the TSE3 code base. I'd only put it off because I though it involved some hairy MCOP stuff, but thankfully it didn't. It's gone in OK, but I can't get it to work yet. 14 Random tse3play errors are in fact a non-handled switch statement for the new error case from FileRecogniser. Fixed. Still can't get aRts to work. Added ArtsMidiScheduler support to UnixMidiSchedulerFactory. 16 Fixed bug when playing TSE2 files. Demo TSE2 file added to the misc directory. Doesn't install, though. * Release 0.0.25 31 Got the instrument name lookup stuff working quite nicely. Proved this by using it in Anthem. ------------------------------------------------------------------------------- June 30 Added the ability to get at an Instrument's ControlData and NrpnData. ------------------------------------------------------------------------------- July - 11 More documentation. Moved to beat release * 0.1.0 release 19 Started a marathon stint of work getting TSE3 to compile under gcc 3.0. The new compiler is /much/ stricter and there are a number of areas TSE3 was loose on. The most common (and easiest to fix) is the tightened use of the std namespace. 20 More gcc 3.0 work. Got it to compile, but can't yet run because the rest of my system is not built with gcc 3.0. Out of interest the file sizes are, gcc 2.95.3 gcc 3.0 debug build 6571618 9176054 non-debug build 1372042 1403374 That looks quite poor! 24 Started planning for improved serialization and MidiScheduler frameworks. * 0.1.1 release ------------------------------------------------------------------------------- August 6 Work on a new MidiScheduler architecture that is more flexible. 10 Work on a more XML-like file structure - thinking of removing the Serializable class completely ------------------------------------------------------------------------------- September Somewhat distracted by other events ------------------------------------------------------------------------------- October 9 Fiddled the MidiFileExport so that you give it a filename, as you do for import and TSE3MDL save/load. Added the MidiFileExportError. Fixed bug in MidiEvent constructor for NoteOns that meant no note off events were ever being created. Fixed bug in MidiData::lastClock which deferenced data.end() - that's an invalid data member. Added a new example - creating a scale, playing it and saving it as a MIDI file on request by a user. ...Work on a new MidiScheduler framework, and XML file loading (saving is complete) ------------------------------------------------------------------------------- November 28 Added RPNs to the Instrument class, added the RpnData class and fixed the way NRPNs are loaded. Updated the Cakewalk ins format documentation too. Added the examples/midifile example. * 0.1.2 release (no new MidiScheduler stuff yet) 29 Added docs about MidiFile import/export exceptions. Added a reimplemetion of the standard "what" function to the Error class. Fixed the configure search for arts midi header files. ------------------------------------------------------------------------------- December 3 Added work around for OSS MidiScheduler code: it appears that OSS doesn't support running status for AWE emulated MIDI ports properly. The MidiScheduler now detects them and attempts to work around this limitation. Put check for the ALSA verison into configure.in and Alsa.cpp. ------------------------------------------------------------------------------- January 2002 3 Concerted effort to get the new MidiScheduler framework into the build properly, making pragmatic design decisions. 4 Incorporated Jose Maria Sanchez Saez' work on a Win32 MidiScheduler. Moved muldiv from MidiScheduler.cpp into Util namespace 5 Working from a pre-new MidiScheduler tree, sorted out the MidiSchedulerFactory. There are now no subclasses, just the one class that has different implementations on different platforms. That keeps things a little more simple. Used it in tse3play. Worked out how to detect cygwin on Win32, and added tests for this to the configure script, and patched into the build system for the plt directory. Now the Win32 scheduler code should be built on those platforms. I can't test this here, so I'll send it to Jose to see how it works for him. ------------------------------------------------------------------------------- February 20 Added the contents example. ------------------------------------------------------------------------------- March 2002 27 [ASIDE] Branched 0.1.2 for an Alsa 0.9.x maintenance release. A lot of build work to correctly regonise Alsa and the various different Alsa versions. Split implementations of Alsa up into different files Alsa-XXX.cpp. Integrated 0.9.x work kindly done by Takashi Iwai of SuSE. Modified configure.in for aRts header detection too. * 0.1.3 release (branched version) 28 Merged 0.1.3 branch onto trunk. ------------------------------------------------------------------------------- April 4 Added port to Panic 8 Ported OSS MidiScheduler to new implementation. 10 Added concept of "all ports" port number and "no port" port number. Began the porting work for Alsa code. 16 Ported Alsa 0.5 to new MidiScheduler framework. Added $KDEDIRS linkage to configure.in for aRts library. 17 Implemented AllPorts and NoPort in the MidiScheduler. Added the MidiScheduler::portNumber API for simplicity. MidiEcho implementation of port/channel acceptance was wrong - it implemented forcing to the specified destination, NOT filtering the source. Fixed, and also prevented reliance on valid port numbers with the new MidiScheduler. 22 Song::lastClock is now cached. Changed Record ctor, since you don't need to specify a MidiScheduler (it is available through Transport::scheduler()). Fixed MidiScheduler.h bug: clock() didn't account for "_running == false" Expanded MidiSchedulerListener to have _PortAdded and _PortRemoved. Emitted these in the relevant places. 25 Added time parameter to the EventTrackListener interfaces. Added the Track_Sort command. 26 Sped up Track_Sort considerably by moving away from a quicksort algorithm, to a more careful and less track-swap-hungry approach. The sort command now also reselects selected Tracks once they've all been moved about. EventTrack::insert returns a size_t index of the new event. Changed the listener interface so that the parameter is the index. 28 Named the anonymous enums in the MidiCommand class that describe "magic" port and channel numbers - they were causing some compiler warnings. Adjusted the demo songs so that they honour the magic channel/ports. 29 Fixed MidiFilter in light of new magic port/channel numbers. * Release 0.2.0 ------------------------------------------------------------------------------- May 3 MidiEcho default channel is sensible. The Part_Move command correctly names itself when Parts are moved between Tracks. Late night hackery to get TSE3 to build under automake 1.6.1. It does some weird stuff with .deps which caused failures since I had a rule libtse3plt_ls_SOURCES_alsa = Alsa-$(TSE3_ALSA_VERSION).cpp 7 Some fixes for building with Alsa 0.9. More documentation for command classes - placing it into the standard classes documentation for reference. In doing this realised that Song_ReplacePhrase clashed with Phrase_Replace. Removed former. 8 Moved the "misc" directory to "demos". * Release 0.2.1 9 Added MidiScheduler::numberToIndex(). MidiFilter has sensible default port and channel. Alsa 0.9 build fixes and aRts fixes under SuSe 8.0. * Release 0.2.2 13 Fixed some issues: MidiFilter.cpp - removed run time check that was replaced by a compile-time check. PartIterator::Part_PhraseAltered doesn't resend the MidiParams. Sorted out SerializableLoadIterator ctor so that it works with gcc 3.0.x - initialising an int with a negative number in an initialiser list doesn't work. Sigh. PhraseList is more careful if Phrase creation fails during load. A little more thoughtful dealing with MidiParams in the PartIterator during moves. 14 Fixed crash in Anthem when it is closed whilst playing - the TrackIterator didn't check that _track hadn't been deleted when doing a "moveTo". 16 Fixed the PartIterator so that it doesn't throw away the first event of the Phrase. 17 Added "-l" option to tse3play, this was Joerg's suggestion. Added ports example. Fixed MidiEcho bug. * Release 0.2.3 21 Added more docs to MidiEcho to make it clear what setChannel/setPort do. ------------------------------------------------------------------------------- July 10 MidiFileExport and TSE3MDL can save to an ostream as well as a filename. You can specify "-" as tse3play output parameters. 11 Got MidiFileExport ofstream flags right, so file gets truncated. 16 configure.in fix thanks to Sébastien Prud'homme. 28 Changed email address away from old Pace one since I no longer work there. * Release 0.2.4 ------------------------------------------------------------------------------- August 22 MidiFile.cpp patch so that it compiles under gcc 3.2. * Release 0.2.5 ------------------------------------------------------------------------------- October 22 Bug fix tse3play, default port is NoPort Added a MidiScheduler concept of internal and external ports. Updated the implementation accordingly. Made tse3play a lot more clever in which ports it picks for playback. 23 Added Doxyfile 24 More MidiScheduler implementation docs. 30 Put the doxygen documentation completely in the distribution * Release 0.2.6 ------------------------------------------------------------------------------- February 2003 10 Tidied tse3play so you don't need to open the MIDI devices to convert files. ------------------------------------------------------------------------------- March 6 Added MIDI record example application. 7 Added definition of TSE3::Clock::PPQN to Midi.cpp * Release 0.2.7 12 Fixed compilation error ni Alsa-0.9.cpp ------------------------------------------------------------------------------- TODO ------------------------------------------------------------------------------- Core TSE3 library * AllChannels/NoChannels in MidiScheduler - or punt out? * XML file format loading * Check use of EventTrack::index, now there's a bool parameter, can some redundant logic be removed? * Lyric track * Plugin interface for audio/video tracks * Load any type of file utility * PowerQuantise with groove taken from another Phrase/Track. * Finish off the Demidify utility. * Mixer architecture needs sorting out now ports can be arbitary numbers * MidiScheduler catches sysex into a bit bucket, and then sends it out wholesale tse3play * Reset sent on ctrl-c Issues * disable RepeatTrack, iterator moves to 0, _more == false. Enable it, it will move to 0 which will be wrong. - I've done some thinking about this - see paper notes (somewhere). ------------------------------------------------------------------------------- tse3-0.3.1/doc/README0000644000175700001440000000044210271145632010743 00000000000000Doc dir README ============== You need to build the documentation before you can read it properly. A simple "cd doc; make" will do. Ovbiously, this means that you can't read the HTML build docs before building :-( You can just read the file "src/Build.html.in" in a web browser, though. tse3-0.3.1/doc/Makefile.am0000644000175700001440000000573010271145632012124 00000000000000############################################################################### # These are the distribution files EXTRA_DIST = \ History \ src/About.html.in \ src/Article.html.in \ src/Build.html.in \ src/Bugs.html.in \ src/Commands.html.in \ src/Copyright.html.in \ src/Error.html.in \ src/Examples.html.in \ src/Feedback.html.in \ src/HOWTO.html.in \ src/History.html.in \ src/InsFiles.html.in \ src/KDOC.html.in \ src/Mutex.html.in \ src/Notifier.html.in \ src/Playable.html.in \ src/Porting.html.in \ src/Psalm150.html.in \ src/Song.html.in \ src/Structure.html.in \ src/TSE3MDL.html.in \ src/Trax.html.in \ src/Trouble.html.in \ src/Whitepaper.html.in \ src/Version.html.in \ src/htmlize.pl \ src/index.html.in \ src/pete.jpeg.verbatim.in \ src/trax.gif.verbatim.in \ src/tse3.gif.verbatim.in \ src/tse3logo.png.verbatim.in ############################################################################### # These are the files that get built HTML_FILES = \ About.html \ Article.html \ Build.html \ Bugs.html \ Commands.html \ Copyright.html \ Error.html \ Examples.html \ Feedback.html \ HOWTO.html \ History.html \ InsFiles.html \ KDOC.html \ Mutex.html \ Notifier.html \ Playable.html \ Porting.html \ Psalm150.html \ Song.html \ Structure.html \ TSE3MDL.html \ Trax.html \ Trouble.html \ Whitepaper.html \ Version.html \ index.html VERBATIM_FILES = \ History \ pete.jpeg \ trax.gif \ tse3.gif \ tse3logo.png ############################################################################### # This is how they get built HTMLIZE = $(srcdir)/src/htmlize.pl VERSION_FILE = $(top_srcdir)/Version VERSION = `cat $(VERSION_FILE)` all-local: $(HTML_FILES) $(VERBATIM_FILES) $(HTMLIZE) $(VERSION_FILE) clean-local: rm -rf *.html api tse3-doxygen: @cd ../src; doxygen tse3-kdoc: @cd ../src/tse3; make tse3-kdoc tse3-kdoc-all: @cd ../src/tse3; make tse3-kdoc-all tse3-kdoc-libs: @cd ../src/tse3; make tse3-kdoc-libs %.html: src/%.html.in @echo "Creating $@ from $<" @if (which perl > /dev/null 2>/dev/null); then \ perl $(HTMLIZE) $(VERSION) < $< > $@; \ else cp $< $@; fi %.gif: src/%.gif.verbatim.in @echo "Creating $@ from $<" cp $< $@ %.png: src/%.png.verbatim.in @echo "Creating $@ from $<" cp $< $@ %.jpeg: src/%.jpeg.verbatim.in @echo "Creating $@ from $<" cp $< $@ ############################################################################### # And this is how they are installed if INSTALL_TSE3_DOC docs_DATA = $(HTML_FILES) $(VERBATIM_FILES) docsdir = ${prefix}/doc/${PACKAGE}-${VERSION} endif tse3-0.3.1/doc/Makefile.in0000644000175700017570000003301510302622110012127 00000000000000# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ ############################################################################### # These are the distribution files srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = SOURCES = DIST_SOURCES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(docsdir)" docsDATA_INSTALL = $(INSTALL_DATA) DATA = $(docs_DATA) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPP_MM = @CPP_MM@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ HAVE_ALSA_FALSE = @HAVE_ALSA_FALSE@ HAVE_ALSA_TRUE = @HAVE_ALSA_TRUE@ HAVE_ARTS_FALSE = @HAVE_ARTS_FALSE@ HAVE_ARTS_TRUE = @HAVE_ARTS_TRUE@ HAVE_OSS_FALSE = @HAVE_OSS_FALSE@ HAVE_OSS_TRUE = @HAVE_OSS_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTALL_TSE3_DOC_FALSE = @INSTALL_TSE3_DOC_FALSE@ INSTALL_TSE3_DOC_TRUE = @INSTALL_TSE3_DOC_TRUE@ LDFLAGS = @LDFLAGS@ LIBARTS = @LIBARTS@ LIBASOUND = @LIBASOUND@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TSE3_ALSA_PREFIX = @TSE3_ALSA_PREFIX@ TSE3_ALSA_VERSION = @TSE3_ALSA_VERSION@ TSE3_ARTS_PREFIX = @TSE3_ARTS_PREFIX@ TSE3_WITH_ALSA = @TSE3_WITH_ALSA@ TSE3_WITH_ALSA_0_5_X = @TSE3_WITH_ALSA_0_5_X@ TSE3_WITH_ALSA_0_5_X_FALSE = @TSE3_WITH_ALSA_0_5_X_FALSE@ TSE3_WITH_ALSA_0_5_X_TRUE = @TSE3_WITH_ALSA_0_5_X_TRUE@ TSE3_WITH_ALSA_0_9_X = @TSE3_WITH_ALSA_0_9_X@ TSE3_WITH_ALSA_0_9_X_FALSE = @TSE3_WITH_ALSA_0_9_X_FALSE@ TSE3_WITH_ALSA_0_9_X_TRUE = @TSE3_WITH_ALSA_0_9_X_TRUE@ TSE3_WITH_ALSA_FALSE = @TSE3_WITH_ALSA_FALSE@ TSE3_WITH_ALSA_TRUE = @TSE3_WITH_ALSA_TRUE@ TSE3_WITH_ARTS = @TSE3_WITH_ARTS@ TSE3_WITH_ARTS_FALSE = @TSE3_WITH_ARTS_FALSE@ TSE3_WITH_ARTS_TRUE = @TSE3_WITH_ARTS_TRUE@ TSE3_WITH_OSS = @TSE3_WITH_OSS@ TSE3_WITH_OSS_FALSE = @TSE3_WITH_OSS_FALSE@ TSE3_WITH_OSS_TRUE = @TSE3_WITH_OSS_TRUE@ TSE3_WITH_WIN32 = @TSE3_WITH_WIN32@ TSE3_WITH_WIN32_FALSE = @TSE3_WITH_WIN32_FALSE@ TSE3_WITH_WIN32_TRUE = @TSE3_WITH_WIN32_TRUE@ VERSION = `cat $(VERSION_FILE)` ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ prefix = @prefix@ program_transform_name = @program_transform_name@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ EXTRA_DIST = \ History \ src/About.html.in \ src/Article.html.in \ src/Build.html.in \ src/Bugs.html.in \ src/Commands.html.in \ src/Copyright.html.in \ src/Error.html.in \ src/Examples.html.in \ src/Feedback.html.in \ src/HOWTO.html.in \ src/History.html.in \ src/InsFiles.html.in \ src/KDOC.html.in \ src/Mutex.html.in \ src/Notifier.html.in \ src/Playable.html.in \ src/Porting.html.in \ src/Psalm150.html.in \ src/Song.html.in \ src/Structure.html.in \ src/TSE3MDL.html.in \ src/Trax.html.in \ src/Trouble.html.in \ src/Whitepaper.html.in \ src/Version.html.in \ src/htmlize.pl \ src/index.html.in \ src/pete.jpeg.verbatim.in \ src/trax.gif.verbatim.in \ src/tse3.gif.verbatim.in \ src/tse3logo.png.verbatim.in ############################################################################### # These are the files that get built HTML_FILES = \ About.html \ Article.html \ Build.html \ Bugs.html \ Commands.html \ Copyright.html \ Error.html \ Examples.html \ Feedback.html \ HOWTO.html \ History.html \ InsFiles.html \ KDOC.html \ Mutex.html \ Notifier.html \ Playable.html \ Porting.html \ Psalm150.html \ Song.html \ Structure.html \ TSE3MDL.html \ Trax.html \ Trouble.html \ Whitepaper.html \ Version.html \ index.html VERBATIM_FILES = \ History \ pete.jpeg \ trax.gif \ tse3.gif \ tse3logo.png ############################################################################### # This is how they get built HTMLIZE = $(srcdir)/src/htmlize.pl VERSION_FILE = $(top_srcdir)/Version ############################################################################### # And this is how they are installed @INSTALL_TSE3_DOC_TRUE@docs_DATA = $(HTML_FILES) $(VERBATIM_FILES) @INSTALL_TSE3_DOC_TRUE@docsdir = ${prefix}/doc/${PACKAGE}-${VERSION} all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: install-docsDATA: $(docs_DATA) @$(NORMAL_INSTALL) test -z "$(docsdir)" || $(mkdir_p) "$(DESTDIR)$(docsdir)" @list='$(docs_DATA)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(docsDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docsdir)/$$f'"; \ $(docsDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docsdir)/$$f"; \ done uninstall-docsDATA: @$(NORMAL_UNINSTALL) @list='$(docs_DATA)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(docsdir)/$$f'"; \ rm -f "$(DESTDIR)$(docsdir)/$$f"; \ done tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) $(mkdir_p) $(distdir)/src @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) all-local installdirs: for dir in "$(DESTDIR)$(docsdir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-libtool dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-docsDATA install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-docsDATA uninstall-info-am .PHONY: all all-am all-local check check-am clean clean-generic \ clean-libtool clean-local distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-docsDATA install-exec install-exec-am install-info \ install-info-am install-man install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \ uninstall-docsDATA uninstall-info-am all-local: $(HTML_FILES) $(VERBATIM_FILES) $(HTMLIZE) $(VERSION_FILE) clean-local: rm -rf *.html api tse3-doxygen: @cd ../src; doxygen tse3-kdoc: @cd ../src/tse3; make tse3-kdoc tse3-kdoc-all: @cd ../src/tse3; make tse3-kdoc-all tse3-kdoc-libs: @cd ../src/tse3; make tse3-kdoc-libs %.html: src/%.html.in @echo "Creating $@ from $<" @if (which perl > /dev/null 2>/dev/null); then \ perl $(HTMLIZE) $(VERSION) < $< > $@; \ else cp $< $@; fi %.gif: src/%.gif.verbatim.in @echo "Creating $@ from $<" cp $< $@ %.png: src/%.png.verbatim.in @echo "Creating $@ from $<" cp $< $@ %.jpeg: src/%.jpeg.verbatim.in @echo "Creating $@ from $<" cp $< $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: tse3-0.3.1/src/0000777000175700017570000000000010310240002010161 500000000000000tse3-0.3.1/src/tse3/0000777000175700017570000000000010310240001011036 500000000000000tse3-0.3.1/src/tse3/app/0000777000175700017570000000000010310240001011616 500000000000000tse3-0.3.1/src/tse3/app/Choices.cpp0000644000175700001440000005334010302614150013620 00000000000000/* * @(#)Choices.cpp 3.00 25 May 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/app/Choices.h" #include #include #include #include #include "tse3/MidiScheduler.h" #include "tse3/FileBlockParser.h" #include "tse3/app/Application.h" #include "tse3/Error.h" #include "tse3/Metronome.h" #include "tse3/Transport.h" #include "tse3/ins/Destination.h" #include "tse3/ins/Instrument.h" using namespace TSE3; using namespace TSE3::App; /****************************************************************************** * ChoiceHandler class *****************************************************************************/ ChoiceHandler::ChoiceHandler(const std::string &choicename) : _name(choicename) { } ChoiceHandler::~ChoiceHandler() { } /****************************************************************************** * ChoicesManager class *****************************************************************************/ ChoicesManager::ChoicesManager() { } ChoicesManager::~ChoicesManager() { } void ChoicesManager::save(const std::string &filename) { std::ofstream out(filename.c_str()); if (!out) { std::cerr << "TSE3: Couldn't save application choices to '" << filename << "'.\n"; } out << "TSE3MDL\n" << "# This is an automatically generated file containing choices for\n" << "# applications that use the TSE3 library (available from\n" << "# ).\n" << "# You shouldn't need to edit this file by hand.\n" << "{\n" << " Choices\n"; handler.save(out, 1); out << "}\n"; } void ChoicesManager::load(const std::string &filename) { std::ifstream in(filename.c_str()); if (!in) { std::cerr << "TSE3: Couldn't load application choices from '" << filename << "'.\n"; return; } // Check first line reads TSE3MDL std::string tse3mdl; getline(in, tse3mdl); if (tse3mdl != "TSE3MDL") { std::cerr << "TSE3: " << filename << " is not a TSE3MDL choices file.\n"; return; } SerializableLoadInfo info; // Now scan the file contents. FileBlockParser parser; parser.add("Choices", &handler); try { parser.parse(in, info); } catch (const TSE3::Error &e) { std::cerr << "TSE3: Failed to parse choices file\n"; } if (info.noChunks == 0) { std::cerr << "TSE3: Choices file contained no choices\n"; } in.close(); } /****************************************************************************** * ChoicesManager::ChoicesChoiceHandler class *****************************************************************************/ ChoicesManager::ChoicesChoiceHandler::ChoicesChoiceHandler() : ChoiceHandler("Choices") { } ChoicesManager::ChoicesChoiceHandler::~ChoicesChoiceHandler() { while (handlers.size()) { delete *(handlers.begin()); handlers.remove(*(handlers.begin())); } } void ChoicesManager::ChoicesChoiceHandler::add(ChoiceHandler *ch) { handlers.push_back(ch); } void ChoicesManager::ChoicesChoiceHandler::remove(ChoiceHandler *ch) { handlers.remove(ch); } void ChoicesManager::ChoicesChoiceHandler::save(std::ostream &out, int ind) const { out << indent(ind) << "{\n"; std::list::const_iterator i = handlers.begin(); while (i != handlers.end()) { out << indent(ind+1) << (*i)->name() << "\n"; (*i)->save(out, ind+1); ++i; } out << indent(ind) << "}\n"; } void ChoicesManager::ChoicesChoiceHandler::load(std::istream &in, SerializableLoadInfo &info) { FileBlockParser parser; std::list::iterator i = handlers.begin(); while (i != handlers.end()) { parser.add((*i)->name(), *i); ++i; } parser.parse(in, info); } /****************************************************************************** * ApplicationChoiceHandler class *****************************************************************************/ ApplicationChoiceHandler::ApplicationChoiceHandler(Application *a) : ChoiceHandler("Application"), a(a) { } ApplicationChoiceHandler::~ApplicationChoiceHandler() { } void ApplicationChoiceHandler::save(std::ostream &out, int i) const { std::time_t time = std::time(0); out << indent(i) << "{\n" << indent(i+1) << "AppName:" << a->appName().c_str() << "\n" << indent(i+1) << "AppVersion:" << a->appVersion().c_str() << "\n"; if (time != time_t(-1)) { const char *days[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri" }; std::tm *gt = std::gmtime(&time); out << indent(i+1) << "ThisFileCreatedOn:" << 1900+gt->tm_year << "-" << gt->tm_mon+1 << "-" << gt->tm_mday << "-" << gt->tm_hour << "-" << gt->tm_min << "-" << gt->tm_sec << " (" << days[gt->tm_wday] << ")\n"; } out << indent(i+1) << "SaveChoicesOnDestroy:"; if (a->saveChoicesOnDestroy()) out << "Yes\n"; else out << "No\n"; out << indent(i) << "}\n"; } void ApplicationChoiceHandler::load(std::istream &in, SerializableLoadInfo &info) { FileItemParser_OnOff scod(a, &Application::setSaveChoicesOnDestroy); FileBlockParser parser; parser.add("SaveChoicesOnDestroy", &scod); parser.parse(in, info); } /****************************************************************************** * MetronomeChoiceHandler class *****************************************************************************/ MetronomeChoiceHandler::MetronomeChoiceHandler(Metronome *m) : ChoiceHandler("Metronome"), m(m) { } MetronomeChoiceHandler::~MetronomeChoiceHandler() { } void MetronomeChoiceHandler::save(std::ostream &out, int i) const { out << indent(i) << "{\n"; out << indent(i+1) << "Channel:" << m->channel() << "\n"; out << indent(i+1) << "Port:" << m->port() << "\n"; out << indent(i+1) << "Duration:" << m->duration() << "\n"; out << indent(i+1) << "BarNote:" << m->barNote() << "\n"; out << indent(i+1) << "BarVelocity:" << m->barVelocity() << "\n"; out << indent(i+1) << "BeatNote:" << m->beatNote() << "\n"; out << indent(i+1) << "BeatVelocity:" << m->beatVelocity() << "\n"; out << indent(i+1) << "PlayingStatus:"; if (m->status(Transport::Playing)) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "RecordingStatus:"; if (m->status(Transport::Recording)) out << "On\n"; else out << "Off\n"; out << indent(i) << "}\n"; } void MetronomeChoiceHandler::load(std::istream &in, SerializableLoadInfo &info) { FileItemParser_Number channel(m, &Metronome::setChannel); FileItemParser_Number port(m, &Metronome::setPort); FileItemParser_Number duration(m, &Metronome::setDuration); FileItemParser_Number barNote(m, &Metronome::setBarNote); FileItemParser_Number barVelocity(m, &Metronome::setBarVelocity); FileItemParser_Number beatNote(m, &Metronome::setBeatNote); FileItemParser_Number beatVelocity(m, &Metronome::setBeatVelocity); FileItemParser_ReasonOnOff playing(m, &Metronome::setStatus, Transport::Playing); FileItemParser_ReasonOnOff recording(m, &Metronome::setStatus, Transport::Recording); FileBlockParser parser; parser.add("Channel", &channel); parser.add("Port", &port); parser.add("Duration", &duration); parser.add("BarNote", &barNote); parser.add("BarVelocity", &barVelocity); parser.add("BeatNote", &beatNote); parser.add("BeatVelocity", &beatVelocity); parser.add("PlayingStatus", &playing); parser.add("RecordingStatus", &recording); parser.parse(in, info); } /****************************************************************************** * TransportChoiceHandler class *****************************************************************************/ TransportChoiceHandler::TransportChoiceHandler(Transport *t) : ChoiceHandler("Transport"), t(t), startPanicHandler(t->startPanic()), endPanicHandler(t->endPanic()), mapperHandler(t->midiMapper()) { } TransportChoiceHandler::~TransportChoiceHandler() { } void TransportChoiceHandler::save(std::ostream &out, int i) const { out << indent(i) << "{\n"; out << indent(i+1) << "Synchro:"; if (t->synchro()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "PuchIn:"; if (t->punchIn()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "AutoStop:"; if (t->autoStop()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "StartPanic\n"; startPanicHandler.save(out, i+1); out << indent(i+1) << "EndPanic\n"; endPanicHandler.save(out, i+1); out << indent(i+1) << "MidiMapper\n"; mapperHandler.save(out, i+1); out << indent(i) << "}\n"; } void TransportChoiceHandler::load(std::istream &in, SerializableLoadInfo &info) { FileItemParser_OnOff synchro(t, &Transport::setSynchro); FileItemParser_OnOff punchIn(t, &Transport::setPunchIn); FileItemParser_OnOff autoStop(t, &Transport::setAutoStop); PanicChoiceHandler startPanic(t->startPanic()); PanicChoiceHandler endPanic(t->endPanic()); MidiMapperChoiceHandler mapper(t->midiMapper()); FileBlockParser parser; parser.add("Synchro", &synchro); parser.add("PunchIn", &punchIn); parser.add("AutoStop", &autoStop); parser.add("StartPanic", &startPanic); parser.add("EndPanic", &endPanic); parser.add("MidiMapper", &mapper); parser.parse(in, info); } /****************************************************************************** * PanicChoiceHandler class *****************************************************************************/ PanicChoiceHandler::PanicChoiceHandler(Panic *p) : ChoiceHandler("Panic"), p(p) { } PanicChoiceHandler::~PanicChoiceHandler() { } void PanicChoiceHandler::save(std::ostream &out, int i) const { out << indent(i) << "{\n"; out << indent(i+1) << "Status:"; if (p->status()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "MidiReset:"; if (p->midiReset()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "GmReset:"; if (p->gmReset()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "GsReset:"; if (p->gsReset()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "XgReset:"; if (p->xgReset()) out << "On\n"; else out << "Off\n"; int gsIDMask = 0; for (int n = 0; n < 32; ++n) if (p->gsIDMask(n)) gsIDMask |= 1 << n; out << indent(i+1) << "GsIDMask:" << std::hex << gsIDMask << std::dec << "\n"; int xgIDMask = 0; for (int n = 0; n < 16; ++n) if (p->xgIDMask(n)) xgIDMask |= 1 << n; out << indent(i+1) << "XgIDMask:" << std::hex << xgIDMask << std::dec << "\n"; out << indent(i+1) << "AllNotesOff:"; if (p->allNotesOff()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "AllNotesOffMan:"; if (p->allNotesOffManually()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "AllModsOff:"; if (p->allModsOff()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "AllPitchOff:"; if (p->allPitchOff()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "AllCtrlOff:"; if (p->allCtrlOff()) out << "On\n"; else out << "Off\n"; out << indent(i+1) << "LiftSustain:"; if (p->liftSustain()) out << "On\n"; else out << "Off\n"; out << indent(i) << "}\n"; } namespace { /** * A utility class implementing a specific type of FileItemParser. * This class will call a member function with signature * void setXXX(int maskNo, bool) with mask values from 0 to maskSize-1 * and values of bool based on a hexidecimal mask string representing * a bitfield where bit 0 corresponds to maskNo 0. * * @short Internal utility for parsing bitfield data lines * @author Pete Goodliffe * @version 1.00 */ template class FileItemParser_Mask : public FileItemParser { public: typedef void (T::*fn_t)(size_t mask, bool); FileItemParser_Mask(T *obj, fn_t mfun, int maskSize) : obj(obj), mfun(mfun), maskSize(maskSize) {} void parse(const std::string &data) { size_t mask; std::stringstream si(data); si >> std::hex >> mask; for (size_t n = 0; n < maskSize; ++n) (obj->*mfun)(n, mask&(1< status(p, &Panic::setStatus); FileItemParser_OnOff midi(p, &Panic::setMidiReset); FileItemParser_OnOff gm(p, &Panic::setGmReset); FileItemParser_OnOff gs(p, &Panic::setGsReset); FileItemParser_OnOff xg(p, &Panic::setXgReset); FileItemParser_OnOff notes(p, &Panic::setAllNotesOff); FileItemParser_OnOff notesMan(p, &Panic::setAllNotesOffManually); FileItemParser_OnOff mods(p, &Panic::setAllModsOff); FileItemParser_OnOff pitch(p, &Panic::setAllPitchOff); FileItemParser_OnOff ctrl(p, &Panic::setAllCtrlOff); FileItemParser_OnOff sustain(p, &Panic::setLiftSustain); FileItemParser_Mask gsMask(p, &Panic::setGsIDMask, 32); FileItemParser_Mask xgMask(p, &Panic::setXgIDMask, 16); FileBlockParser parser; parser.add("Status", &status); parser.add("MidiReset", &midi); parser.add("GmReset", &gm); parser.add("GsReset", &gs); parser.add("GsIDMask", &gsMask); parser.add("XgReset", &xg); parser.add("XgIDMask", &xgMask); parser.add("AllNotesOff", ¬es); parser.add("AllNotesOffMan", ¬esMan); parser.add("AllModsOff", &mods); parser.add("AllPitchOff", &pitch); parser.add("AllCtrlOff", &ctrl); parser.add("LiftSustain", &sustain); parser.parse(in, info); } /****************************************************************************** * MidiMapperChoiceHandler class *****************************************************************************/ MidiMapperChoiceHandler::MidiMapperChoiceHandler(MidiMapper *m) : ChoiceHandler("MidiMapper"), m(m) { } MidiMapperChoiceHandler::~MidiMapperChoiceHandler() { } void MidiMapperChoiceHandler::save(std::ostream &out, int i) const { out << indent(i) << "{\n"; out << indent(i+1) << "MaximumMap:" << m->maximumMap() << "\n"; for (int port = 0; port < m->maximumMap(); ++port) { int map = m->map(port); out << indent(i+1) << "Map:" << port << "," << map << "\n"; } out << indent(i) << "}\n"; } namespace { /** * A utility class implementing a specific type of FileItemParser. * It interprets the Map lines saved by the MidiMapperChoiceHandler. * * @short Internal utility for parsing MidiMapper block items. * @author Pete Goodliffe * @version 1.00 */ class FileItemParser_Map : public FileItemParser { public: FileItemParser_Map(MidiMapper *obj) : obj(obj) {} void parse(const std::string &data) { if (data.substr(0, 8) == "MaximumMap:") { int i; std::istringstream si(data.c_str()+8); si >> i; } else if (data.substr(0, 4) == "Map:") { int fromPort, toPort; std::istringstream si(data.c_str()+4); si >> fromPort; si.ignore(1); si >> toPort; obj->setMap(fromPort, toPort); } } private: MidiMapper *obj; }; } void MidiMapperChoiceHandler::load(std::istream &in, SerializableLoadInfo &info) { m->reset(); FileBlockParser parser; FileItemParser_Map itemParser(m); parser.add(&itemParser); parser.parse(in, info); } /****************************************************************************** * DestinationChoiceHandler class *****************************************************************************/ DestinationChoiceHandler::DestinationChoiceHandler(TSE3::Ins::Destination *d, TSE3::MidiScheduler *ms) : ChoiceHandler("Destination"), d(d), ms(ms) { } DestinationChoiceHandler::~DestinationChoiceHandler() { } void DestinationChoiceHandler::save(std::ostream &out, int i) const { out << indent(i) << "{\n"; out << indent(i+1) << "NoInstruments:" << d->numInstruments() << "\n"; for (size_t ins = 0; ins < d->numInstruments(); ++ins) { out << indent(i+1) << "Instrument\n" << indent(i+1) << "{\n" << indent(i+2) << "Title:" << d->instrument(ins)->title() << "\n" << indent(i+2) << "Filename:" << d->instrument(ins)->filename() << "\n" << indent(i+1) << "}\n"; } for (size_t port = 0; port < ms->numPorts(); ++port) { out << indent(i+1) << "AllChannels:" << port << ","; if (d->allChannels(port)) { out << "Yes\n"; TSE3::Ins::Instrument *ins = d->port(port); out << indent(i+1) << "AllChannelsPort:" << port << ","; if (ins) { out << ins->title() << "\n"; } else { out << "\n"; } } else { out << "No\n"; for (size_t ch = 0; ch < 16; ++ch) { if (d->channel(port, ch)) { out << indent(i+1) << "Channel:" << port << "," << ch << "," << d->channel(port, ch)->title() << "\n"; } } } } out << indent(i) << "}\n"; } namespace { /** * Loads the Destination "AllChannels" data item. */ class FileItemParser_AllChannels : public FileItemParser { public: FileItemParser_AllChannels(TSE3::Ins::Destination *d) : d(d) {} void parse(const std::string &data) { size_t channel; std::istringstream si(data); si >> channel; si.ignore(1); std::string s; getline(si ,s); d->setPort(channel, d->instrument(s)); } private: TSE3::Ins::Destination *d; }; /** * Loads the Destination "Channel" data item. */ class FileItemParser_Channel : public FileItemParser { public: FileItemParser_Channel(TSE3::Ins::Destination *d) : d(d) {} void parse(const std::string &data) { size_t port, channel; std::istringstream si(data); si >> port; si.ignore(1); si >> channel; si.ignore(1); std::string s; getline(si ,s); d->setChannel(port, channel, d->instrument(s)); } private: TSE3::Ins::Destination *d; }; class InstrumentLoader : public Serializable { public: InstrumentLoader(Ins::Destination *d) : d(d) {} virtual void load(std::istream &in, SerializableLoadInfo &info); void setTitle(const std::string &t) { title = t; } void setFilename(const std::string &f) { filename = f; } private: TSE3::Ins::Destination *d; std::string title; std::string filename; }; void InstrumentLoader::load(std::istream &in, SerializableLoadInfo &info) { FileItemParser_String t(this, &InstrumentLoader::setTitle); FileItemParser_String f(this, &InstrumentLoader::setFilename); FileBlockParser parser; parser.add("Title", &t); parser.add("Filename", &f); parser.parse(in, info); if (!title.empty() && !filename.empty()) { Ins::Instrument *ins = new Ins::Instrument(title, filename); d->addInstrument(ins); } } } void DestinationChoiceHandler::load(std::istream &in, SerializableLoadInfo &info) { // clear all instruments if (d->numInstruments()) { // XXX clean instruments } FileItemParser_AllChannels ac(d); FileItemParser_Channel c(d); InstrumentLoader ins(d); FileBlockParser parser; parser.add("AllChannelsPort", &ac); parser.add("Channel", &c); parser.add("Instrument", &ins); parser.parse(in, info); } tse3-0.3.1/src/tse3/app/TrackSelection.cpp0000644000175700001440000001240710271145574015172 00000000000000/* * @(#)TrackSelection.cpp 3.00 17 January 2001 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/app/TrackSelection.h" #include "tse3/Song.h" #include "tse3/Track.h" #include using namespace TSE3; using namespace TSE3::App; TrackSelection::TrackSelection() : tracksValid(false), minTrack(0), maxTrack(0) { } TrackSelection::TrackSelection(const TrackSelection &t) : TSE3::Listener(), TSE3::Listener(), TSE3::Notifier() { // Copy data members tracks = t.tracks; tracksValid = t.tracksValid; minTrack = t.minTrack; maxTrack = t.maxTrack; // Listen to each Track iterator_t i = tracks.begin(); while (i != tracks.end()) { Listener::attachTo(*i); ++i; } } TrackSelection::~TrackSelection() { // Detach from current Tracks while (tracks.size()) { removeTrack(tracks.front()); } } bool TrackSelection::isSelected(TSE3::Track *track) const { std::vector::const_iterator i = find(tracks.begin(), tracks.end(), track); return i != tracks.end(); } void TrackSelection::select(TSE3::Track *track, bool add) { if (!add) { clear(); } addTrack(track); } void TrackSelection::deselect(TSE3::Track *track) { removeTrack(track); } void TrackSelection::clear() { minTrack = maxTrack = 0; tracksValid = false; while (tracks.size()) { Track *t = *tracks.begin(); Listener::detachFrom(t); tracks.erase(tracks.begin()); notify(&TrackSelectionListener::TrackSelection_Selected, t, false); } recalculateEnds(); } void TrackSelection::selectAll(TSE3::Song *song) { for (size_t t = 0; t < song->size(); ++t) { addTrack((*song)[t]); } } void TrackSelection::invert(TSE3::Song *song) { for (size_t t = 0; t < song->size(); ++t) { TSE3::Track * const track = (*song)[t]; if (isSelected(track)) { removeTrack(track); } else { addTrack(track); } } } TrackSelection &TrackSelection::operator=(const TrackSelection &p) { // Detach from current Tracks while (tracks.size()) { Track *track = tracks.front(); removeTrack(track); } // Copy data members tracks = p.tracks; tracksValid = p.tracksValid; minTrack = p.minTrack; maxTrack = p.maxTrack; // Listen to each Track iterator_t i = tracks.begin(); while (i != tracks.end()) { Listener::attachTo(*i); notify(&TrackSelectionListener::TrackSelection_Selected, *i, true); ++i; } return *this; } void TrackSelection::addTrack(TSE3::Track *track) { if (track->parent() && find(tracks.begin(), tracks.end(), track) == tracks.end()) { tracks.push_back(track); Listener::attachTo(track); size_t trackno = track->parent()->index(track); if (!tracksValid || trackno < minTrack->parent()->index(minTrack)) { minTrack = track; } if (!tracksValid || trackno > maxTrack->parent()->index(maxTrack)) { maxTrack = track; tracksValid = true; } notify(&TrackSelectionListener::TrackSelection_Selected, track, true); } } void TrackSelection::removeTrack(TSE3::Track *track) { std::vector::iterator i = find(tracks.begin(), tracks.end(), track); if (i != tracks.end()) { Listener::detachFrom(track); tracks.erase(i); recalculateEnds(); notify(&TrackSelectionListener::TrackSelection_Selected, track, false); } } void TrackSelection::recalculateEnds() { minTrack = maxTrack = 0; tracksValid = false; std::vector::iterator i = tracks.begin(); while (i != tracks.end()) { if (!minTrack) { // Only happens 1st time round the loop minTrack = maxTrack = *i; tracksValid = true; } else { if ((*i)->parent()->index(*i) < minTrack->parent()->index(minTrack)) { minTrack = *i; } if ((*i)->parent()->index(*i) > maxTrack->parent()->index(maxTrack)) { maxTrack = *i; } } ++i; } } void TrackSelection::Track_Reparented(Track *track) { if (!track->parent()) { removeTrack(track); } } void TrackSelection::Notifier_Deleted(Track *track) { removeTrack(track); } void TrackSelection::PartSelection_Selected(PartSelection *, TSE3::Part *, bool selected) { if (selected) { clear(); } } tse3-0.3.1/src/tse3/app/PartDisplay.cpp0000644000175700001440000000451510271145574014515 00000000000000/* * @(#)PartDisplay.cpp 3.00 25 May 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/app/PartDisplay.h" #include "tse3/app/Application.h" #include "tse3/DisplayParams.h" #include "tse3/Part.h" #include "tse3/Phrase.h" using namespace TSE3; using namespace TSE3::App; PartDisplay::PartDisplay(Part *p, PresetColours *pc) : p(p), preset(pc), _calculated(false) { } void PartDisplay::calculate() { _useColour = false; _r = 255; _g = 255; _b = 255; Phrase *phr = p->phrase(); DisplayParams *d = p->displayParams(); DisplayParams *phrd = phr ? phr->displayParams() : 0; if (d->style() != DisplayParams::None) { if (d->style() == DisplayParams::Default && phr) { // Get values from Phrase if (phrd->style() == DisplayParams::Colour) { phrd->colour(_r, _g, _b); _useColour = true; } else if (phrd->style() == DisplayParams::PresetColour && preset) { preset->colour(phrd->presetColour(), _r, _g, _b); _useColour = true; } } else if (d->style() != DisplayParams::Default) { // Values from Part: must be using colour _useColour = true; if (d->style() == DisplayParams::Colour) { d->colour(_r, _g, _b); _useColour = true; } else if (preset) { preset->colour(d->presetColour(), _r, _g, _b); _useColour = true; } } } _calculated = true; } bool PartDisplay::useColour() { if (!_calculated) { calculate(); } return _useColour; } void PartDisplay::colour(int &r, int &g, int &b) { if (!_calculated) { calculate(); } r = _r; g = _g; b = _b; } tse3-0.3.1/src/tse3/app/Modified.h0000644000175700001440000002047010271145574013444 00000000000000/* * @(#)app/Modified.h 1.00 27 October 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_APP_MODIFIED_H #define TSE3_APP_MODIFIED_H #include "tse3/listen/app/Modified.h" #include "tse3/Notifier.h" #include "tse3/listen/Song.h" #include "tse3/listen/Track.h" #include "tse3/listen/Part.h" #include "tse3/listen/DisplayParams.h" #include "tse3/listen/Phrase.h" #include "tse3/listen/PhraseList.h" #include "tse3/listen/FlagTrack.h" #include "tse3/listen/TimeSigTrack.h" #include "tse3/listen/TempoTrack.h" #include "tse3/listen/MidiFilter.h" #include "tse3/listen/MidiParams.h" #include namespace TSE3 { namespace App { /** * Listens to a @ref TSE3::Song and all its subcomponents, and * works out whether it has been 'modified' at all. * * You can change which @ref TSE3::Song is monitored at any * time. * * @short @ref TSE3::Song modified status monitor * @author Pete Goodliffe * @version 1.00 * @see TSE3 */ class Modified : public TSE3::Notifier, public TSE3::Listener, public TSE3::Listener, public TSE3::Listener, public TSE3::Listener, public TSE3::Listener, public TSE3::Listener, public TSE3::Listener, public TSE3::Listener, public TSE3::Listener, public TSE3::Listener, public TSE3::Listener { public: /** * Create a Modified object for the specified @ref TSE3::Song. * If no song is specified then this will return false from * @ref modified until a @ref TSE3::Song is set with * @ref setSong. * * @param song @ref TSE3::Song to monitor at first. */ Modified(TSE3::Song *song = 0); /** * Returns the @ref TSE3::Song currently being monitored, * or zero if no song is being monitored. * * @return @ref TSE3::Song being monitored * @see setSong */ TSE3::Song *song() const { return _song; } /** * Sets the @ref TSE3::Song currently being monitored. This * will clear the return value of @ref modified if it * is currently true. * * @see song */ void setSong(TSE3::Song *song); /** * Returns whether or not the @ref TSE3::Song has been * modified. * * @return Whether the @ref TSE3::Song has been modified. * @see setModified */ bool modified() const { return _modified; } /** * Causes the modified status to be set. If necessary, this * will emit a Modified_Changed notification. * * @param m New modified status * @see modified */ void setModified(bool modified = true); /** * @reimplemented */ virtual void Song_InfoAltered(Song *); /** * @reimplemented */ virtual void Song_FromAltered(Song *, Clock /*from*/); /** * @reimplemented */ virtual void Song_ToAltered(Song *, Clock /*to*/); /** * @reimplemented */ virtual void Song_TrackInserted(Song *, Track *); /** * @reimplemented */ virtual void Song_TrackRemoved(Song *, Track *, size_t); /** * @reimplemented */ virtual void Track_TitleAltered(Track *); /** * @reimplemented */ virtual void Track_PartInserted(Track *, Part *); /** * @reimplemented */ virtual void Track_PartRemoved(Track *, Part *); /** * @reimplemented */ virtual void Part_StartAltered(Part *, Clock /*start*/); /** * @reimplemented */ virtual void Part_EndAltered(Part *, Clock /*end*/); /** * @reimplemented */ virtual void Part_RepeatAltered(Part *, Clock /*repeat*/); /** * @reimplemented */ virtual void Part_PhraseAltered(Part *, Phrase * /*phrase*/); /** * @reimplemented */ virtual void PhraseList_Inserted(PhraseList *, Phrase * /*p*/); /** * @reimplemented */ virtual void PhraseList_Removed(PhraseList *, Phrase * /*p*/); /** * @reimplemented */ virtual void MidiParams_Altered(MidiParams *, int /*what*/); /** * @reimplemented */ virtual void DisplayParams_Altered(DisplayParams *); /** * @reimplemented */ virtual void EventTrack_EventAltered(EventTrack *, size_t); /** * @reimplemented */ virtual void EventTrack_EventInserted(EventTrack *, size_t); /** * @reimplemented */ virtual void EventTrack_EventErased(EventTrack *, size_t); /** * @reimplemented */ virtual void EventTrack_EventAltered(EventTrack *); /** * @reimplemented */ virtual void EventTrack_EventInserted(EventTrack *); /** * @reimplemented */ virtual void EventTrack_EventErased(EventTrack *); /** * @reimplemented */ virtual void EventTrack_EventAltered(EventTrack *); /** * @reimplemented */ virtual void EventTrack_EventInserted(EventTrack *); /** * @reimplemented */ virtual void EventTrack_EventErased(EventTrack *); /** * @reimplemented */ void MidiFilter_Altered(MidiFilter *, int /*what*/); private: void attachToTrack(TSE3::Track *track); void detachFromTrack(TSE3::Track *track); void attachToPart(TSE3::Part *part); void detachFromPart(TSE3::Part *part); TSE3::Song *_song; bool _modified; }; } } #endif tse3-0.3.1/src/tse3/app/Record.cpp0000644000175700001440000001034510271145574013475 00000000000000/* * @(#)Record.cpp 3.00 19 June 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/app/Record.h" #include "tse3/Song.h" #include "tse3/Transport.h" #include "tse3/PhraseEdit.h" #include "tse3/Error.h" #include "tse3/MidiFilter.h" #include "tse3/PhraseList.h" #include "tse3/Part.h" #include "tse3/Track.h" #include "tse3/MidiScheduler.h" #include "tse3/cmd/Part.h" #include "tse3/cmd/Phrase.h" #include "tse3/cmd/CommandHistory.h" #include "tse3/cmd/CommandGroup.h" using namespace TSE3; using namespace TSE3::App; /****************************************************************************** * Record class *****************************************************************************/ Record::Record(TSE3::Transport *t) : _transport(t), _phraseEdit(0), _startTime(-1), _endTime(-1), recording(false) { attachTo(_transport); } Record::~Record() { } void Record::start(TSE3::Song *s, TSE3::Track *t) { if (!recording && _phraseEdit) { reset(); } if (!recording && _transport->status() == TSE3::Transport::Resting) { _startTime = _transport->scheduler()->clock(); _phraseEdit = new TSE3::PhraseEdit(); _song = s; _track = t; TSE3::MidiFilter *f = t ? t->filter() : 0; _transport->record(_song, _startTime, _phraseEdit, f); recording = true; } else if (recording && _phraseEdit) { stop(); } } void Record::stop() { if (_phraseEdit && recording && _transport->status() == TSE3::Transport::Recording) { _transport->stop(); // This will cause us to get a notification } } void Record::reset() { delete _phraseEdit; _phraseEdit = 0; _startTime = -1; _endTime = -1; recording = false; } void Record::Transport_Status(TSE3::Transport *, int status) { if (_phraseEdit && status == TSE3::Transport::Resting && recording) { recording = false; _endTime = _transport->scheduler()->clock(); _phraseEdit->timeShift(-_startTime); _phraseEdit->tidy(_endTime-_startTime); if (_phraseEdit->size()) { notify(&RecordListener::Record_RecordingEnded, _song, _track); } else { delete _phraseEdit; _phraseEdit = 0; } } } void Record::insertPhrase(const std::string &title, bool replacePhrase, bool insertPart, int insertAction, TSE3::Cmd::CommandHistory *history) { TSE3::Phrase *existing = _song->phraseList()->phrase(title); if (existing && !replacePhrase) { throw TSE3::PhraseListError(PhraseNameExistsErr); } Phrase *phrase = 0; if (replacePhrase && existing) { Cmd::Phrase_Replace *cmd = new Cmd::Phrase_Replace(existing, _phraseEdit, _song); cmd->execute(); phrase = cmd->phrase(); if (history) { history->add(cmd); } else { delete cmd; } } else { Cmd::Phrase_Create *cmd = new Cmd::Phrase_Create(_song->phraseList(), _phraseEdit, title); cmd->execute(); phrase = cmd->phrase(); if (history) { history->add(cmd); } else { delete cmd; } } if (insertPart && _track) { TSE3::Part *part = new TSE3::Part(); part->setStartEnd(_startTime, _endTime); Cmd::CommandGroup *group = new Cmd::CommandGroup(); group->add(new Cmd::Part_Move(insertAction, part, _track)); group->add(new Cmd::Part_SetPhrase(part, phrase)); group->execute(); if (history) { history->add(group); } else { delete group; } } reset(); } tse3-0.3.1/src/tse3/app/PartDisplay.h0000644000175700001440000000467410271145574014170 00000000000000/* * @(#)app/PartDisplay.h 1.00 18 June 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_APP_PARTDISPLAY_H #define TSE3_APP_PARTDISPLAY_H namespace TSE3 { class Part; class PresetColours; namespace App { /** * The PartDisplay class handles interpretting a @ref TSE3::Part's * @ref TSE3::DisplayParams alongside it's child @ref TSE3::Phrase's * @ref TSE3::DisplayParams. * * The @ref TSE3::Part parameters take precidence over the * @ref TSE3::Phrase parameters. This class centralises the logic for * working out which parameter to use. * * The PartDisplay class uses the @ref Application's * @ref TSE3::PresetColours object if necessary to find a preset * colour value. * * @short Support class for @ref TSE3::Part display * @author Pete Goodliffe * @version 1.00 * @see TSE3 */ class PartDisplay { public: /** * You specify the @ref Part to display and the * @ref TSE3::PresetColours that applies. * * @param part @ref TSE3::Part to create DisplayParams for * @param pc @ref TSE3::PresetColours object to use */ PartDisplay(TSE3::Part *part, TSE3::PresetColours *pc = 0); /** * Returns whether to display this part in colour or not. */ bool useColour(); /** * Returns which colour to use on redraw. */ void colour(int &r, int &g, int &b); private: void calculate(); TSE3::Part *p; TSE3::PresetColours *preset; int _calculated; bool _useColour; int _r, _g, _b; }; } } #endif tse3-0.3.1/src/tse3/app/PartSelection.h0000644000175700001440000003271210271145574014502 00000000000000/* * @(#)app/PartSelection.h 1.00 18 June 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_APP_PARTSELECTION_H #define TSE3_APP_PARTSELECTION_H #include "tse3/listen/app/PartSelection.h" #include "tse3/Notifier.h" #include "tse3/Part.h" #include "tse3/Midi.h" #include "tse3/listen/app/TrackSelection.h" #include #include namespace TSE3 { class Phrase; class Song; class Track; namespace App { /** * The PartSelection class allows an Application to provide the facility * to 'select' one or more @ref TSE3::Part in a @ref TSE3::Song. These * @ref TSE3::Part objects must be held in a @ref TSE3::Track. As soon * as a @ref TSE3::Part is removed from a @ref TSE3::Track, it is * removed from the selection. * * This behviour is useful when using the command history system in * the @ref TSE3::Cmd namespace where undoing a @ref TSE3::Part add, * for example, may cause a selected Part to be removed from the @ref * TSE3::Song. * * Internally, the Parts are held in an STL vector of type . * In order to get access to the contents of this vector, access * is provided to it's iterator. * * If you are using the iterators and performing any operations that * may affect the PartSelection (i.e. removing a @ref TSE3::Part from * it's @ref TSE3::Track and reinserting it elsewhere) then you * will invalidate the iterator. * * A method of avoiding this would be to, rather than iterate over each * Part, to remove a Part from the head of the list, work on it, * and place it into a second PartSelection. Do this for each Part * in the PartSelection, and when finished, copy the new PartSelection * into the old one. * * @sect Interaction with @ref TrackSelection * * You may want to use this selection utility in connection with the * @ref TrackSelection class to ensure that the user has only selected * one type of object at any time. * * To facilitate this, the PartSelection is a * @ref TrackSelectionListener. You can attach it to a * @ref TrackSelection object, and whenever the @ref TrackSelection * has a @ref TSE3::Track selected the PartSelection will be cleared. * * You will need to use an attach like this: *

             *   PartSelection   ps;
             *   TrackSelection *ts = someTrackSelection();
             *   ps.TSE3::Listener::attachTo(ts);
             * 
    * * @short Support class for selecting one or more @ref Part object * @author Pete Goodliffe * @version 1.00 * @see TSE3 */ class PartSelection : public TSE3::Listener, public TSE3::Listener, public TSE3::Notifier { public: /** * The PartSelection begins with no @ref Part selected. */ PartSelection(); ~PartSelection(); PartSelection(const PartSelection &); /************************************************************** * Setting the selection *************************************************************/ /** * Returns the earliest start time of any @ref TSE3::Part in the * selection. * * If there is no selection, this will return -1. * * @return Earliest @ref TSE3::Part start time */ TSE3::Clock earliest() const { return _earliest; } /** * Returns the latest end time of any @ref TSE3::Part in the * selection. * * If there is no selection, this will return -1. * * @return Latest @ref TSE3::Part start time */ TSE3::Clock latest() const { return _latest; } /** * Returns the lowest @ref TSE3::Track index that any selected * @ref TSE3::Part is in. * * If there is no selection, this will return 0. * * @return Lowest @ref TSE3::Track index. */ size_t minTrack() const { return _minTrack; } /** * Returns the greatest @ref TSE3::Track index that any selected * @ref TSE3::Part is in. * * If there is no selection, this will return 0. * * @return Greatest @ref TSE3::Track index. */ size_t maxTrack() const { return _maxTrack; } /** * Selects a @ref TSE3::Part. * * If the @ref TSE3::Part is not in a @ref TSE3::Track, it * will not be selected. * * @param part The @ref Part to select * @param add Whether to add the @ref TSE3::Part to the * selection (true) or to replace the current * selection (false). */ void select(TSE3::Part *part, bool add); /** * Deselects a @ref Part. If the @ref Part is not selected, * then nothing will happen. * * @param part The @ref Part to deselect */ void deselect(TSE3::Part *part); /** * Clears the entire selection. */ void clear(); /** * Selects all the @ref TSE3::Part objects in the * given @ref TSE3::Song (this 'should' include any Parts * alreadys selected!). * * @param song @ref TSE3::Song whose @ref TSE3::Part objects * are all to be selected */ void selectAll(TSE3::Song *song); /** * Adds to the selection all the @ref TSE3::Part objects in the * given @ref TSE3::Track. * * @param track @ref TSE3::Track whose @ref TSE3::Part objects * are all to be selected */ void selectAll(TSE3::Track *track); /** * Inverts the selection for all the @ref TSE3::Part objects in * the given @ref TSE3::Song (i.e. all selected Parts are * deselected and all deselected Parts are selected). * * @param song @ref TSE3::Song whose @ref TSE3::Part objects * are all to be inverted */ void invert(TSE3::Song *song); /** * Adds to the selection all the Parts which have a section * lying either inside or outside the window between a * @p start time and an @p end time. * * @param song @ref TSE3::Song whose @ref TSE3::Part objects * are all to be operated on * @param start Start of selection window * @param end End of selection window * @param inside If true, select @ref TSE3::Part objects between * @p start and @p end, else select Parts NOT * between these times */ void selectBetween(TSE3::Song *song, TSE3::Clock start, TSE3::Clock end, bool inside = true); /** * Adds to the selection all the Parts which have a section * lying either inside or outside the window between a * @p start time and an @p end time. * * @param track @ref TSE3::Track whose @ref TSE3::Part objects * are all to be operated on * @param start Start of selection window * @param end End of selection window * @param inside If true, select @ref TSE3::Part objects between * @p start and @p end, else select Parts NOT * between these times */ void selectBetween(TSE3::Track *track, TSE3::Clock start, TSE3::Clock end, bool inside = true); /** * Copy PartSelection contents. */ PartSelection &operator=(const PartSelection &); /************************************************************** * Access to the selected Parts *************************************************************/ /** * Returns how many @ref TSE3::Part objects are selected. * * @return No of selected @ref TSE3::Part objects */ size_t size() const { return parts.size(); } /** * Returns whether a particular @ref TSE3::Part is selected. * * @param part The @ref TSE3::Part to run selection test on * @return Whether the @ref TSE3::Part is selected */ bool isSelected(TSE3::Part *part) const; typedef std::vector::const_iterator iterator_t; /** * Returns the first item in the PartSelection, or zero if * there are no selected Parts. * * @return First selected @ref TSE3::Part */ Part *front() const { return parts.size() ? parts.front() : 0; } /** * Returns the last item in the PartSelection, or zero if * there are no selected Parts. * * @return Last selected @ref TSE3::Part */ Part *back() const { return parts.size() ? parts.back() : 0; } /** * Returns an iterator pointing to the first @ref TSE3::Part in * this selection. * * @return Iterator pointing to first selected @ref TSE3::Part */ iterator_t begin() const { return parts.begin(); } /** * Returns an iterator pointing to the last @ref TSE3::Part in * this selection. * * @return Iterator pointing to last selected @ref TSE3::Part */ iterator_t end() const { return parts.end(); } /** * @reimplemented */ virtual void Part_StartAltered(Part *, Clock start); /** * @reimplemented */ virtual void Part_EndAltered(Part *, Clock end); /** * @reimplemented */ virtual void Part_Reparented(Part *); /** * @reimplemented */ virtual void Notifier_Deleted(Part *); /** * @reimplemented */ virtual void TrackSelection_Selected (TrackSelection *, TSE3::Track *, bool); private: /** * Adds the @ref TSE3::Part to the vector and attaches the * PartSelection to it, then updates the _earliest and _latest * values. */ void addPart(TSE3::Part *part); /** * Removes the @ref TSE3::Part from the vector and detaches the * PartSelection from it, then updates the _earliest and _latest * values. */ void removePart(TSE3::Part *part); /** * Recalculates _earliest and _latest; */ void recalculateEnds(); std::vector parts; bool timesValid; TSE3::Clock _earliest; TSE3::Clock _latest; bool tracksValid; size_t _minTrack; size_t _maxTrack; }; } } #endif tse3-0.3.1/src/tse3/app/Application.h0000644000175700001440000002266610302616255014172 00000000000000/* * @(#)app/Application.h 1.00 16 Nov 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_APP_APPLICATION_H #define TSE3_APP_APPLICATION_H #include "tse3/Song.h" #include #include #include #include namespace TSE3 { class Metronome; class Transport; class MidiScheduler; class MidiSchedulerFactory; class PresetColours; namespace Cmd { class CommandHistory; } namespace Ins { class Destination; } /** * The App namespace contains classes that use the @ref TSE3 * API, and provide a level of application support - including facilities * such as choices file saving. * * @short @ref TSE3 library application support * @author Pete Goodliffe * @version 3.00 * @see TSE3 */ namespace App { class ChoicesManager; class Record; /** * This class provides the GUI independant core functionality of a * sequencer application based upon the @ref TSE3 library. * * The functionality provided by this class includes: * @li Choices file saved to user's directory * @li Management of the lifetimes of the common TSE3 objects * * This class is used as a singleton. * * @short Support class providing core TSE3 application functionality * @author Pete Goodliffe * @version 1.00 * @see TSE3 */ class Application : public TSE3::Listener { public: /** * Create the application. * * @param appname The appname supplied is the name of this * application. Any use of the application * name should access it from this object in * future. * @param appversion A string containing the application * version number. * @param msf A factory use to generate a * @ref MidiScheduler. * @param choicesFile The name of the file that choices are * loaded from on startup, and saved to by * default. You will conventionally want * this to be something like "$HOME/.tse3". * If you specify no choicesFile then no * default choices loading/saving will be * performed. */ Application(const std::string &appname, const std::string &appversion, TSE3::MidiSchedulerFactory *msf, const std::string &choicesFile = ""); /** * Any @ref Song objects 'managed' by the application will * be deleted. */ ~Application(); /** * Returns the application's name. * * If you need to quote the application's name at some * point in your code, use the Application::name() method, * rather than hardcoding a string constant. */ const std::string &appName() const { return _appname; } /** * Returns the application's version. * * If you need to quote the application's version at some * point in your code, use the Application::name() method, * rather than hardcoding a string constant. */ const std::string &appVersion() const { return _appversion; } /************************************************************** * Access to the main non-Song TSE3 components *************************************************************/ /** * Returns a pointer to the @ref Metronome object used in this * application. */ TSE3::Metronome *metronome() const { return _metronome; } /** * Returns a pointer to the @ref Transport object used in this * application. */ TSE3::Transport *transport() const { return _transport; } /** * Returns a pointer to the @ref MidiScheduler object used in * this application. This has been created from the * @ref MidiSchedulerFactory object passed to the constructor. */ TSE3::MidiScheduler *scheduler() const { return _scheduler; } /** * Returns a pointer to the @ref ChoicesManager. */ ChoicesManager *choicesManager() const { return _cm; } /** * Returns a pointer to the Application's @ref Record object. * This object is only created when it's needed. */ Record *record() const; /** * Returns the @ref TSE3::Ins::Destintation object used in this * application. */ TSE3::Ins::Destination *destination() const { return _destination; } /** * Returns the @ref TSE3::PresetColours object used in this * application. */ TSE3::PresetColours *presetColours() const { return _presetColours; } /************************************************************** * Configuration of the application behaviour *************************************************************/ /** * Sets whether choices are saved on destruction or not. * * @see setSaveChoicesOnDestroy */ bool saveChoicesOnDestroy() const { return _saveChoicesOnDestroy; } /** * Returns whether choices are saved on destruction. * * @see saveChoicesOnDestroy */ void setSaveChoicesOnDestroy(bool s); /************************************************************** * Functionality *************************************************************/ /** * Saves the current choices to the given filename. If no * filename is supplied then the default one is used. */ void saveChoices(const std::string &filename = ""); /** * Add a new @ref TSE3::Song to the Application object. If you * don't specify a @ref TSE3::Song, then a new @ref TSE3::Song * will be created. * * You can remove the @ref TSE3::Song by simply deleting it. * * @param song @ref TSE3::Song to add, or zero to create a * new one. * @return Pointer to the @ref TSE3::Song that has been added * (useful if @p song was zero). */ TSE3::Song *addSong(TSE3::Song *song = 0); /** * Returns the number of @ref TSE3::Song objects being * managed by this Application. */ size_t numSongs() const; /** * Returns the @ref CommandHistory object associated with this * @ref Song. * * @param song @ref TSE3::Song to get history object for. */ TSE3::Cmd::CommandHistory *history(TSE3::Song *song); /** * @reimplemented */ virtual void Notifier_Deleted(TSE3::Song *song); protected: std::string _appname; std::string _appversion; std::string _choicesFile; TSE3::Metronome *_metronome; TSE3::Transport *_transport; TSE3::MidiScheduler *_scheduler; ChoicesManager *_cm; Record *_record; TSE3::Ins::Destination *_destination; TSE3::PresetColours *_presetColours; bool _saveChoicesOnDestroy; std::vector songs; std::map histories; }; } } #endif tse3-0.3.1/src/tse3/app/TrackSelection.h0000644000175700001440000002264210271145574014641 00000000000000/* * @(#)app/TrackSelection.h 1.00 17 January 2001 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_APP_TRACKSELECTION_H #define TSE3_APP_TRACKSELECTION_H #include "tse3/listen/app/TrackSelection.h" #include "tse3/Notifier.h" #include "tse3/Track.h" #include "tse3/listen/app/PartSelection.h" #include #include namespace TSE3 { class Phrase; class Song; class Track; namespace App { /** * The TrackSelection class allows an Application to provide the * facility to 'select' one or more @ref TSE3::Track in a * @ref TSE3::Song. These @ref TSE3::Track objects must be held in a * @ref TSE3::Song. As soon as a @ref TSE3::Track is removed from a * @ref TSE3::Song, it is removed from the selection. * * This behviour is useful when using the command history system in * the @ref TSE3::Cmd namespace where undoing a @ref TSE3::Track add, * for example, may cause a selected Track to be removed from the @ref * TSE3::Song. * * Internally, the Tracks are held in an STL vector of type . * In order to get access to the contents of this vector, access * is provided to it's iterator. * * If you are using the iterators and performing any operations that * may affect the TrackSelection (i.e. removing a @ref TSE3::Track from * it's @ref TSE3::Track and reinserting it elsewhere) then you * will invalidate the iterator. * * A method of avoiding this would be to, rather than iterate over each * Track, to remove a Track from the head of the list, work on it, * and place it into a second TrackSelection. Do this for each Track * in the TrackSelection, and when finished, copy the new TrackSelection * into the old one. * * @sect Interaction with @ref PartSelection * * You may want to use this selection utility in connection with the * @ref PartSelection class to ensure that the user has only selected * one type of object at any time. * * To facilitate this, the TrackSelection is a * @ref PartSelectionListener. You can attach it to a * @ref PartSelection object, and whenever the @ref PartSelection * has a @ref TSE3::Part selected the TrackSelection will be cleared. * * You will need to use an attach like this: *
             *   TrackSelection  ts;
             *   PartSelection  *ps = somePartSelection();
             *   ts.TSE3::Listener::attachTo(ps);
             * 
    * * @short Support class for selecting one or more @ref Track object * @author Pete Goodliffe * @version 1.00 * @see TSE3 */ class TrackSelection : public TSE3::Listener, public TSE3::Listener, public TSE3::Notifier { public: /** * The TrackSelection begins with no @ref Track selected. */ TrackSelection(); ~TrackSelection(); TrackSelection(const TrackSelection &); /************************************************************** * Setting the selection *************************************************************/ /** * Selects a @ref TSE3::Track. * * If the @ref TSE3::Track is not in a @ref TSE3::Song, it * will not be selected. * * @param track The @ref Track to select * @param add Whether to add the @ref TSE3::Track to the * selection (true) or to replace the current * selection (false). */ void select(TSE3::Track *track, bool add); /** * Deselects a @ref Track. If the @ref Track is not selected, * then nothing will happen. * * @param track The @ref Track to deselect */ void deselect(TSE3::Track *track); /** * Clears the entire selection. */ void clear(); /** * Selects all the @ref TSE3::Track objects in the * given @ref TSE3::Song (this 'should' include any Tracks * alreadys selected!). * * @param song @ref TSE3::Song whose @ref TSE3::Track objects * are all to be selected */ void selectAll(TSE3::Song *song); /** * Inverts the selection for all the @ref TSE3::Track objects in * the given @ref TSE3::Song (i.e. all selected Tracks are * deselected and all deselected Tracks are selected). * * @param song @ref TSE3::Song whose @ref TSE3::Track objects * are all to be inverted */ void invert(TSE3::Song *song); /** * Copy TrackSelection contents. */ TrackSelection &operator=(const TrackSelection &); /************************************************************** * Access to the selected Tracks *************************************************************/ /** * Returns how many @ref TSE3::Track objects are selected. * * @return No of selected @ref TSE3::Track objects */ size_t size() const { return tracks.size(); } /** * Returns whether a particular @ref TSE3::Track is selected. * * @param track The @ref TSE3::Track to run selection test on * @return Whether the @ref TSE3::Track is selected */ bool isSelected(TSE3::Track *track) const; typedef std::vector::const_iterator iterator_t; /** * Returns the first item in the TrackSelection, or zero if * there are no selected Tracks. * * @return First selected @ref TSE3::Track */ Track *front() const { return tracks.size() ? tracks.front() : 0; } /** * Returns the last item in the TrackSelection, or zero if * there are no selected Tracks. * * @return Last selected @ref TSE3::Track */ Track *back() const { return tracks.size() ? tracks.back() : 0; } /** * Returns an iterator pointing to the first @ref TSE3::Track * in this selection. * * @return Iterator pointing to first selected @ref TSE3::Track */ iterator_t begin() const { return tracks.begin(); } /** * Returns an iterator pointing to the last @ref TSE3::Track in * this selection. * * @return Iterator pointing to last selected @ref TSE3::Track */ iterator_t end() const { return tracks.end(); } /** * @reimplemented */ virtual void Track_Reparented(Track *); /** * @reimplemented */ virtual void Notifier_Deleted(Track *); /** * @reimplemented */ virtual void PartSelection_Selected (PartSelection *, TSE3::Part *, bool); private: /** * Adds the @ref TSE3::Track to the vector and attaches the * TrackSelection to it. */ void addTrack(TSE3::Track *track); /** * Removes the @ref TSE3::Track from the vector and detaches the * TrackSelection from it. */ void removeTrack(TSE3::Track *part); /** * Recalculates minTrack and maxTrack; */ void recalculateEnds(); std::vector tracks; bool tracksValid; TSE3::Track *minTrack; TSE3::Track *maxTrack; }; } } #endif tse3-0.3.1/src/tse3/app/Modified.cpp0000644000175700001440000001466410271145574014007 00000000000000/* * @(#)Modified.cpp 3.00 27 October 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/app/Modified.h" #include "tse3/Mutex.h" #include "tse3/Song.h" #include "tse3/Track.h" #include "tse3/Part.h" #include "tse3/DisplayParams.h" #include "tse3/Phrase.h" #include "tse3/PhraseList.h" #include "tse3/FlagTrack.h" #include "tse3/TimeSigTrack.h" #include "tse3/TempoTrack.h" #include "tse3/MidiFilter.h" #include "tse3/MidiParams.h" using namespace TSE3; using namespace TSE3::App; Modified::Modified(TSE3::Song *s) :_song(0), _modified(false) { setSong(s); } void Modified::setModified(bool m) { if (_modified != m) { _modified = m; notify(&ModifiedListener::Modified_Changed); } } void Modified::setSong(TSE3::Song *s) { Impl::CritSec cs; // 1. Detach from the current song if (_song) { Listener::detachFrom(_song); Listener::detachFrom(_song->flagTrack()); Listener::detachFrom(_song->timeSigTrack()); Listener::detachFrom(_song->tempoTrack()); Listener::detachFrom(_song->phraseList()); for (size_t trk = 0; trk < _song->size(); trk++) { detachFromTrack((*_song)[trk]); } for (size_t phr = 0; phr < _song->phraseList()->size(); phr++) { Listener::detachFrom((*(_song->phraseList()))[phr]); Listener::detachFrom ((*(_song->phraseList()))[phr]->displayParams()); } } // 2. Attach to new song if (s) { Listener::attachTo(s); Listener::attachTo(s->flagTrack()); Listener::attachTo(s->timeSigTrack()); Listener::attachTo(s->tempoTrack()); Listener::attachTo(s->phraseList()); for (size_t trk = 0; trk < s->size(); trk++) { attachToTrack((*s)[trk]); } for (size_t phr = 0; phr < s->phraseList()->size(); phr++) { Listener::attachTo((*(s->phraseList()))[phr]); Listener::attachTo ((*(s->phraseList()))[phr]->displayParams()); } } // 3. Set new values _song = s; setModified(false); } void Modified::attachToTrack(TSE3::Track *track) { Impl::CritSec cs; Listener::attachTo(track); Listener::attachTo(track->params()); Listener::attachTo(track->filter()); for (size_t prt = 0; prt < track->size(); prt++) { attachToPart((*track)[prt]); } } void Modified::detachFromTrack(TSE3::Track *track) { Impl::CritSec cs; for (size_t prt = 0; prt < track->size(); prt++) { detachFromPart((*track)[prt]); } Listener::detachFrom(track); Listener::detachFrom(track->params()); Listener::detachFrom(track->filter()); } void Modified::attachToPart(TSE3::Part *part) { Impl::CritSec cs; Listener::attachTo(part); Listener::attachTo(part->params()); Listener::attachTo(part->filter()); Listener::attachTo(part->displayParams()); } void Modified::detachFromPart(TSE3::Part *part) { Impl::CritSec cs; Listener::detachFrom(part->params()); Listener::detachFrom(part->filter()); Listener::detachFrom(part->displayParams()); Listener::detachFrom(part); } void Modified::Song_InfoAltered(Song *) { setModified(); } void Modified::Song_FromAltered(Song *, Clock /*from*/) { setModified(); } void Modified::Song_ToAltered(Song *, Clock /*to*/) { setModified(); } void Modified::Song_TrackInserted(Song *, Track *track) { setModified(); attachToTrack(track); } void Modified::Song_TrackRemoved(Song *, Track *track, size_t) { setModified(); detachFromTrack(track); } void Modified::Track_TitleAltered(Track *) { setModified(); } void Modified::Track_PartInserted(Track *, Part *part) { setModified(); attachToPart(part); } void Modified::Track_PartRemoved(Track *, Part *part) { setModified(); detachFromPart(part); } void Modified::Part_StartAltered(Part *, Clock /*start*/) { setModified(); } void Modified::Part_EndAltered(Part *, Clock /*end*/) { setModified(); } void Modified::Part_RepeatAltered(Part *, Clock /*repeat*/) { setModified(); } void Modified::Part_PhraseAltered(Part *, Phrase * /*phrase*/) { setModified(); } void Modified::PhraseList_Inserted(PhraseList *, Phrase *phrase) { setModified(); Listener::attachTo(phrase); } void Modified::PhraseList_Removed(PhraseList *, Phrase *phrase) { setModified(); Listener::detachFrom(phrase); } void Modified::MidiParams_Altered(MidiParams *, int /*what*/) { setModified(); } void Modified::DisplayParams_Altered(DisplayParams *) { setModified(); } void Modified::EventTrack_EventAltered(EventTrack *, size_t) { setModified(); } void Modified::EventTrack_EventInserted(EventTrack *, size_t) { setModified(); } void Modified::EventTrack_EventErased(EventTrack *, size_t) { setModified(); } void Modified::EventTrack_EventAltered(EventTrack *) { setModified(); } void Modified::EventTrack_EventInserted(EventTrack *) { setModified(); } void Modified::EventTrack_EventErased(EventTrack *) { setModified(); } void Modified::EventTrack_EventAltered(EventTrack *) { setModified(); } void Modified::EventTrack_EventInserted(EventTrack *) { setModified(); } void Modified::EventTrack_EventErased(EventTrack *) { setModified(); } void Modified::MidiFilter_Altered(MidiFilter *, int /*what*/) { setModified(); } tse3-0.3.1/src/tse3/app/Application.cpp0000644000175700001440000000715310271145574014525 00000000000000/* * @(#)Application.cpp 3.00 25 May 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/app/Application.h" #include "tse3/app/Record.h" #include "tse3/app/Choices.h" #include "tse3/Metronome.h" #include "tse3/Transport.h" #include "tse3/Error.h" #include "tse3/Song.h" #include "tse3/DisplayParams.h" #include "tse3/cmd/CommandHistory.h" #include "tse3/util/MidiScheduler.h" #include "tse3/ins/Destination.h" #include using namespace TSE3; using namespace TSE3::App; Application::Application(const std::string &a, const std::string &v, MidiSchedulerFactory *msf, const std::string &cf) : _appname(a), _appversion(v), _choicesFile(cf), _record(0) { // Create aggregate objects _metronome = new Metronome; try { _scheduler = msf->createScheduler(); } catch (const TSE3::Error &e) { std::cerr << "TSE3: Failed to create MidiScheduler, " << "creating NullMidiScheduler instead\n"; _scheduler = new Util::NullMidiScheduler(); } _transport = new Transport(_metronome, _scheduler); _cm = new ChoicesManager; _destination = new Ins::Destination(); _presetColours = new PresetColours; // Set up Application object _saveChoicesOnDestroy = false; // Populate the ChoicesManager _cm->add(new ApplicationChoiceHandler(this)); _cm->add(new MetronomeChoiceHandler(_metronome)); _cm->add(new TransportChoiceHandler(_transport)); _cm->add(new DestinationChoiceHandler(_destination, _scheduler)); // Load any application choices that may have been saved previously if(!_choicesFile.empty()) { _cm->load(_choicesFile); } } Application::~Application() { if (_saveChoicesOnDestroy) { _cm->save(_choicesFile); } delete _presetColours; delete _destination; delete _cm; // this deletes ChoicesHandlers too delete _transport; delete _metronome; delete _scheduler; } Record *Application::record() const { if (!_record) { Application *me = const_cast(this); me->_record = new Record(_transport); } return _record; } void Application::setSaveChoicesOnDestroy(bool s) { _saveChoicesOnDestroy = s; // notify } void Application::saveChoices(const std::string &filename) { if (filename != "") { _cm->save(filename); } else if (_choicesFile != "") { _cm->save(_choicesFile); } } TSE3::Song *Application::addSong(TSE3::Song *song) { if (!song) { song = new TSE3::Song(); } songs.push_back(song); histories[song] = new TSE3::Cmd::CommandHistory(); return song; } size_t Application::numSongs() const { return songs.size(); } TSE3::Cmd::CommandHistory *Application::history(TSE3::Song *song) { if (find(songs.begin(), songs.end(), song) == songs.end()) { return 0; } return histories[song]; } void Application::Notifier_Deleted(TSE3::Song *song) { if (find(songs.begin(), songs.end(), song) != songs.end()) { Cmd::CommandHistory *history = histories[song]; histories.erase(song); delete history; } } tse3-0.3.1/src/tse3/app/Makefile.am0000644000175700001440000000113010271145574013577 00000000000000tse3apph_HEADERS = Application.h Choices.h Modified.h PartSelection.h PartDisplay.h Record.h TrackSelection.h tse3apphdir = $(pkgincludedir)/app noinst_LTLIBRARIES = libtse3app.la libtse3app_la_SOURCES = Application.cpp Choices.cpp Modified.cpp PartSelection.cpp PartDisplay.cpp Record.cpp TrackSelection.cpp DISTCLEANFILES = ./.deps/* ./.deps/.P INCLUDES = -I$(top_srcdir)/src #noinst_PROGRAMS = test #test_SOURCES = test.cpp #test_LDFLAGS = -L$(top_builddir)/src/tse3 -L$(top_builddir)/src/tse3/platform -L$(top_builddir)/src/tse3/application #test_LDADD = -ltse3 -ltse3_OSS -ltse3_application tse3-0.3.1/src/tse3/app/Makefile.in0000644000175700017570000004054010302622112013612 00000000000000# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ SOURCES = $(libtse3app_la_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/tse3/app DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(tse3apph_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libtse3app_la_LIBADD = am_libtse3app_la_OBJECTS = Application.lo Choices.lo Modified.lo \ PartSelection.lo PartDisplay.lo Record.lo TrackSelection.lo libtse3app_la_OBJECTS = $(am_libtse3app_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libtse3app_la_SOURCES) DIST_SOURCES = $(libtse3app_la_SOURCES) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(tse3apphdir)" tse3apphHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(tse3apph_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPP_MM = @CPP_MM@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ HAVE_ALSA_FALSE = @HAVE_ALSA_FALSE@ HAVE_ALSA_TRUE = @HAVE_ALSA_TRUE@ HAVE_ARTS_FALSE = @HAVE_ARTS_FALSE@ HAVE_ARTS_TRUE = @HAVE_ARTS_TRUE@ HAVE_OSS_FALSE = @HAVE_OSS_FALSE@ HAVE_OSS_TRUE = @HAVE_OSS_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTALL_TSE3_DOC_FALSE = @INSTALL_TSE3_DOC_FALSE@ INSTALL_TSE3_DOC_TRUE = @INSTALL_TSE3_DOC_TRUE@ LDFLAGS = @LDFLAGS@ LIBARTS = @LIBARTS@ LIBASOUND = @LIBASOUND@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TSE3_ALSA_PREFIX = @TSE3_ALSA_PREFIX@ TSE3_ALSA_VERSION = @TSE3_ALSA_VERSION@ TSE3_ARTS_PREFIX = @TSE3_ARTS_PREFIX@ TSE3_WITH_ALSA = @TSE3_WITH_ALSA@ TSE3_WITH_ALSA_0_5_X = @TSE3_WITH_ALSA_0_5_X@ TSE3_WITH_ALSA_0_5_X_FALSE = @TSE3_WITH_ALSA_0_5_X_FALSE@ TSE3_WITH_ALSA_0_5_X_TRUE = @TSE3_WITH_ALSA_0_5_X_TRUE@ TSE3_WITH_ALSA_0_9_X = @TSE3_WITH_ALSA_0_9_X@ TSE3_WITH_ALSA_0_9_X_FALSE = @TSE3_WITH_ALSA_0_9_X_FALSE@ TSE3_WITH_ALSA_0_9_X_TRUE = @TSE3_WITH_ALSA_0_9_X_TRUE@ TSE3_WITH_ALSA_FALSE = @TSE3_WITH_ALSA_FALSE@ TSE3_WITH_ALSA_TRUE = @TSE3_WITH_ALSA_TRUE@ TSE3_WITH_ARTS = @TSE3_WITH_ARTS@ TSE3_WITH_ARTS_FALSE = @TSE3_WITH_ARTS_FALSE@ TSE3_WITH_ARTS_TRUE = @TSE3_WITH_ARTS_TRUE@ TSE3_WITH_OSS = @TSE3_WITH_OSS@ TSE3_WITH_OSS_FALSE = @TSE3_WITH_OSS_FALSE@ TSE3_WITH_OSS_TRUE = @TSE3_WITH_OSS_TRUE@ TSE3_WITH_WIN32 = @TSE3_WITH_WIN32@ TSE3_WITH_WIN32_FALSE = @TSE3_WITH_WIN32_FALSE@ TSE3_WITH_WIN32_TRUE = @TSE3_WITH_WIN32_TRUE@ VERSION = @VERSION@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ prefix = @prefix@ program_transform_name = @program_transform_name@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ tse3apph_HEADERS = Application.h Choices.h Modified.h PartSelection.h PartDisplay.h Record.h TrackSelection.h tse3apphdir = $(pkgincludedir)/app noinst_LTLIBRARIES = libtse3app.la libtse3app_la_SOURCES = Application.cpp Choices.cpp Modified.cpp PartSelection.cpp PartDisplay.cpp Record.cpp TrackSelection.cpp DISTCLEANFILES = ./.deps/* ./.deps/.P INCLUDES = -I$(top_srcdir)/src all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tse3/app/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/tse3/app/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libtse3app.la: $(libtse3app_la_OBJECTS) $(libtse3app_la_DEPENDENCIES) $(CXXLINK) $(libtse3app_la_LDFLAGS) $(libtse3app_la_OBJECTS) $(libtse3app_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Application.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Choices.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Modified.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PartDisplay.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PartSelection.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Record.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackSelection.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: install-tse3apphHEADERS: $(tse3apph_HEADERS) @$(NORMAL_INSTALL) test -z "$(tse3apphdir)" || $(mkdir_p) "$(DESTDIR)$(tse3apphdir)" @list='$(tse3apph_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(tse3apphHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(tse3apphdir)/$$f'"; \ $(tse3apphHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(tse3apphdir)/$$f"; \ done uninstall-tse3apphHEADERS: @$(NORMAL_UNINSTALL) @list='$(tse3apph_HEADERS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(tse3apphdir)/$$f'"; \ rm -f "$(DESTDIR)$(tse3apphdir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(tse3apphdir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-tse3apphHEADERS install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am uninstall-tse3apphHEADERS .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip install-tse3apphHEADERS installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-info-am \ uninstall-tse3apphHEADERS #noinst_PROGRAMS = test #test_SOURCES = test.cpp #test_LDFLAGS = -L$(top_builddir)/src/tse3 -L$(top_builddir)/src/tse3/platform -L$(top_builddir)/src/tse3/application #test_LDADD = -ltse3 -ltse3_OSS -ltse3_application # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: tse3-0.3.1/src/tse3/app/PartSelection.cpp0000644000175700001440000001620110271145574015030 00000000000000/* * @(#)PartSelection.cpp 3.00 25 May 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/app/PartSelection.h" #include "tse3/Song.h" #include "tse3/Track.h" #include "tse3/Part.h" #include "tse3/Phrase.h" #include using namespace TSE3; using namespace TSE3::App; PartSelection::PartSelection() : timesValid(false), _earliest(-1), _latest(-1), tracksValid(false), _minTrack(0), _maxTrack(0) { } PartSelection::PartSelection(const PartSelection &p) : TSE3::Listener(), TSE3::Listener(), TSE3::Notifier() { // Copy data members parts = p.parts; timesValid = p.timesValid; _earliest = p._earliest; _latest = p._latest; tracksValid = p.tracksValid; _minTrack = p._minTrack; _maxTrack = p._maxTrack; // Listen to each Part iterator_t i = parts.begin(); while (i != parts.end()) { Listener::attachTo(*i); ++i; } } PartSelection::~PartSelection() { // Detach from current Parts while (parts.size()) { removePart(parts.front()); } } bool PartSelection::isSelected(TSE3::Part *part) const { std::vector::const_iterator i = find(parts.begin(), parts.end(), part); return i != parts.end(); } void PartSelection::select(TSE3::Part *part, bool add) { if (!add) { clear(); } addPart(part); } void PartSelection::deselect(TSE3::Part *part) { removePart(part); } void PartSelection::clear() { _earliest = _latest = -1; _minTrack = _maxTrack = 0; timesValid = tracksValid = false; while (parts.size()) { Part *p = *parts.begin(); Listener::detachFrom(p); parts.erase(parts.begin()); notify(&PartSelectionListener::PartSelection_Selected, p, false); } recalculateEnds(); } void PartSelection::selectAll(TSE3::Song *song) { for (size_t t = 0; t < song->size(); ++t) { selectAll((*song)[t]); } } void PartSelection::selectAll(TSE3::Track *track) { for (size_t p = 0; p < track->size(); ++p) { addPart((*track)[p]); } } void PartSelection::invert(TSE3::Song *song) { for (size_t t = 0; t < song->size(); ++t) { TSE3::Track * const track = (*song)[t]; for (size_t p = 0; p < track->size(); ++p) { if (isSelected((*track)[p])) { removePart((*track)[p]); } else { addPart((*track)[p]); } } } } void PartSelection::selectBetween(TSE3::Song *song, TSE3::Clock start, TSE3::Clock end, bool inside) { for (size_t t = 0; t < song->size(); ++t) { selectBetween((*song)[t], start, end, inside); } } void PartSelection::selectBetween(TSE3::Track *track, TSE3::Clock start, TSE3::Clock end, bool inside) { for (size_t p = 0; p < track->size(); ++p) { Part *part = (*track)[p]; bool within = false; if (part->start() < start && part->end() > start) within = true; if (part->start() < end && part->end() > end) within = true; if (within == inside) { addPart(part); } } } PartSelection &PartSelection::operator=(const PartSelection &p) { // Detach from current Parts while (parts.size()) { Part *part = parts.front(); removePart(part); } // Copy data members parts = p.parts; timesValid = p.timesValid; _earliest = p._earliest; _latest = p._latest; tracksValid = p.tracksValid; _minTrack = p._minTrack; _maxTrack = p._maxTrack; // Listen to each Part iterator_t i = parts.begin(); while (i != parts.end()) { Listener::attachTo(*i); notify(&PartSelectionListener::PartSelection_Selected, *i, true); ++i; } return *this; } void PartSelection::addPart(TSE3::Part *part) { if (part->parent() && find(parts.begin(), parts.end(), part) == parts.end()) { parts.push_back(part); Listener::attachTo(part); if (!timesValid || part->start() < _earliest) { _earliest = part->start(); } if (!timesValid || part->end() > _latest) { _latest = part->end(); timesValid = true; } size_t track = part->parent()->parent()->index(part->parent()); if (!tracksValid || track < _minTrack) { _minTrack = track; } if (!tracksValid || track > _maxTrack) { _maxTrack = track; tracksValid = true; } notify(&PartSelectionListener::PartSelection_Selected, part, true); } } void PartSelection::removePart(TSE3::Part *part) { std::vector::iterator i = find(parts.begin(), parts.end(), part); if (i != parts.end()) { Listener::detachFrom(part); parts.erase(i); recalculateEnds(); notify(&PartSelectionListener::PartSelection_Selected, part, false); } } void PartSelection::recalculateEnds() { if (parts.size()) { std::vector::iterator i = parts.begin(); _earliest = (*i)->start(); _latest = (*i)->end(); _minTrack = (*i)->parent()->parent()->index((*i)->parent()); _maxTrack = _minTrack; timesValid = true; tracksValid = true; while (++i != parts.end()) { if ((*i)->start() < _earliest) _earliest = (*i)->start(); if ((*i)->end() < _latest) _latest = (*i)->end(); size_t track = (*i)->parent()->parent()->index((*i)->parent()); if (track < _minTrack) _minTrack = track; if (track > _maxTrack) _maxTrack = track; } } else { _earliest = -1; _latest = -1; _minTrack = 0; _maxTrack = 0; timesValid = false; tracksValid = false; } } void PartSelection::Part_StartAltered(Part *, Clock) { recalculateEnds(); } void PartSelection::Part_EndAltered(Part *, Clock) { recalculateEnds(); } void PartSelection::Part_Reparented(Part *part) { if (!part->parent()) { removePart(part); } } void PartSelection::Notifier_Deleted(Part *part) { removePart(part); } void PartSelection::TrackSelection_Selected(TrackSelection *, TSE3::Track *, bool selected) { if (selected) { clear(); } } tse3-0.3.1/src/tse3/app/Record.h0000644000175700001440000002071010302616276013134 00000000000000/* * @(#)app/Record.h 1.00 18 June 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_APPLICATION_RECORD_H #define TSE3_APPLICATION_RECORD_H #include "tse3/listen/app/Record.h" #include "tse3/Notifier.h" #include "tse3/Midi.h" #include "tse3/listen/Transport.h" #include namespace TSE3 { class PhraseEdit; class Track; class Song; class Transport; class MidiScheduler; namespace Cmd { class CommandHistory; } namespace App { /** * This class provides help using the @ref Transport object's record * facilities. When using the @ref Transport record API, you need * to create a @ref PhraseEdit and keep track of when you started * and stopped recording. * * After recording you will need to supply a name for the new @ref * Phrase and then have it inserted into the @ref Song. * * The job of this helper class is to aid this process. The lifetime * of the objects involved are managed, and the actions needed are * encapsulated in these methods. * * It is assumed that neither the @ref Transport object or the * @ref MidiScheduler object will be deleted from under the Recording * object's feet. * * @short Support class for recording * @author Pete Goodliffe * @version 1.00 * @see TSE3 */ class Record : public TSE3::Listener, public TSE3::Notifier { public: /** * Creates a new recording helper object. * * The initial values of @ref start() and @ref end() default, * and there is no @ref PhraseEdit created (see @ref * phraseEdit()). */ Record(TSE3::Transport *transport); /** * Any allocated object will be deallocated. */ ~Record(); /** * Start recording at the current @ref MidiScheduler time. * This will create a new @ref PhraseEdit object. * * You must pass a @ref Song and @ref Track parameter. These * are used to pass a @ref Playable and * @ref SimpleMidiEventFilter * parameter to the @ref TSE3::Transport::record() method. * * It is also used later on to insert a @ref Part into the * @ref Track. * * If you call start a second time, whilst recording is taking * place, then it is equivalent to calling @ref stop(). * * You don't have to call @ref Record::stop(), you can just * use @ref TSE3::Transport::stop(). However, read the * documentation for this object's @ref stop method for * information on the callback generated. * * @see stop */ void start(TSE3::Song *p, TSE3::Track *t); /** * Stops recording at the current @ref MidiScheduler time. * Sends a notification to any @ref TSE3::Listener objects. * * You do not have to call this to stop recording: any call to * @ref TSE3::Transport::stop() will cause the Record object * to notice, and notify any listeners. * * @sect Notification * * The @ref RecordingListener::Record_RecordingEnded * notification is only sent if there was something recorded * into the @ref PhraseEdit object. * * If you handle the * @ref RecordingListener::Record_RecordingEnded callback * you must take care to check the @ref TSE3::Song and * @ref TSE3::Track parameters. If there are two or more * objects that use the Record utility, they will both receive * the notification and will have to check whether it was a * recording that they started or not. * * @ref start */ void stop(); /** * Returns the time recording was last started at, or -1 if * recording has never been started. */ TSE3::Clock startTime() const { return _startTime; } /** * Returns the time recording was last ended at, or -1 if * recording has never been ended. */ TSE3::Clock endTime() const { return _endTime; } /** * Returns a pointer to the current @ref PhraseEdit object, or * zero if no @ref PhraseEdit has been created. */ TSE3::PhraseEdit *phraseEdit() const { return _phraseEdit; } /** * Inserts the recorded @ref Phrase into the @ref Song. * You specify a name for the new @ref Phrase. * * This method may propagate the @ref PhraseList exception if * the @ref Phrase name already exists. * * After the action has been carried out, the internally * allocated @ref PhraseEdit object is deallocated. * * This operation will be performed using @ref TSE3::Command * objects, and the object will be placed on the * @ref TSE3::Cmd::CommandHistory object specified. * * @param title New @ref Phrase title (must be unique) * @param replacePhrase If the Phrase name already exists, * setting this to true will replace it. * @param insertAction A @ref * TSE3::Cmd::Part_Move::PartInsertAction * value. * @param history @ref TSE3::Cmd::CommandHistory object * to place undoable commands onto. * Specify zero will not store any * commands. */ void insertPhrase(const std::string &title, bool replacePhrase, bool insertPart, int insertAction, TSE3::Cmd::CommandHistory *history = 0); /** * Ensures that all objects are deallocated, in case the * recording has ended but the user doesn't want to save the * recording into the @ref Song. * * It's not strictly necessary to call this if you are not * going to call @ref insertPhrase(). Without calling this * the next call to @ref start() will handle object reallocation * successfully. However, by calling this you will free up * resources that aren't currently needed. */ void reset(); /** * @reimplemented */ void Transport_Status(TSE3::Transport *, int status); protected: TSE3::Transport *_transport; TSE3::PhraseEdit *_phraseEdit; TSE3::Song *_song; TSE3::Track *_track; TSE3::Clock _startTime; TSE3::Clock _endTime; bool recording; }; } } #endif tse3-0.3.1/src/tse3/app/Choices.h0000644000175700001440000002710310271145574013301 00000000000000/* * @(#)app/Choices.h 1.00 16 Nov 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_APP_CHOICES_H #define TSE3_APP_CHOICES_H #include "tse3/Notifier.h" #include "tse3/Serializable.h" #include "tse3/FileBlockParser.h" #include #include namespace TSE3 { class Metronome; class Transport; class Panic; class MidiMapper; class MidiScheduler; namespace Ins { class Destination; } namespace App { class Application; /** * ChoiceHandlers are used by the @ref ChoicesManger object. You access * the choices save/load mechanism through that object. * * This is a base class for objects that can save a particular block of * choices. ChoiceHandlers are registered with the @ref ChoicesManager * which delegates responsibility for saving/loading to each * ChoiceHandler. * * ChoiceHandlers implement the @ref Serializable interface as the * mechansim with which to perform saving, however they differ from the * normal @ref TSE3::Song hierarchy save method since the object whose * state is being saved is not the @ref TSE3::Serializable object - it * is a ChoiceHandler based on it that does the saving. * * A number of stock implementations of ChoiceHandler are provided to * save the common @ref TSE3 objects that are not directly related to a * @ref Song. However, an application will want to add many more * ChoiceHandlers to save it's internal settings (e.g. window positions, * feature statuses end so on). * * @short Choice save/load base class * @author Pete Goodliffe * @version 1.00 * @see ChoicesManager */ class ChoiceHandler : public TSE3::Serializable { public: /** * Create a ChoiceHandler with the given name. */ ChoiceHandler(const std::string &choicename); virtual ~ChoiceHandler(); /** * Returns the name of this ChoiceHandler. This is a unique * text string that will identify a block of data in the * choices file as having been saved by this ChoiceHandler. */ const std::string &name() const { return _name; } protected: std::string _name; }; /** * This class provides a mechanism for saving 'choices'. These are * the configuration aspects of any objects in the @ref TSE3 sequencer * application. * * It employs the singleton design pattern. * * The format of a choices file is the blocked @ref TSE3MDL format. * * @short Choices file saving management * @author Pete Goodliffe * @version 1.00 * @see TSE3 */ class ChoicesManager// : public Listener { public: ChoicesManager(); ~ChoicesManager(); /** * Add a new @ref ChoiceHandler to the manager. This ties the * object's lifecycle to the ChoicesManager; if it is not * removed then the destruction of this object will bring about * the destruction of the added ChoiceHandler. */ void add(ChoiceHandler *ch) { handler.add(ch); } /** * Remove the @ref ChoiceHandler from the manager. The * @ref ChoiceHandler's life is not tied to the manager's any * more. */ void remove(ChoiceHandler *ch) { handler.remove(ch); } /** * This method steps through each @ref ChoiceHandler registered * and requests that it saves it's choices in the appropriate * file format. */ void save(const std::string &filename); /** * This method reads and interprets the given choices file. * It reads each block and then intructs the appropriate * @ref ChoiceHandler to perform the necessary settings based * on it. * * If the file doesn't exist then no error is thrown. */ void load(const std::string &filename); private: /** * This internal class does the real work of the * @ref ChoicesHandler saving. We do this in a nested class * since the agent performing the top level save needs to be a * @ref ChoiceHandler, but it is unnecssarily messy for the * ChoiesManager to be a @ref ChoiceHandler (this would give it * member functions that could be called incorrectly). */ class ChoicesChoiceHandler : public ChoiceHandler { public: ChoicesChoiceHandler(); ~ChoicesChoiceHandler(); void add(ChoiceHandler *ch); void remove(ChoiceHandler *ch); /** * @reimplemented */ virtual void save(std::ostream &out, int indent) const; /** * @reimplemented */ virtual void load(std::istream &in, TSE3::SerializableLoadInfo &info); private: std::list handlers; }; ChoicesChoiceHandler handler; }; /********************************************************************** * ChoiceHandlers **********************************************************************/ /** * ChoiceHandler for the @ref TSE3::App::Application class. * * @short @ref TSE3::App::Application ChoiceHandler * @author Pete Goodliffe * @version 3.0 */ class ApplicationChoiceHandler : public ChoiceHandler { public: ApplicationChoiceHandler(Application *a); ~ApplicationChoiceHandler(); /** * @reimplemented */ virtual void save(std::ostream &out, int indent) const; /** * @reimplemented */ virtual void load(std::istream &in, TSE3::SerializableLoadInfo &info); private: Application *a; }; /** * ChoiceHandler for the @ref TSE3::Metronome class. * * @short @ref TSE3::Metronome ChoiceHandler * @author Pete Goodliffe * @version 3.0 */ class MetronomeChoiceHandler : public ChoiceHandler { public: MetronomeChoiceHandler(TSE3::Metronome *m); ~MetronomeChoiceHandler(); /** * @reimplemented */ virtual void save(std::ostream &out, int indent) const; /** * @reimplemented */ virtual void load(std::istream &in, TSE3::SerializableLoadInfo &info); private: TSE3::Metronome *m; }; /** * ChoiceHandler for the @ref TSE3::Panic class. * * @short @ref TSE3::Panic ChoiceHandler * @author Pete Goodliffe * @version 3.0 */ class PanicChoiceHandler : public ChoiceHandler { public: PanicChoiceHandler(TSE3::Panic *p); ~PanicChoiceHandler(); /** * @reimplemented */ virtual void save(std::ostream &out, int indent) const; /** * @reimplemented */ virtual void load(std::istream &in, TSE3::SerializableLoadInfo &info); private: TSE3::Panic *p; }; /** * ChoiceHandler for the @ref TSE3::MidiMapper class. * * @short @ref TSE3::MidiMapper ChoiceHandler * @author Pete Goodliffe * @version 3.0 */ class MidiMapperChoiceHandler : public ChoiceHandler { public: MidiMapperChoiceHandler(TSE3::MidiMapper *m); ~MidiMapperChoiceHandler(); /** * @reimplemented */ virtual void save(std::ostream &out, int indent) const; /** * @reimplemented */ virtual void load(std::istream &in, TSE3::SerializableLoadInfo &info); private: TSE3::MidiMapper *m; }; /** * ChoiceHandler for the @ref TSE3::Transport class. * * @short @ref TSE3::Transport ChoiceHandler * @author Pete Goodliffe * @version 3.0 */ class TransportChoiceHandler : public ChoiceHandler { public: TransportChoiceHandler(TSE3::Transport *t); ~TransportChoiceHandler(); /** * @reimplemented */ virtual void save(std::ostream &out, int indent) const; /** * @reimplemented */ virtual void load(std::istream &in, TSE3::SerializableLoadInfo &info); private: TSE3::Transport *t; PanicChoiceHandler startPanicHandler; PanicChoiceHandler endPanicHandler; MidiMapperChoiceHandler mapperHandler; }; /** * ChoiceHandler for the @ref TSE3::Ins::Destination class. * * @short @ref TSE3::Ins::Destination ChoiceHandler * @author Pete Goodliffe * @version 3.0 */ class DestinationChoiceHandler : public ChoiceHandler { public: DestinationChoiceHandler(TSE3::Ins::Destination *d, TSE3::MidiScheduler *ms); ~DestinationChoiceHandler(); /** * @reimplemented */ virtual void save(std::ostream &out, int indent) const; /** * @reimplemented */ virtual void load(std::istream &in, TSE3::SerializableLoadInfo &info); private: TSE3::Ins::Destination *d; TSE3::MidiScheduler *ms; }; } } #endif tse3-0.3.1/src/tse3/cmd/0000777000175700017570000000000010310240001011601 500000000000000tse3-0.3.1/src/tse3/cmd/Part.cpp0000644000175700001440000001304410271145576013151 00000000000000/* * @(#)Part.cpp 3.00 9 July 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/cmd/Part.h" #include "tse3/Track.h" #include "tse3/Part.h" #include "tse3/Error.h" #include using namespace TSE3; using namespace TSE3::Cmd; /****************************************************************************** * Part_SetInfo class *****************************************************************************/ Part_SetInfo::Part_SetInfo(TSE3::Part *part, TSE3::Phrase *phrase, TSE3::Clock repeat, const TSE3::MidiFilter &smef, const TSE3::MidiParams &mp, const TSE3::DisplayParams &dp) : Command("set part info"), part(part), newPhrase(phrase), newRepeat(repeat), smef(smef), mp(mp), dp(dp) { } void Part_SetInfo::executeImpl() { oldPhrase = part->phrase(); oldRepeat = part->repeat(); part->setPhrase(newPhrase); part->setRepeat(newRepeat); std::swap(smef, *(part->filter())); std::swap(mp, *(part->params())); std::swap(dp, *(part->displayParams())); } void Part_SetInfo::undoImpl() { part->setPhrase(oldPhrase); part->setRepeat(oldRepeat); std::swap(smef, *(part->filter())); std::swap(mp, *(part->params())); std::swap(dp, *(part->displayParams())); } /****************************************************************************** * Part_SetPhrase class *****************************************************************************/ Part_SetPhrase::Part_SetPhrase(TSE3::Part *part, TSE3::Phrase *phrase) : Command("set phrase"), part(part), newPhrase(phrase) { } void Part_SetPhrase::executeImpl() { oldPhrase = part->phrase(); part->setPhrase(newPhrase); } void Part_SetPhrase::undoImpl() { part->setPhrase(oldPhrase); } /****************************************************************************** * Part_Move class *****************************************************************************/ Part_Move::Part_Move(int action, TSE3::Part *part, TSE3::Track *track, TSE3::Clock nStart, TSE3::Clock nEnd) : Command(prvTitle(part->parent() != 0, newEnd != -1, track == part->parent())), part(part), newTrack(track), newStart(nStart), newEnd(nEnd), action(action), clippedStart(-1), clippedEnd(-1), newPart(0), valid(true) { oldTrack = part->parent(); oldStart = part->start(); oldEnd = part->end(); if (newStart == -1) newStart = oldStart; if (newEnd == -1) newEnd = newStart + oldEnd - oldStart; if (!newTrack || newStart < 0) valid = false; } const char *Part_Move::prvTitle(bool hasParent, bool relativeEnd, bool sameTrack) { if (!hasParent) { return "insert part"; } else { if (!relativeEnd || !sameTrack) { return "move part"; } else { return "resize part"; } } } Part_Move::~Part_Move() { if (done()) { while (removed.size()) { delete removed.back(); removed.pop_back(); } } else { delete newPart; } } void Part_Move::removeAndSetPart() { if (oldTrack) oldTrack->remove(part); part->setStartEnd(newStart, newEnd); } void Part_Move::unsetAndReinsertPart() { part->setStartEnd(oldStart, oldEnd); if (oldTrack) oldTrack->insert(part); } void Part_Move::executeImpl() { if (valid) { // Remove the Part from it's old position removeAndSetPart(); switch (action) { case NoOverlap: { try { newTrack->insert(part); } catch (const TSE3::TrackError &e) { unsetAndReinsertPart(); valid = false; throw; } break; } case Replace: { Util::Track_RemoveParts(newTrack, part->start(), part->end(), removed, clippedStart, clippedEnd, newPart); newTrack->insert(part); break; } case Under: { break; } } } } void Part_Move::undoImpl() { if (valid) { switch (action) { case NoOverlap: { newTrack->remove(part); break; } case Replace: { newTrack->remove(part); Util::Track_UnremoveParts(newTrack, part->start(), part->end(), removed, clippedStart, clippedEnd); break; } case Under: { break; } } // The Part will just slot back into the old gap unsetAndReinsertPart(); } } tse3-0.3.1/src/tse3/cmd/Phrase.h0000644000175700001440000002304210271145576013131 00000000000000/* * @(#)cmd/Phrase.h 3.00 21 November 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_CMD_PHRASE_H #define TSE3_CMD_PHRASE_H #include "tse3/cmd/Command.h" #include "tse3/Phrase.h" #include "tse3/DisplayParams.h" #include #include namespace TSE3 { class Phrase; class Song; class Part; namespace Cmd { /** * Command to set a @ref TSE3::Phrase's info (the title and its * @ref TSE3::DisplayParams setup). * * If the @ref TSE3::Phrase is parented in a @ref TSE3::PhraseList * and you change the title to an invalid name, then the exception * generated by @ref TSE3::PhraseList::insert() will be propragated back * to you. * * @short Set @ref TSE3::Phrase info Command * @author Pete Goodliffe * @version 1.00 * @see Command */ class Phrase_SetInfo : public Command { public: /** * To create this command specify the @ref TSE3::Track object to * alter and the new information. * * If the @ref TSE3::Phrase is not parented, or the new * @p title already exists in the @ref PhraseList, then * a @ref PhraseListError is thrown. * * @param phrase @ref TSE3::Phrase to run command on * @param title New title string (or "" to leave title) * @param dp New @ref TSE3::DisplayParams * @throws PhraseListError */ Phrase_SetInfo(TSE3::Phrase *phrase, const std::string &title, const TSE3::DisplayParams &dp); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Phrase *phrase; std::string newTitle, oldTitle; TSE3::DisplayParams dp; }; /** * Command to insert a @ref TSE3::Phrase into a @ref TSE3::Song * by creating it from a @ref TSE3::PhraseEdit. * * This object may propagate the @ref TSE3::PhraseListError exception * if the @ref Phrase name already exists. * * @short Insert @ref TSE3::Phrase Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Phrase_Create : public Command { public: /** * Creates a new Phrase_Create command. * * After having performed the first @ref execute() on this * object it is safe to delete the @ref PhraseEdit object. * Until then you must ensure that the object is not deleted. * * @param phrase @ref TSE3::Phrase to insert * @param phraseList @ref TSE3::PhraseList to insert it in */ Phrase_Create(TSE3::PhraseList *phraseList, TSE3::PhraseEdit *phraseEdit, const std::string &title = ""); virtual ~Phrase_Create(); /** * Returns a pointer to the created @ref Phrase. This * is only valid once @ref execute() had been called. */ TSE3::Phrase *phrase() const { return newPhrase; } protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::PhraseList *phraseList; TSE3::PhraseEdit *phraseEdit; TSE3::Phrase *newPhrase; std::string title; }; /** * Command to erase a @ref TSE3::Phrase from a @ref TSE3::PhraseList. * * @short Erase @ref TSE3::Phrase Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Phrase_Erase : public Command { public: /** * Creates a new Phrase_Erase command. * * The @ref TSE3::PhraseList to remove from is read from the * @ref TSE3::Phrase. * * @param phrase @ref TSE3::Phrase to erase * @param song @ref TSE3::Song the @ref TSE3::Phrase * is from. Every use of a * @ref TSE3::Phrase in a @ref TSE3::Part in the * @ref TSE3::Song will be removed, and on * undo replaced. */ Phrase_Erase(TSE3::Phrase *phrase, TSE3::Song *song); virtual ~Phrase_Erase(); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Phrase *phrase; TSE3::Song *song; std::vector parts; bool vector_done; }; /* * Command to replace a @ref TSE3::Phrase in a @ref TSE3::Song with * another @ref TSE3::Phrase. The new @ref TSE3::Phrase can be * automatically created from a @ref TSE3::PhraseEdit and given the * same name as the original @ref TSE3::Phrase. * * @short Replace @ref TSE3::Phrase @ref Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Phrase_Replace : public Command { public: /** * Creates a new Phrase_Replace command. * * Every @ref TSE3::Part that uses the @p oldPhrase will be * made to use the @p newPhrase. * * Both of the @ref TSE3::Phrase objects ought to be in the * same @ref TSE3::PhraseList (which should be in the * @ref TSE3::Song). * * @param oldPhrase @ref TSE3::Phrase to remove * @param newPhrase @ref TSE3::Phrase to replace with * @param song @ref TSE3::Song to act on */ Phrase_Replace(TSE3::Phrase *oldPhrase, TSE3::Phrase *newPhrase, TSE3::Song *song); /** * The @p oldPhrase is removed from the @ref TSE3::PhraseList * completely. A new @p Phrase created from the @p phraseEdit * object and is inserted in its place. If the @p title is not * specified, then it will be give the same title as the * @p oldPhrase. The replacement operation will be performed, * and the the new @p Phrase will be inserted into the * @ref TSE3::PhraseList. * * @param oldPhrase @ref TSE3::Phrase to remove * @param phraseEdit @ref TSE3::PhraseEdit to source data from * @param song @ref TSE3::Song to act on * @param title Title for new Phras */ Phrase_Replace(TSE3::Phrase *oldPhrase, TSE3::PhraseEdit *phraseEdit, TSE3::Song *song, const std::string &title = ""); ~Phrase_Replace(); /** * Returns a pointer to the new (possibly created) @ref Phrase. * * If this @ref Phrase has been created, then the result of * this method is only valid once @ref execute() had been * called. */ TSE3::Phrase *phrase() const { return newPhrase; } protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Phrase *newPhrase; TSE3::Phrase *oldPhrase; TSE3::PhraseEdit *phraseEdit; TSE3::Song *song; std::string newTitle; std::vector parts; }; } } #endif tse3-0.3.1/src/tse3/cmd/FlagTrack.h0000644000175700001440000000316010271145576013544 00000000000000/* * @(#)cmd/FlagTrack.h 3.00 26 April 2002 * * Copyright (c) 2002 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_CMD_FLAG_H #define TSE3_CMD_FLAG_H #include "tse3/cmd/Command.h" #include "tse3/FlagTrack.h" #include #include namespace TSE3 { namespace Cmd { /** * Command to add a @ref TSE3::Flag to a @ref TSE3::FlagTrack. * * @short Add @ref TSE3::Flag Command * @author Pete Goodliffe * @version 1.00 * @see Command */ class FlagTrack_Add : public Command { public: FlagTrack_Add(TSE3::FlagTrack *flagTrack, const TSE3::Event &flag); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::FlagTrack *flagTrack; const TSE3::Event flag; size_t insertIndex; }; } } #endif tse3-0.3.1/src/tse3/cmd/CommandGroup.cpp0000644000175700001440000000300410271145576014631 00000000000000/* * @(#)CommandGroup.cpp 3.00 5 September 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/cmd/CommandGroup.h" #include using namespace TSE3; using namespace TSE3::Cmd; CommandGroup::CommandGroup(const std::string &title) : Command(title), canAdd(true) { } CommandGroup::~CommandGroup() { // delete every command while (!cmds.empty()) { delete cmds.back(); cmds.pop_back(); } } void CommandGroup::add(Command *command) { if (canAdd) { cmds.push_back(command); if (title() == "") { setTitle(command->title()); } } else { std::cerr << "TSE3: Bad attempt to add a Command to a CommandGroup\n"; } } void CommandGroup::executeImpl() { canAdd = false; std::vector::iterator i = cmds.begin(); while (i != cmds.end()) { (*i)->execute(); i++; } } void CommandGroup::undoImpl() { std::vector::reverse_iterator i = cmds.rbegin(); while (i != cmds.rend()) { (*i)->undo(); i++; } } tse3-0.3.1/src/tse3/cmd/Part.h0000644000175700001440000001752310271145576012624 00000000000000/* * @(#)cmd/Part.h 3.00 9 July 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_CMD_PART_H #define TSE3_CMD_PART_H #include "tse3/cmd/Command.h" #include "tse3/util/Track.h" #include "tse3/MidiFilter.h" #include "tse3/MidiParams.h" #include "tse3/DisplayParams.h" namespace TSE3 { class Part; class Phrase; namespace Cmd { /** * Command to set a @ref TSE3::Part's info (the @ref TSE3::Phrase, * it's @ref TSE3::MidiParams setup, the @ref TSE3::DisplayParams and * it's @ref TSE3::MidiFilter setup). * * If you just want to set the @ref TSE3::Phrase, use * @ref Part_SetPhrase. * * @short Set @ref TSE3::Part info Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Part_SetInfo : public Command { public: /** * To create this command specify the @ref Part object to alter * and the new information. */ Part_SetInfo(TSE3::Part *part, TSE3::Phrase *phrase, TSE3::Clock repeat, const TSE3::MidiFilter &smef, const TSE3::MidiParams &mp, const TSE3::DisplayParams &dp); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Part *part; TSE3::Phrase *newPhrase, *oldPhrase; TSE3::Clock newRepeat, oldRepeat; TSE3::MidiFilter smef; TSE3::MidiParams mp; TSE3::DisplayParams dp; }; /** * Command to set a @ref TSE3::Part's @ref TSE3::Phrase. * * @short Set @ref TSE3::Part @ref TSE3::Phrase Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Part_SetPhrase : public Command { public: /** * To create this command specify the @ref Part object to alter * and the new @ref TSe3::Phrase. */ Part_SetPhrase(TSE3::Part *part, TSE3::Phrase *phrase); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Part *part; TSE3::Phrase *newPhrase, *oldPhrase; }; /** * Command to move a @ref TSE3::Part's from it's current position * (which may be in a @ref TSE3::Track or not - in which case the * @ref TSE3::Part is being 'inserted') to another position in a * (possibly different) @ref TSE3::Track. * * @short Move @ref TSE3::Part Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Part_Move : public Command { public: /** * This enum type describes how a @ref TSE3::Part should be * inserted into a @ref TSE3::Track by the Part_Move * @ref Command. The items are: * * @li NoOverlap The new @ref TSE3::Part is not allowed to * overlap any existing Parts in the * @ref TSE3::Track. If inserting it will cause * an overlap, a @ref TSE3::TrackError exception * will be thrown by the @ref TSE3::Track. * @li Replace The new @ref TSE3::Part will replace any * @ref TSE3::Part objects that it overlaps. This * may result in some existing @ref TSE3::Part * objects being deleted. * @li Under If there are any overlaps, the inserted * @ref TSE3::Part will be placed 'underneath' * the other @ref TSE3::Part objects (i.e. it * will have holes cut in it for each existing * @ref TSE3::Part position). This may result in * more than one @ref TSE3::Part being inserted * in the Track. */ enum PartInsertAction { NoOverlap, Replace, Under }; /** * To create this command specify the @ref Part object to alter * and the new information. * * @param action @ref PartInsertAction to perform Command with * @param part @ref TSE3::Part to move/insert * @param track @ref TSE3::Track to insert into * @param newStart New @ref TSE3::Part start time * (leave as default to maintain original value) * @param newEnd New @ref TSE3::Part end time * (leave as default to maintain original Part * length) */ Part_Move(int action, TSE3::Part *part, TSE3::Track *track, TSE3::Clock newStart = -1, TSE3::Clock newEnd = -1); virtual ~Part_Move(); protected: /** * @reimplemented * May throw a @ref TSE3::PartError if insert fails. */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: /** * Returns a title for this command worked out from the * ctor parameters specified. * * @param hasParent Set to the value of (part->parent() != 0) * @param relativeEnd Set to the value of (end == -1) */ static const char *prvTitle(bool hasParent, bool relativeEnd, bool sameTrack); void removeAndSetPart(); void unsetAndReinsertPart(); TSE3::Part *part; TSE3::Track *newTrack, *oldTrack; TSE3::Clock newStart, oldStart; TSE3::Clock newEnd, oldEnd; int action; std::vector removed; TSE3::Clock clippedStart; TSE3::Clock clippedEnd; TSE3::Part *newPart; bool valid; }; } } #endif tse3-0.3.1/src/tse3/cmd/Song.h0000644000175700001440000002305610271145576012622 00000000000000/* * @(#)cmd/Song.h 3.00 10 June 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_CMD_SONG_H #define TSE3_CMD_SONG_H #include "tse3/cmd/Command.h" #include "tse3/Song.h" #include #include #include namespace TSE3 { class Part; class Phrase; namespace Cmd { /** * Command to set a @ref Song's info (the title, author, copyright * and date strings). * * @short Set Song info strings Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Song_SetInfo : public Command { public: /** * To create this command specify the @ref Song object to alter * and the new information. */ Song_SetInfo(TSE3::Song *s, const std::string &title, const std::string &author, const std::string ©right, const std::string &date); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Song *song; std::string newTitle, oldTitle; std::string newAuthor, oldAuthor; std::string newCopyright, oldCopyright; std::string newDate, oldDate; }; /** * Command to set a @ref Song's title. * * @short Set Song title Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Song_SetTitle : public VariableSetCommand { public: /** * To create this command specify the @ref Song object to alter * and the new title. */ Song_SetTitle(TSE3::Song *s, const std::string &str) : VariableSetCommand (s, str, "song title") {} }; /** * Command to set a @ref Song's author. * * @short Set Song author Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Song_SetAuthor : public VariableSetCommand { public: /** * To create this command specify the @ref Song object to alter * and the new author. */ Song_SetAuthor(TSE3::Song *s, const std::string &str) : VariableSetCommand (s, str, "author") {} }; /** * Command to set a @ref Song's copyright. * * @short Set Song copyright Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Song_SetCopyright : public VariableSetCommand { public: /** * To create this command specify the @ref Song object to alter * and the new copyright message. */ Song_SetCopyright(TSE3::Song *s, const std::string &str) : VariableSetCommand (s, str, "copyright") {} }; /** * Command to set a @ref Song's date. * * @short Set Song date Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Song_SetDate : public VariableSetCommand { public: /** * To create this command specify the @ref Song object to alter * and the new date. */ Song_SetDate(TSE3::Song *s, const std::string &str) : VariableSetCommand (s, str, "song date") {} }; /** * Command to insert a new blank @ref Track into a @ref Song. * * @short Insert Track Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Song_InsertTrack : public Command { public: /** * Insert a new blank @ref TSE3::Track into the @ref TSE3::Song * @p song at index @p track. * * @param song @ref TSE3::Song to insert @ref TSE3::Track into * @param track Index at which to insert new @ref TSE3::Track */ Song_InsertTrack(TSE3::Song *song, size_t track); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Song *song; int track; }; /** * Command to remove a @ref Track from a @ref Song. * * @short Remove Track Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Song_RemoveTrack : public Command { public: /** * Remove the specified @ref TSE3::Track from it's parent * @ref TSE3::Song. * * @param track @ref TSE3:Track to remove */ Song_RemoveTrack(TSE3::Track *track); /** * Remove the @ref TSE3::Track specified by the index * @p track in the @ref TSE3::Song @p song. * * @param song @ref TSE3::Song to remove @ref TSE3::Track from * @param track Index of @ref TSE3::Track to remove */ Song_RemoveTrack(TSE3::Song *song, size_t track); /** * Remove the specified @ref TSE3::Track @p track from the * @ref TSE3::Song @p song. * * @param song @ref TSE3::Song to remove @ref TSE3::Track from * @param track @ref TSE3::Track to remove */ Song_RemoveTrack(TSE3::Song *song, Track *track); virtual ~Song_RemoveTrack(); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Song *song; TSE3::Track *track; int trackno; }; /** * Command to set the solo @ref Track in a @ref Song. * * @short Solo Track Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Song_SoloTrack : public Command { public: Song_SoloTrack(TSE3::Song *song, int track); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Song *song; int track; int old; }; } } #endif tse3-0.3.1/src/tse3/cmd/FlagTrack.cpp0000644000175700001440000000220510271145576014076 00000000000000/* * @(#)FlagTrack.cpp 3.00 26 April 2002 * * Copyright (c) 2002 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/cmd/FlagTrack.h" using namespace TSE3; using namespace TSE3::Cmd; /****************************************************************************** * FlagTrack_Add class *****************************************************************************/ FlagTrack_Add::FlagTrack_Add(TSE3::FlagTrack *flagTrack, const TSE3::Event &flag) : Command("add flag"), flagTrack(flagTrack), flag(flag), insertIndex(0) { } void FlagTrack_Add::executeImpl() { insertIndex = flagTrack->insert(flag); } void FlagTrack_Add::undoImpl() { flagTrack->erase(insertIndex); } tse3-0.3.1/src/tse3/cmd/CommandHistory.cpp0000644000175700001440000001001610271145576015177 00000000000000/* * @(#)CommandHistory.cpp 3.00 20 July 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/cmd/CommandHistory.h" using namespace TSE3::Cmd; /****************************************************************************** * CommandHistory class *****************************************************************************/ CommandHistory::CommandHistory(int l) : _limit(l) { } void CommandHistory::add(Command *c) { bool sendNotify = (undolist.size() == 0); undolist.push_front(c); if (!redolist.empty()) { while (!redolist.empty()) { delete redolist.back(); redolist.pop_back(); } notify(&CommandHistoryListener::CommandHistory_Redo); } if (_limit != -1 && undolist.size() > static_cast(_limit)) { delete undolist.back(); undolist.pop_back(); } if (!c->undoable()) { while (!undolist.empty()) { delete undolist.back(); undolist.pop_back(); } } if (sendNotify) notify(&CommandHistoryListener::CommandHistory_Undo); } bool CommandHistory::undos() const { return undolist.size() > 0; } void CommandHistory::undo() { if (undolist.empty()) return; undolist.front()->undo(); bool sendRedoNotify = (redolist.size() == 0); redolist.push_front(undolist.front()); undolist.pop_front(); if (undolist.size() == 0) notify(&CommandHistoryListener::CommandHistory_Undo); if (sendRedoNotify) notify(&CommandHistoryListener::CommandHistory_Redo); } Command *CommandHistory::undoCommand(size_t pos) { Command *cmd = 0; if (pos < undolist.size()) { std::list::iterator i = undolist.begin(); for (size_t n = 0; n < pos && i != undolist.end(); n++) { i++; } cmd = *i; } return cmd; } bool CommandHistory::redos() const { return redolist.size() > 0; } void CommandHistory::redo() { if (redolist.empty()) return; redolist.front()->execute(); bool sendUndoNotify = (undolist.size() == 0); undolist.push_front(redolist.front()); redolist.pop_front(); if (redolist.size() == 0) notify(&CommandHistoryListener::CommandHistory_Redo); if (sendUndoNotify) notify(&CommandHistoryListener::CommandHistory_Undo); } Command *CommandHistory::redoCommand(size_t pos) { Command *cmd = 0; if (pos < redolist.size()) { std::list::iterator i = redolist.begin(); for (size_t n = 0; n < pos && i != redolist.end(); n++) { i++; } cmd = *i; } return cmd; } int CommandHistory::limit() const { return _limit; } void CommandHistory::setLimit(int l) { if (l < -1) l = -1; _limit = l; while (_limit == -1 || undolist.size() > static_cast(_limit)) { delete *(undolist.end()); undolist.erase(undolist.end()); } while (_limit == -1 || redolist.size() > static_cast(_limit)) { delete *(redolist.end()); redolist.erase(redolist.end()); } // Send notification whatever (this doesn't happen often ;-) notify(&CommandHistoryListener::CommandHistory_Undo); notify(&CommandHistoryListener::CommandHistory_Redo); } void CommandHistory::clearUndos() { if (undolist.size() != 0) { undolist.clear(); notify(&CommandHistoryListener::CommandHistory_Undo); } } void CommandHistory::clearRedos() { if (redolist.size() != 0) { redolist.clear(); notify(&CommandHistoryListener::CommandHistory_Redo); } } tse3-0.3.1/src/tse3/cmd/CommandGroup.h0000644000175700001440000000707010271145576014305 00000000000000/* * @(#)cmd/CommandGroup.h 3.00 5 Septemeber 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_CMD_COMMANDGROUP_H #define TSE3_CMD_COMMANDGROUP_H #include "tse3/cmd/Command.h" #include #include namespace TSE3 { namespace Cmd { /** * A class that groups @ref Command object together so you can * pretend that several commands are one. * * The commands will be executed in the order that they are added * to the CommandGroup (see @ref add). They will be undone in the * reverse order. * * @short Group of commands @ref Command * @author Pete Goodliffe * @version 3.00 */ class CommandGroup : public Command { public: /** * Creates an initially empty CommandGroup. Add @ref Command * objects with @ref add. * * You may specify a name for the group, or leave it blank. * If you leave it blank then the first @ref Command added * will give its name to the CommandGroup. * * @param title Command name for CommandGroup */ CommandGroup(const std::string &title = ""); virtual ~CommandGroup(); /** * Adds a @ref Command to the group. You can keep doing this * up to the first time you call @ref Command::execute. * * After the CommandGroup has been executed, this function * will do nothing. * * When you insert the @ref Command you bind it's lifetime * to the lifetime of this @ref CommandGroup. * * You may have already executed this command prior to * inserting it, in which case it will not be run on the * first CommandGroup execute. You may need to be careful * when doing this to ensure you know that Commands won't * interfere with one another. * * @param command New @ref Command to add to the CommandGroup */ void add(Command *command); /** * Returns the number of @ref Command objects that have * been added to this CommandGroup (see @ref add). * * @return Number of @ref Command objects in this CommandGroup */ size_t size() const { return cmds.size(); } protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: CommandGroup(const CommandGroup &); const CommandGroup &operator=(const CommandGroup &); std::vector cmds; bool canAdd; }; } } #endif tse3-0.3.1/src/tse3/cmd/Makefile.am0000644000175700001440000000101510271145576013566 00000000000000tse3comh_HEADERS = Command.h CommandGroup.h CommandHistory.h FlagTrack.h Song.h Track.h Part.h Phrase.h tse3comhdir = $(pkgincludedir)/cmd noinst_LTLIBRARIES = libtse3cmd.la libtse3cmd_la_SOURCES = CommandGroup.cpp CommandHistory.cpp FlagTrack.cpp Song.cpp Track.cpp Part.cpp Phrase.cpp DISTCLEANFILES = ./.deps/* ./.deps/.P INCLUDES = -I$(top_srcdir)/src #noinst_PROGRAMS = test #test_SOURCES = test.cpp #test_LDFLAGS = -L$(top_builddir)/src/tse3 -L$(top_builddir)/src/tse3/commands #test_LDADD = -ltse3 -ltse3_commands tse3-0.3.1/src/tse3/cmd/Makefile.in0000644000175700017570000004036510302622112013602 00000000000000# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ SOURCES = $(libtse3cmd_la_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/tse3/cmd DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(tse3comh_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libtse3cmd_la_LIBADD = am_libtse3cmd_la_OBJECTS = CommandGroup.lo CommandHistory.lo \ FlagTrack.lo Song.lo Track.lo Part.lo Phrase.lo libtse3cmd_la_OBJECTS = $(am_libtse3cmd_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libtse3cmd_la_SOURCES) DIST_SOURCES = $(libtse3cmd_la_SOURCES) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(tse3comhdir)" tse3comhHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(tse3comh_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPP_MM = @CPP_MM@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ HAVE_ALSA_FALSE = @HAVE_ALSA_FALSE@ HAVE_ALSA_TRUE = @HAVE_ALSA_TRUE@ HAVE_ARTS_FALSE = @HAVE_ARTS_FALSE@ HAVE_ARTS_TRUE = @HAVE_ARTS_TRUE@ HAVE_OSS_FALSE = @HAVE_OSS_FALSE@ HAVE_OSS_TRUE = @HAVE_OSS_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTALL_TSE3_DOC_FALSE = @INSTALL_TSE3_DOC_FALSE@ INSTALL_TSE3_DOC_TRUE = @INSTALL_TSE3_DOC_TRUE@ LDFLAGS = @LDFLAGS@ LIBARTS = @LIBARTS@ LIBASOUND = @LIBASOUND@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TSE3_ALSA_PREFIX = @TSE3_ALSA_PREFIX@ TSE3_ALSA_VERSION = @TSE3_ALSA_VERSION@ TSE3_ARTS_PREFIX = @TSE3_ARTS_PREFIX@ TSE3_WITH_ALSA = @TSE3_WITH_ALSA@ TSE3_WITH_ALSA_0_5_X = @TSE3_WITH_ALSA_0_5_X@ TSE3_WITH_ALSA_0_5_X_FALSE = @TSE3_WITH_ALSA_0_5_X_FALSE@ TSE3_WITH_ALSA_0_5_X_TRUE = @TSE3_WITH_ALSA_0_5_X_TRUE@ TSE3_WITH_ALSA_0_9_X = @TSE3_WITH_ALSA_0_9_X@ TSE3_WITH_ALSA_0_9_X_FALSE = @TSE3_WITH_ALSA_0_9_X_FALSE@ TSE3_WITH_ALSA_0_9_X_TRUE = @TSE3_WITH_ALSA_0_9_X_TRUE@ TSE3_WITH_ALSA_FALSE = @TSE3_WITH_ALSA_FALSE@ TSE3_WITH_ALSA_TRUE = @TSE3_WITH_ALSA_TRUE@ TSE3_WITH_ARTS = @TSE3_WITH_ARTS@ TSE3_WITH_ARTS_FALSE = @TSE3_WITH_ARTS_FALSE@ TSE3_WITH_ARTS_TRUE = @TSE3_WITH_ARTS_TRUE@ TSE3_WITH_OSS = @TSE3_WITH_OSS@ TSE3_WITH_OSS_FALSE = @TSE3_WITH_OSS_FALSE@ TSE3_WITH_OSS_TRUE = @TSE3_WITH_OSS_TRUE@ TSE3_WITH_WIN32 = @TSE3_WITH_WIN32@ TSE3_WITH_WIN32_FALSE = @TSE3_WITH_WIN32_FALSE@ TSE3_WITH_WIN32_TRUE = @TSE3_WITH_WIN32_TRUE@ VERSION = @VERSION@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ prefix = @prefix@ program_transform_name = @program_transform_name@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ tse3comh_HEADERS = Command.h CommandGroup.h CommandHistory.h FlagTrack.h Song.h Track.h Part.h Phrase.h tse3comhdir = $(pkgincludedir)/cmd noinst_LTLIBRARIES = libtse3cmd.la libtse3cmd_la_SOURCES = CommandGroup.cpp CommandHistory.cpp FlagTrack.cpp Song.cpp Track.cpp Part.cpp Phrase.cpp DISTCLEANFILES = ./.deps/* ./.deps/.P INCLUDES = -I$(top_srcdir)/src all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tse3/cmd/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/tse3/cmd/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libtse3cmd.la: $(libtse3cmd_la_OBJECTS) $(libtse3cmd_la_DEPENDENCIES) $(CXXLINK) $(libtse3cmd_la_LDFLAGS) $(libtse3cmd_la_OBJECTS) $(libtse3cmd_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CommandGroup.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CommandHistory.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FlagTrack.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Part.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Phrase.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Song.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Track.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: install-tse3comhHEADERS: $(tse3comh_HEADERS) @$(NORMAL_INSTALL) test -z "$(tse3comhdir)" || $(mkdir_p) "$(DESTDIR)$(tse3comhdir)" @list='$(tse3comh_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(tse3comhHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(tse3comhdir)/$$f'"; \ $(tse3comhHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(tse3comhdir)/$$f"; \ done uninstall-tse3comhHEADERS: @$(NORMAL_UNINSTALL) @list='$(tse3comh_HEADERS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(tse3comhdir)/$$f'"; \ rm -f "$(DESTDIR)$(tse3comhdir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(tse3comhdir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-tse3comhHEADERS install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am uninstall-tse3comhHEADERS .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip install-tse3comhHEADERS installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-info-am \ uninstall-tse3comhHEADERS #noinst_PROGRAMS = test #test_SOURCES = test.cpp #test_LDFLAGS = -L$(top_builddir)/src/tse3 -L$(top_builddir)/src/tse3/commands #test_LDADD = -ltse3 -ltse3_commands # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: tse3-0.3.1/src/tse3/cmd/Phrase.cpp0000644000175700001440000001521410271145576013466 00000000000000/* * @(#)Phrase.cpp 3.00 21 November 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/cmd/Phrase.h" #include "tse3/Song.h" #include "tse3/Part.h" #include "tse3/Phrase.h" #include "tse3/PhraseEdit.h" #include "tse3/PhraseList.h" #include "tse3/Error.h" #include "tse3/util/Song.h" using namespace TSE3; using namespace TSE3::Cmd; /****************************************************************************** * Phrase_SetInfo class *****************************************************************************/ Phrase_SetInfo::Phrase_SetInfo(TSE3::Phrase *phrase, const std::string &title, const TSE3::DisplayParams &dp) : Command("phrase info"), phrase(phrase), newTitle(title), dp(dp) { if (!phrase->parent()) { throw TSE3::PhraseListError(TSE3::PhraseUnparentedErr); } if (title.size() && phrase->parent()->phrase(title)) { if (phrase->parent()->phrase(title) != phrase) { throw TSE3::PhraseListError(TSE3::PhraseNameExistsErr); } else { newTitle = ""; } } } void Phrase_SetInfo::executeImpl() { oldTitle = phrase->title(); if (newTitle.size()) phrase->setTitle(newTitle); std::swap(dp, *(phrase->displayParams())); } void Phrase_SetInfo::undoImpl() { if (newTitle.size()) phrase->setTitle(oldTitle); std::swap(dp, *(phrase->displayParams())); } /****************************************************************************** * Phrase_Create class *****************************************************************************/ Phrase_Create::Phrase_Create(TSE3::PhraseList *pl, TSE3::PhraseEdit *pe, const std::string &t) : Command("create phrase"), phraseList(pl), phraseEdit(pe), newPhrase(0), title(t) { if (phraseList->phrase(title)) { throw TSE3::PhraseListError(TSE3::PhraseNameExistsErr); } } Phrase_Create::~Phrase_Create() { if (!done()) { delete newPhrase; } } void Phrase_Create::executeImpl() { if (!newPhrase) { newPhrase = phraseEdit->createPhrase(phraseList, title); } else { phraseList->insert(newPhrase); } } void Phrase_Create::undoImpl() { phraseList->remove(newPhrase); } /****************************************************************************** * Phrase_Erase class *****************************************************************************/ Phrase_Erase::Phrase_Erase(TSE3::Phrase *phrase, TSE3::Song *song) : Command("erase phrase"), phrase(phrase), song(song), vector_done(false) { if (!song || phrase->parent() != song->phraseList()) { // phrase == 0 means that the operation is invalid, either // 1) the parents don't match, or // 2) the Phrase has no parent phrase = 0; } } Phrase_Erase::~Phrase_Erase() { if (phrase && done()) { delete phrase; } } void Phrase_Erase::executeImpl() { if (!phrase) return; if (song) { TSE3::PhraseList *phraseList = song->phraseList(); if (phraseList->index(phrase) != phraseList->size()) { if (!vector_done) { Util::Song_SearchForPhrase(song, phrase, parts); vector_done = true; } phraseList->remove(phrase); } else { phrase = 0; } } else { phrase->parent()->remove(phrase); } } void Phrase_Erase::undoImpl() { if (phrase) { song->phraseList()->insert(phrase); std::vector::iterator i = parts.begin(); while (i != parts.end()) { (*i)->setPhrase(phrase); i++; } } } /****************************************************************************** * Phrase_Replace class *****************************************************************************/ Phrase_Replace::Phrase_Replace(TSE3::Phrase *newPhrase, TSE3::Phrase *oldPhrase, TSE3::Song *song) : Command("replace phrase"), newPhrase(newPhrase), oldPhrase(oldPhrase), phraseEdit(0), song(song) { Util::Song_SearchForPhrase(song, oldPhrase, parts); } Phrase_Replace::Phrase_Replace(TSE3::Phrase *oldPhrase, TSE3::PhraseEdit *pe, TSE3::Song *song, const std::string &title) : Command("replace phrase"), newPhrase(0), oldPhrase(oldPhrase), phraseEdit(pe), song(song), newTitle(title) { Util::Song_SearchForPhrase(song, oldPhrase, parts); } Phrase_Replace::~Phrase_Replace() { if (done()) { delete oldPhrase; } else { delete newPhrase; } } void Phrase_Replace::executeImpl() { TSE3::PhraseList *phraseList = song->phraseList(); if (newPhrase && !phraseEdit) { // Just a simple swap between two Phrases in the PhraseList } else if (newPhrase) { // Redo of a created Phrase from next case... phraseList->remove(oldPhrase); phraseList->insert(newPhrase); } else { // Create a new phrase phraseList->remove(oldPhrase); if (newTitle.size() == 0) { newPhrase = phraseEdit->createPhrase(phraseList, oldPhrase->title()); } else { newPhrase = phraseEdit->createPhrase(phraseList, newTitle); } // We won't actually dereference PhraseEdit again, (it might now // get deleted) but we keep the pointer to remember what kind of // operation this is. } std::vector::iterator i = parts.begin(); while (i != parts.end()) { (*i)->setPhrase(newPhrase); ++i; } } void Phrase_Replace::undoImpl() { TSE3::PhraseList *phraseList = song->phraseList(); if (phraseEdit) { phraseList->remove(newPhrase); phraseList->insert(oldPhrase); } std::vector::iterator i = parts.begin(); while (i != parts.end()) { (*i)->setPhrase(oldPhrase); ++i; } } tse3-0.3.1/src/tse3/cmd/Track.cpp0000644000175700001440000002711210271145576013310 00000000000000/* * @(#)Track.cpp 3.00 8 July 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/cmd/Track.h" #include "tse3/Track.h" #include "tse3/Part.h" #include "tse3/Song.h" #include "tse3/MidiFilter.h" #include "tse3/app/TrackSelection.h" #include #include #include using namespace TSE3; using namespace TSE3::Cmd; /****************************************************************************** * Track_SetInfo class *****************************************************************************/ Track_SetInfo::Track_SetInfo(TSE3::Track *track, const std::string &title, const TSE3::MidiFilter &smef, const TSE3::MidiParams &mp, const TSE3::DisplayParams &dp) : Command("track info"), track(track), newTitle(title), smef(smef), mp(mp), dp(dp) { } void Track_SetInfo::executeImpl() { oldTitle = track->title(); track->setTitle(newTitle); std::swap(smef, *(track->filter())); std::swap(mp, *(track->params())); std::swap(dp, *(track->displayParams())); } void Track_SetInfo::undoImpl() { track->setTitle(oldTitle); std::swap(smef, *(track->filter())); std::swap(mp, *(track->params())); std::swap(dp, *(track->displayParams())); } /****************************************************************************** * Track_Snip class *****************************************************************************/ Track_Snip::Track_Snip(TSE3::Track *track, TSE3::Clock snipTime) : Command("snip part"), track(track), snipTime(snipTime), valid(false), shouldDelete(false) { size_t pos = track->index(snipTime); if (pos < track->size() && (*track)[pos]->start() < snipTime) { oldPart = (*track)[pos]; oldEndTime = oldPart->end(); newPart = new Part(*oldPart); valid = true; shouldDelete = true; // Work out new Part's parameters newPart->setStart(snipTime); TSE3::Clock phraseStart = oldPart->start(); if (oldPart->repeat()) { while (phraseStart+oldPart->repeat() <= snipTime) { phraseStart += oldPart->repeat(); } } newPart->filter()->setOffset(snipTime - phraseStart + oldPart->filter()->offset()); if (oldPart->repeat()) { while (newPart->filter()->offset() >= newPart->repeat()) { newPart->filter()->setOffset(newPart->filter()->offset() - newPart->repeat()); } } } } Track_Snip::~Track_Snip() { if (shouldDelete) { delete newPart; } } void Track_Snip::executeImpl() { if (valid) { oldPart->setEnd(snipTime); track->insert(newPart); shouldDelete = false; } } void Track_Snip::undoImpl() { if (valid) { track->remove(newPart); oldPart->setEnd(oldEndTime); shouldDelete = true; } } /****************************************************************************** * Track_Glue class *****************************************************************************/ bool Track_Glue::valid(TSE3::Track *track, TSE3::Clock glueTime) { size_t pos = track->index(glueTime); if (pos != 0 && pos != track->size() && (*track)[pos]->start() <= glueTime) { if ((*track)[pos-1]->end() == (*track)[pos]->start()) { return true; } } return false; } Track_Glue::Track_Glue(TSE3::Track *track, TSE3::Clock glueTime) : Command("glue parts"), track(track), glueTime(glueTime), _valid(valid(track, glueTime)), oldPart(0) { if (_valid) { pos = track->index(glueTime); oldEndTime = (*track)[pos]->start(); } } Track_Glue::~Track_Glue() { delete oldPart; } void Track_Glue::executeImpl() { if (_valid) { oldPart = (*track)[pos]; track->remove(pos); (*track)[pos-1]->setEnd(oldPart->end()); } } void Track_Glue::undoImpl() { if (_valid) { (*track)[pos-1]->setEnd(oldEndTime); track->insert(oldPart); oldPart = 0; } } /****************************************************************************** * Track_RemovePart class *****************************************************************************/ Track_RemovePart::Track_RemovePart(Part *p) : Command("remove part"), track(p->parent()), part(p), partno(0) { if (!track) part=0; } Track_RemovePart::Track_RemovePart(Track *t, size_t p) : Command("remove part"), track(t), part(NULL), partno(p) { } Track_RemovePart::Track_RemovePart(Track *t, Part *p) : Command("remove part"), track(t), part(p), partno(0) { } Track_RemovePart::~Track_RemovePart() { if (done()) { delete part; } } void Track_RemovePart::executeImpl() { if (!part && partno < (int)track->size()) { part = (*track)[partno]; } else { partno = track->index(part); } track->remove(part); } void Track_RemovePart::undoImpl() { if (part) { track->insert(part); } } /****************************************************************************** * Track_Sort class *****************************************************************************/ class TSE3::Cmd::Track_SortImpl { public: Track_SortImpl(TSE3::Song *song, TSE3::Cmd::Track_Sort::SortBy by, TSE3::Cmd::Track_Sort::SortOrder order, TSE3::App::TrackSelection *selection) : song(song), by(by), order(order), selection(selection) { for (size_t trk = 0; trk < song->size(); ++trk) { original_order.push_back((*song)[trk]); } if (selection) { std::copy(selection->begin(), selection->end(), std::back_inserter(selected_tracks)); } comparator = &Track_SortImpl::compare_name; switch (by) { case Track_Sort::ByName: { comparator = &Track_SortImpl::compare_name; break; } case Track_Sort::ByMuted: { comparator = &Track_SortImpl::compare_muted; break; } case Track_Sort::BySelected: { comparator = &Track_SortImpl::compare_selected; break; } case Track_Sort::ByPort: { comparator = &Track_SortImpl::compare_port; break; } case Track_Sort::ByChannel: { comparator = &Track_SortImpl::compare_channel; break; } case Track_Sort::BySize: { comparator = &Track_SortImpl::compare_size; break; } } } void executeImpl(); void undoImpl(); private: typedef bool (Track_SortImpl::*comparator_t)(size_t,size_t); TSE3::Song *song; TSE3::Cmd::Track_Sort::SortBy by; TSE3::Cmd::Track_Sort::SortOrder order; TSE3::App::TrackSelection *selection; std::vector original_order; std::vector selected_tracks; comparator_t comparator; void swap(size_t index1, size_t index2); bool compare(size_t index1, size_t index2); bool compare_name(size_t index1, size_t index2); bool compare_muted(size_t index1, size_t index2); bool compare_selected(size_t index1, size_t index2); bool compare_port(size_t index1, size_t index2); bool compare_channel(size_t index1, size_t index2); bool compare_size(size_t index1, size_t index2); void reselectTracks(); }; void TSE3::Cmd::Track_SortImpl::executeImpl() { for (size_t trk = 0; trk < song->size(); ++trk) { size_t bestMatch = trk; for (size_t subtrk = trk+1; subtrk < song->size(); ++subtrk) { bool comparison = (this->*comparator)(bestMatch, subtrk); comparison ^= order; if (comparison) { bestMatch = subtrk; } } swap(trk, bestMatch); } reselectTracks(); } void Track_SortImpl::undoImpl() { while (song->size()) { song->remove((size_t)0); } std::vector::iterator i = original_order.begin(); while (i != original_order.end()) { song->insert(*i); ++i; } reselectTracks(); } void Track_SortImpl::reselectTracks() { if (selection) { std::vector::iterator i = selected_tracks.begin(); while (i != selected_tracks.end()) { selection->select(*i, true); ++i; } } } void Track_SortImpl::swap(size_t index1, size_t index2) { if (index1 == index2) return; if (index2 < index1) { std::swap(index1, index2); } TSE3::Track *track1 = (*song)[index1]; TSE3::Track *track2 = (*song)[index2]; song->remove(index2); song->insert(track2, index1); song->remove(index1+1); song->insert(track1, index2); } bool Track_SortImpl::compare_name(size_t index1, size_t index2) { return (*song)[index1]->title().compare((*song)[index2]->title()) > 0; } bool Track_SortImpl::compare_muted(size_t index1, size_t index2) { return (*song)[index1]->filter()->status() > (*song)[index2]->filter()->status(); } bool Track_SortImpl::compare_selected(size_t index1, size_t index2) { bool res1 = std::find(selected_tracks.begin(), selected_tracks.end(), (*song)[index1]) != selected_tracks.end(); bool res2 = std::find(selected_tracks.begin(), selected_tracks.end(), (*song)[index2]) != selected_tracks.end(); return res1 < res2; } bool Track_SortImpl::compare_port(size_t index1, size_t index2) { return (*song)[index1]->filter()->port() > (*song)[index2]->filter()->port(); } bool Track_SortImpl::compare_channel(size_t index1, size_t index2) { return (*song)[index1]->filter()->channel() > (*song)[index2]->filter()->channel(); } bool Track_SortImpl::compare_size(size_t index1, size_t index2) { return (*song)[index1]->size() > (*song)[index2]->size(); } Track_Sort::Track_Sort(Song *song, SortBy by, SortOrder order, TSE3::App::TrackSelection *selection) : Command("sort tracks"), pimpl(new Track_SortImpl(song, by, order, selection)) { } Track_Sort::~Track_Sort() { delete pimpl; } void Track_Sort::executeImpl() { pimpl->executeImpl(); } void Track_Sort::undoImpl() { pimpl->undoImpl(); } tse3-0.3.1/src/tse3/cmd/Command.h0000644000175700001440000001647410271145576013300 00000000000000/* * @(#)cmd/Command.h 3.00 10 June 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_CMD_COMMAND_H #define TSE3_CMD_COMMAND_H #include namespace TSE3 { /** * The Cmd namespace contains classes that implement the Command * pattern (GoF book). They use the @ref TSE3 API to provide undo/redoable * commands objects for all commonly performed operations. * * There are a large number of commands that can be used for different * purposes. The base class for all @ref TSE3 commands is the * @ref Command. There exists one command class for every useful * operation on the @ref TSE3::Song data structure and it's subcomponents. * * There is one proviso with using commands: if you manipulate some * of a @ref TSE3::Song with commands, for the undo/redo to work you * must (logically) manipulate the @ref TSE3::Song entirely through * @ref Command objects. Otherwise the undo/redo system will be * faced with complicated inconsistencies which cannot be resolved. * * You can store executed @ref Command objects on the * @ref CommandHistory buffer to automate the undo/redo process. * * @ref Command subclasses are easy to write, so it's not difficult * to add your own commands and use them with the @ref CommandHistory. * See the notes in the main TSE3 library documentation for more * information. * * @short @ref TSE3 library undo/redoable commands * @author Pete Goodliffe * @version 3.00 * @see TSE3 */ namespace Cmd { /** * A base class for implementing the 'Command' design pattern [Gof] * * If you are implementing a new Command then inherit publicly * from this class, implement the @ref executeImpl() and * @ref undoImpl() methods and ensure that your constructor calls the * Command protected constructor. * * @short Base command class * @author Pete Goodliffe * @version 3.00 */ class Command { public: virtual ~Command() {} /** * Call this to execute the Command. * * If the Command has already been executed, nothing will * happen. * * @see undo */ void execute() { if (!_done) { executeImpl(); _done = true; } } /** * Call this to undo the Command. * * If the Command can't be undone, or it has already been * undone, then nothing will happen. */ void undo() { if (_done && _undoable) { undoImpl(); _done = false; } } /** * Returns a descriptive string for the command. * * The string begins with a lower case letter and is capable * of following "Undo " or "Redo ". */ const std::string &title() const { return _title; } /** * Returns whether this Command is capable of being undone. */ bool undoable() const { return _undoable; } /** * Returns whether this command has been executed. * * @see execute * @see undo */ bool done() const { return _done; } protected: /** * Create a Command with a descriptive string. This must begin * with a lower case letter and be capable of following "Undo " * or "Redo ". * * @param title Name for Command * @param undoable Whether the Command is undoable */ Command(const std::string &title, bool undoable = true) : _title(title), _undoable(undoable), _done(false) {} /** * Implementations of Command override this method to implement * the execute action. */ virtual void executeImpl() = 0; /** * Implementations of Command override this method to implement * to undo action. */ virtual void undoImpl() = 0; /** * Sets the Command title. Normally you will do this in * the ctor and never use this. */ void setTitle(const std::string &title) { _title = title; } private: std::string _title; bool _undoable; bool _done; }; /** * A template class for implementing @ref Command objects that set a * particular class' variable state. * * The template takes five parameters: * @li cls_type - the type of the class to be altered * @li arg_type - the type of variable being set * @li param_type - the type of variable that is accepted as a parameter * @li getmfn - cls_type's method to read the variable, * returns param_type * @li setmfn - cls_type's method to set the variable, takes * param_type * * @short Variable setting command template class * @author Pete Goodliffe * @version 3.00 */ template class VariableSetCommand : public Command { public: VariableSetCommand(cls_type *cls, param_type arg, const std::string &title) : Command(title), cls(cls), arg(arg) {} virtual ~VariableSetCommand() {} protected: /** * @reimplemented */ virtual void executeImpl() { old = (cls->*getmfn)(); (cls->*setmfn)(arg); } /** * @reimplemented */ virtual void undoImpl() { (cls->*setmfn)(old); } private: cls_type *cls; arg_type arg; arg_type old; }; } } #endif tse3-0.3.1/src/tse3/cmd/Song.cpp0000644000175700001440000000736510302616164013151 00000000000000/* * @(#)Song.cpp 3.00 10 Nov 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/cmd/Song.h" #include "tse3/Song.h" #include "tse3/Track.h" #include "tse3/Part.h" #include "tse3/util/Song.h" #include #include using namespace TSE3; using namespace TSE3::Cmd; /****************************************************************************** * Song_SetInfo class *****************************************************************************/ Song_SetInfo::Song_SetInfo(TSE3::Song *s, const std::string &title, const std::string &author, const std::string ©right, const std::string &date) : Command("song info"), song(s), newTitle(title), newAuthor(author), newCopyright(copyright), newDate(date) { } void Song_SetInfo::executeImpl() { // Save old info oldTitle = song->title(); oldAuthor = song->author(); oldCopyright = song->copyright(); oldDate = song->date(); // Set new info song->setTitle(newTitle); song->setAuthor(newAuthor); song->setCopyright(newCopyright); song->setDate(newDate); } void Song_SetInfo::undoImpl() { song->setTitle(oldTitle); song->setAuthor(oldAuthor); song->setCopyright(oldCopyright); song->setDate(oldDate); } /****************************************************************************** * Song_InsertTrack class *****************************************************************************/ Song_InsertTrack::Song_InsertTrack(Song *s, size_t t) : Command("insert track"), song(s), track(t) { if (t > song->size()) { // Invalid parameter track = -1; } } void Song_InsertTrack::executeImpl() { if (track != -1) { song->insert(track); } } void Song_InsertTrack::undoImpl() { if (track != -1) { Track *t = (*song)[track]; song->remove(track); delete t; } } /****************************************************************************** * Song_RemoveTrack class *****************************************************************************/ Song_RemoveTrack::Song_RemoveTrack(Track *t) : Command("remove track"), song(t->parent()), track(t), trackno(0) { if (!song) track=0; } Song_RemoveTrack::Song_RemoveTrack(Song *s, size_t t) : Command("remove track"), song(s), track(NULL), trackno(t) { } Song_RemoveTrack::Song_RemoveTrack(Song *s, Track *t) : Command("remove track"), song(s), track(t), trackno(0) { } Song_RemoveTrack::~Song_RemoveTrack() { if (done()) { delete track; } } void Song_RemoveTrack::executeImpl() { if (!track && trackno < (int)song->size()) { track = (*song)[trackno]; } else { trackno = song->index(track); } song->remove(track); } void Song_RemoveTrack::undoImpl() { if (track) { song->insert(track, trackno); } } /****************************************************************************** * Song_SoloTrack class *****************************************************************************/ Song_SoloTrack::Song_SoloTrack(Song *s, int track) : Command("solo track"), song(s), track(track) { } void Song_SoloTrack::executeImpl() { old = song->soloTrack(); song->setSoloTrack(track); } void Song_SoloTrack::undoImpl() { song->setSoloTrack(old); } tse3-0.3.1/src/tse3/cmd/CommandHistory.h0000644000175700001440000001505210271145576014651 00000000000000/* * @(#)cmd/CommandHistory.h 3.00 10 June 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_CMD_COMMANDHISTORY_H #define TSE3_CMD_COMMANDHISTORY_H #include "tse3/listen/cmd/CommandHistory.h" #include "tse3/Notifier.h" #include "tse3/cmd/Command.h" #include #include namespace TSE3 { namespace Cmd { /** * The history of which @ref Command objects have been executed. Once a * @ref Command has been executed, it should be placed into the * CommandHistory so that an undo/redo mechanism can be operated by the * user. * * In the TSE3 system there could be be one CommandHistroy object per * @ref TSE3::Song or one global CommandHistory. * * When the availablity of either undos or redos changes, a notification * is sent. * * The CommandHistory class has a size limit facility. When either the * undo or redo list goes over a certain threshold (see @ref limit) * @ref Commands will be deleted. This can be set to 'infinite'. * * @short History of which @ref Command objects have been executed * @author Pete Goodliffe * @version 3.00 * @see Command */ class CommandHistory : public TSE3::Notifier { public: /** * Create a CommandHistory with the given limit size. * This limit defaults to the value of @ref defaultLimit. * * @param limit CommandHistory size limit */ CommandHistory(int limit = defaultLimit); /** * Adds a @ref Command to the CommandHistory. The @ref Command * must have been executed. Placing it in the CommandHistory * ties it's lifetime to that of the CommandHistory object. * * Adding a @ref Command will wipe any redos that may have been * possible. * * @param command New @ref Command to add */ void add(Command *command); /** * Returns whether there are any @ref Command objects that can * be undone. * * When this information changes a notification will be sent. * * @return True if there are any undos */ bool undos() const; /** * Undoes the last @ref Command, and places it on the redo list. */ void undo(); /** * Returns the command @p places down in the undo history. * For example, undoCommand(0) returns the next @ref Command * to be undone. * * If there is no command to be undone at this @p pos then * returns zero. * * @param pos Index into undo history * @return @ref Command at this position */ Command *undoCommand(size_t pos); /** * Returns whether there are any @ref Command objects that can * be redone. * * When this information changes a notification will be sent. * * @return True if there are any redos */ bool redos() const; /** * Redoes the last undone @ref Command. */ void redo(); /** * Returns the command @p places down in the redo history. * For example, redoCommand(0) returns the next @ref Command * to be redone. * * If there is no command to be redone at this @p pos then * returns zero. * * @param pos Index into redo history * @return @ref Command at this position */ Command *redoCommand(size_t pos); /** * Returns the value of the history size limit. This is the * number of @ref Command objects that are stored. * * If the value is -1 then the number of undos is unlimited. * * Clearly, if the value is 0 then undo is effectively 'off'. * * @return CommandHistory size limit */ int limit() const; /** * Sets the CommandHistory limit value. If there are more * @ref Command objects than the new limit currently in the * CommandHistory, they will be removed. * * @param limit New CommandHistory size limit */ void setLimit(int limit); /** * Clears all undo and redo actions in the CommandHistory. * * @see clearUndos * @see clearRedos */ void clear() { clearUndos(); clearRedos(); } /** * Clears all undo actions in the CommandHistory. * * @see clear * @see clearRedos */ void clearUndos(); /** * Clears all redo actions in the CommandHistory. * * @see clear * @see clearUndos */ void clearRedos(); /** * The default CommandHistory limit size. */ static const int defaultLimit = 20; private: int _limit; std::list undolist; std::list redolist; }; } } #endif tse3-0.3.1/src/tse3/cmd/Track.h0000644000175700001440000002277210271145576012764 00000000000000/* * @(#)cmd/Track.h 3.00 8 July 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_CMD_TRACK_H #define TSE3_CMD_TRACK_H #include "tse3/cmd/Command.h" #include "tse3/MidiFilter.h" #include "tse3/MidiParams.h" #include "tse3/DisplayParams.h" #include #include namespace TSE3 { class Track; class Part; namespace App { class TrackSelection; } namespace Cmd { /** * Command to set a @ref TSE3::Track's info (the title, it's * @ref TSE3::MidiParams setup and it's @ref TSE3::MidiFilter setup). * * @short Set @ref TSE3::Track info Command * @author Pete Goodliffe * @version 1.00 * @see Command */ class Track_SetInfo : public Command { public: /** * To create this command specify the @ref TSE3::Track object to * alter and the new information. */ Track_SetInfo(TSE3::Track *track, const std::string &title, const TSE3::MidiFilter &smef, const TSE3::MidiParams &mp, const TSE3::DisplayParams &dp); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Track *track; std::string newTitle, oldTitle; TSE3::MidiFilter smef; TSE3::MidiParams mp; TSE3::DisplayParams dp; }; /** * Command to snip a @ref TSE3::Part in a @ref TSE3::Track. * * If there is no @ref TSE3::Part at the specified time, then nothing * will happen, and no error will be raised. It is suggested that * you check that the command is worthwhile before you perform it. * * @short Snip @ref TSE3::Part command * @author Pete Goodliffe * @version 1.00 * @see Command */ class Track_Snip : public Command { public: /** * Create a Track_Snip command for the given @ref TSE3::Track * at the given time. If there is no @ref TSE3::Part at this * time then the command will do nothing. */ Track_Snip(TSE3::Track *track, TSE3::Clock snipTime); virtual ~Track_Snip(); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Track *track; TSE3::Clock snipTime; bool valid; TSE3::Part *oldPart, *newPart; TSE3::Clock oldEndTime; bool shouldDelete; }; /** * Command to glue two @ref TSE3::Part objects in a @ref TSE3::Track. * * If there is no @ref TSE3::Part at the specified time or it is not * directly adjacent to another @ref TSE3::part, then nothing * will happen, and no error will be raised. It is suggested that * you check that the command is worthwhile before you perform it. * You can use the static @ref valid() method to find out whether this * command is valid before performing it. * * @short Snip @ref TSE3::Part command * @author Pete Goodliffe * @version 1.00 * @see Command */ class Track_Glue : public Command { public: /** * Create a Track_Glue command for the given @ref TSE3::Track * at the given time. */ Track_Glue(TSE3::Track *track, TSE3::Clock glueTime); virtual ~Track_Glue(); /** * Returns wether the command for this time is valid. * * To be valid, there must be a @ref TSE3::Part at @p glueTime * and it must directly follow another @ref TSE3::Part object * with no gap inbetween. */ static bool valid(TSE3::Track *track, TSE3::Clock glueTime); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Track *track; TSE3::Clock glueTime; bool _valid; size_t pos; TSE3::Part *oldPart; TSE3::Clock oldEndTime; }; /** * Command to remove a @ref TSE3::Part from a @ref TSE3::Track. * * (Too insert a @ref TSE3::Part use @ref Part_Move.) * * @short Remove Part Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Track_RemovePart : public Command { public: /** * Remove the specified @ref TSE3::Part from it's parent * @ref TSE3::Track. * * @param part @ref TSE3:Part to remove */ Track_RemovePart(TSE3::Part *part); /** * Remove the @ref TSE3::Part specified by the index * @p part in the @ref TSE3::Track @p track. * * @param track @ref TSE3::Track to remove @ref TSE3::Part from * @param part Index of @ref TSE3:Part to remove */ Track_RemovePart(TSE3::Track *track, size_t part); /** * Remove the specified @ref TSE3::Part @p part from the * @ref TSE3::Track @p track. * * @param track @ref TSE3::Track to remove @ref TSE3::Part from * @param part @ref TSE3::Part to remove */ Track_RemovePart(TSE3::Track *track, Part *part); virtual ~Track_RemovePart(); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: TSE3::Track *track; TSE3::Part *part; int partno; }; /** * Command to sort a;; @ref TSE3::Track objects in a @ref TSE3::Song. * * @short Sort Tracks Command * @author Pete Goodliffe * @version 3.00 * @see Command */ class Track_Sort : public Command { public: /** * Describes the Track sort criteria. */ enum SortBy { ByName, ByMuted, BySelected, ByPort, ByChannel, BySize }; /** * Describes the Track sort order */ enum SortOrder { Ascending, Descending }; /** * You specify the @ref TSE3::Song to sort, and the * sort parameters. * * @param song Song to sort Tracks of * @param by Sort criteria * @param order Sort order * @param selection Track selection to use for BySelected * (zero if not supported) */ Track_Sort(TSE3::Song *song, SortBy by, SortOrder order, TSE3::App::TrackSelection *selection = 0); virtual ~Track_Sort(); protected: /** * @reimplemented */ virtual void executeImpl(); /** * @reimplemented */ virtual void undoImpl(); private: class Track_SortImpl *pimpl; }; } } #endif tse3-0.3.1/src/tse3/ins/0000777000175700017570000000000010310240001011627 500000000000000tse3-0.3.1/src/tse3/ins/Destination.h0000644000175700001440000002425210271145611014210 00000000000000/* * @(#)ins/Destination.h 3.00 21 August 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_INS_DESTINATION_H #define TSE3_INS_DESTINATION_H #include "tse3/listen/ins/Destination.h" #include "tse3/Notifier.h" #include #include namespace TSE3 { namespace Ins { /** * The Destination class is a simple utility class that can be used to * associate @ref Instrument definitions with MIDI outputs (channel/port * pairs). * * An application can use this to remember what sort of instrument * definition to use for which output; to present the correct program * change information to the user, for example. * * For each port, you may choose one @ref Instrument for every * channel, or may select a number of different @ref Instrument objects * for the different individual channels. * * You may also leave a particular definition unspecified (as zero). * * The Destination class has a secondary purpose of keeping track of * all the currently used @ref Instrument objects, keeping the * list of desinations up to date if any @ref Instrument is removed. * * Since this class operates independantly of a @ref TSE3::MidiScheduler * it cannot track what port numbers are currently valid, and * which are not. * * @short MIDI destination information utility * @author Pete Goodliffe * @version 3.00 * @see Instrument */ class Destination : public TSE3::Notifier { public: /** * Creates a Destination object. * * Initially no destinations are specified. */ Destination(); ~Destination(); /************************************************************** * Managing the list of destinations *************************************************************/ /** * Returns the default @ref Instrument. * * This is the instrument definition that is returned if * no other mapping has been made. * * By default, this is set to zero. * * @return The default instrument definition * @see setDefaultInstrument */ Instrument *defaultInstrument() const; /** * Sets the default @ref Instrument. * * @param instrument The default definition * @see defaultInstrument */ void setDefaultInstrument(Instrument *instrument); /** * Returns whether there is one @ref Instrument selected for * every channel on this port (true) or whether each channel * is been assigned separately (false). * * @param port Port number to enquire about * @return Whether there is one @ref Instrument for every * channel on this port * @see setPort * @see setChannel */ bool allChannels(int port); /** * Returns the @ref Instrument selected for this entire * port. This instrument is used for every channel on this * port. * * If no instrument has been specified for this @p port, then * port() returns the @ref defaultInstrument. * * If @ref allChannels is false for this @p port then zero * is returned (you have called this in error). * * @param port Port number to enquire about * @return The @ref Instrument selected for this port, or 0 * if no @ref Instrument is specified * @see setPort * @see channel */ Instrument *port(int port); /** * Sets which instrument is used by this port. This will * have the side effect of making @ref allChannels return true. * * You may specify an @p instrument of zero to unspecify * an @ref Instrument definition. * * @param port Port number to set @ref Instrument for * @param instrument @ref Instrument to specify. Whilst it's * not essential that this has been added * with @ref addInstrument, it is advised * to do so. * @see setChannel */ void setPort(int port, Instrument *instrument); /** * Returns the @ref Instrument selected for this channel/port * destination. * * If no instrument has been specified for this port/channel, * then @p port returns @ref defaultInstrument. * * If @ref allChannels is true for this @p port then the * @p channel value is ignored. * * @param port Port number to enquire about * @param channel Channel number to enquire about * @return The @ref Instrument selected for this port, or 0 * if no @ref Instrument is specified * @see setChannel * @see port */ Instrument *channel(int channel, int port); /** * Sets which instrument is used by this channel/port pair. * This will have the side effect of making @ref allChannels * return false. * * You may specify an @p instrument of zero to unspecify * an @ref Instrument definition. * * @param port Port number to set @ref Instrument for * @param channel Channel number to set @ref Instrument for * @param instrument @ref Instrument to specify. Whilst it's * not essential that this has been added * with @ref addInstrument, it is advised * to do so. * @see setChannel */ void setChannel(int channel, int port, Instrument *instrument); /************************************************************** * Managing the list of instruments *************************************************************/ /** * Returns the number of @ref Instrument objects currently * managed by the Destination object. */ size_t numInstruments() const; /** * Returns the @ref Instrument at the given index. * The list of @ref Instrument object is ordered * alphabetically. * * @param index Index into @ref Instrument list (between * 0 and @ref noInstruments()). * @return @ref Instrument object at @p index * @see noInstruments */ Instrument *instrument(size_t index); /** * Returns the @ref Instrument with the given title, * or zero if there is no such @ref Instrument. * * @param title @ref Instrument title to search for * @return @ref Instrument object or 0 */ Instrument *instrument(const std::string &title); /** * Adds the specified @ref Instrument to the list of * @ref Instrument objects. You can only insert a given * @ref Instrument once. The instrument is inserted into the * list in alphabetical order of title. * * The @ref Instrument object is considered to be 'owned' by * the Destination class, and will be deleted when the * Destination is. * * @param instrument New @ref Instrument object to insert * @see removeInstrument */ void addInstrument(Instrument *instrument); /** * Removed the specified @ref Instrument from the list of * @ref Instrument objects. If @p instrument is being used * as a destination, then the destination link is removed. * * Once removed it is your responsibility to delete the * @ref Instrument. * * @param instrument @ref Instrument object to remove * @see addInstrument */ void removeInstrument(Instrument *instrument); private: Destination(const Destination &); Destination &operator=(const Destination &); class DestinationImpl *pimpl; size_t index(int port, int channel) { return (port*16) + channel; } }; } } #endif tse3-0.3.1/src/tse3/ins/Instrument.h0000644000175700001440000006161510271145611014103 00000000000000/* * @(#)ins/Instrument.h 3.00 23 August 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_INS_INSTRUMENT_H #define TSE3_INS_INSTRUMENT_H #include #include #include #include #include namespace TSE3 { class Progress; /** * The @p Ins namespace contains classes that implement the Cakewalk * instrument file parsing routines and provide name lookup for bank/patch * and controller numbers. * * The facilities offered here are utilities that an application may use, * and are not part of the core @ref TSE3 functionality. * * The @ref TSE3::Ins::CakewalkInstrumentFile class is the main entrance * onto @p Ins facilities. * * You can get Cakewalk instrument definition files for practically * every piece of MIDI hardware in existence, which is why they have been * adopted by the TSE3 library. They are most easily obtained from the * @p www.cakewalk.com website; follow the "Download" link and select * "Instrument Definitions". * * @short Utility classes for MIDI instrument definitions * @author Pete Goodliffe * @version 3.00 * @see TSE3 */ namespace Ins { class PatchData; class ControlData; class RpnData; class NrpnData; class NoteData; /** * Bank select values can be expressed as single 14 bit numbers * (Cakewalk instrument files use this format) or as separate LSB and * MSBs (the MIDI format uses this format). * * This function converts a 14 bit bank number into the LSB portion. * If @p bank is -1, returns -1. * * @param bank 14 bit bank select number * @return LSB value * @see bankMSB * @see bankFromBytes */ inline int bankToLSB(int bank) { return (bank < 0) ? bank : bank & 0x7f; } /** * Bank select values can be expressed as single 14 bit numbers * (Cakewalk instrument files use this format) or as separate LSB and * MSBs (the MIDI format uses this format). * * This function converts a 14 bit bank number into the MSB portion. * If @p bank is -1, returns -1. * * @param bank 14 bit bank select number * @return MSB value * @see bankLSB * @see bankFromBytes */ inline int bankToMSB(int bank) { return (bank < 0) ? bank : bank >> 7; } /** * Bank select values can be expressed as single 14 bit numbers * (Cakewalk instrument files use this format) or as separate LSB and * MSBs (the MIDI format uses this format). * * This function converts a bank LSB and MSB into a 14 bit bank number. * If @p bank is -1, returns -1. * * @param bankLSB Bank LSB value * @param bankMSB Bank MSB value * @return bank 14 bit bank select number * @see bankLSB * @see bankMSB */ inline int bankFromBytes(int bankLSB, int bankMSB) { return (bankLSB < 0 || bankMSB < 0) ? -1 : (bankMSB<<7) | bankLSB; } /** * A Voice struct holds information about a voice - the bank and patch * values. It is based on pair where the first in is the * bank value and the second int is the patch value. * * Bank values are defined to be (MSB<<7)+LSB. * * The value -1 denotes a wildcard - it matches any bank/patch. * * This is a value type. * * @short Instrument voice definition * @author Pete Goodliffe * @version 3.00 */ struct Voice : public std::pair { /** * Creates a Voice with the given bank and patch values. * * @param bank New bank value in the form (MSB<<7)+LSB * @param patch New patch value */ Voice(int bank, int patch); /** * Creates a Voice with the given bank and patch values. * * @param bankMSB Bank select MSB * @param bankLSB Bank select LSB * @param patch New patch value */ Voice(int bankMSB, int bankLSB, int patch); /** * Returns the bank value in the form (bankMSB<<7)+bankLSB. */ int bank() const { return first; } /** * Returns the bank MSB value. */ int bankMSB() const { return first >> 7; } /** * Returns the bank LSB value. */ int bankLSB() const { return first & 0x7f; } /** * Returns the patch value. */ int patch() const { return second; } /** * Comparison operator. Compares banks first, then patches. */ int operator <(const Voice &v) const; }; /** * The Instrument class holds information about a specific MIDI * instrument. This includes the voices it provides, control commands * it understands, drum note names and so on. * * The Instrument class is based on the instrument definitions supplied * in Cakewalk .ins instrument definition files. * * @short MIDI Instrument definition * @author Pete Goodliffe * @version 3.00 */ class Instrument { public: /** * Creates an instrument with the given name from information * contained in the given file. This file will be a * Cakewalk .ins file. * * Whilst the file is being loaded, the progess can be reported * via the @ref TSE3::Progess interface. * * @param title The title of this instrument * @param file The file to take input from * @param progess @ref TSE3::Progress callback, or zero for * no callback */ Instrument(const std::string &title, const std::string &filename, TSE3::Progress *progess = 0); /** * Returns the title of this instrument. * * @return Title of this instrument */ const std::string &title() const { return _title; } /** * Returns the filename of the source of the instrument * definition. * * @return Filename of this instrument's definition */ const std::string &filename() const { return _filename; } /** * Sets the title. * * @param title New instrument title */ void setTitle(const std::string &title); /** * Returns the BankSelMethod, the values for this are defined * as the BankSelMethod_XXX constants. * * @return Bank select method */ int bankSelMethod() const { return _bankSelMethod; } /** * Sets the BankSelMethod. * * @param b New bank select method */ void setBankSelMethod(int b); /** * An enum type defining the Instrument's bank select method. * It has the following values * @li @p BankSelMethod_Normal * For normal instruments: uses LSB, MSB and patch. * @li @p BankSelMethod_MSB * For instruments that only use MSB and patch. * @li @p BankSelMethod_LSB * For instruments that only use LSB and patch. * @li @p BankSelMethod_Patch * For instruments that only use patch. */ enum BankSelMethod { BankSelMethod_Normal = 0, BankSelMethod_MSB = 1, BankSelMethod_LSB = 2, BankSelMethod_Patch = 3 }; /** * Returns the UseNotesAsControllers value. * * @return Whenther to use notes as controllers */ bool useNotesAsController() const { return _useNotesAsControllers; } /** * Sets the UseNotesAsControllers value. * * @param u New use notes as controllers value */ void setUseNotesAsControllers(bool u); /** * Returns the number of banks of patch data defined * by this instrument. * * @return Number of banks of patches */ size_t numBanks() const { return banks.size(); } /** * Returns the bank number in the form: *
                     *      bankLSB + (bankMSB<<7)
                     * 
    * for the bank with index @p index. * * If you call this method with an invalid parameter, the * result is undefined. * * @return Bank change values for bank with given index */ int bank(int index) const { return banks[index]; } /** * Returns the bank number in the form: *
                     *      bankLSB + (bankMSB<<7)
                     * 
    * for the bank for @ref Voice @p voice. If there is no such * @ref Voice defined, then -2 will be returned. * * @return Bank change values for bank with given index */ int bank(const Voice &voice) const; /** * Returns the bank LSB for the set of patches with index * @p index. * * If you call this method with an invalid parameter, the * result is undefined. * * @return Bank LSB value for bank with given index * @see bankMSB */ int bankLSB(int index) const; /** * Returns the bank MSB for the set of patches with index * @p index. * * If you call this method with an invalid parameter, the * result is undefined. * * @return Bank MSB value for bank with given index * @see bankLSB */ int bankMSB(int index) const; /** * Returns the @ref PatchData object for the given bank. * * @param index Bank index * @return Pointer to @ref PatchData for bank, or 0 */ PatchData *patch(int index) const { return patches[index]; } /** * Returns the @ref PatchData object for the given bank, or 0 * if there is none. * * Note that this function takes the bank change number (as * read from @ref bank()), not the bank index. * * If there is no PatchData for this bank, then zero is * returned. * * You can specify @p bank as -1 to find the 'catch all' bank, * and if your bank number is undefined, but there is a * ctach all patch set, that will be returned. * * @param bank Bank number * @return Pointer to @ref PatchData for bank, or 0 */ PatchData *patchForBank(int bank) const; /** * Like the @ref patchForBank(int) above, but takes the * LSB and MSB parameters separately. This function actually * fowards responsibility onto the other version. It is * provided as a convenience. * * If either of the LSB or MSB parameters are -1, then the * overal bank value passed on is -1. * * @param bankLSB Bank number LSB * @param bankMSB Bank number MSB * @return Pointer to @ref PatchData for bank, or 0 */ PatchData *patchForBank(int bankLSB, int bankMSB) const; /** * Returns the number of sets of @ref NoteData defined * by this instrument. * * @return Number of patches @ref NoteData objects */ size_t numKeys() const { return keys.size(); } /** * Returns the @ref NoteData with the given @p index. * * If you call this method with an invalid parameter, the * result is undefined. * * @return @ref NoteData for index */ NoteData *key(size_t index) const { return keys[index].second; } /** * Returns the @ref NoteData for the given @ref Voice. * * If there is no such @ref Voice, then zero is returned. * * @return @ref NoteData for index */ NoteData *keyForVoice(const Voice &voice) const; /** * Returns the number of drum statuses defined by this * instrument. * * @return Number of drum statuses */ size_t numDrums() const { return drumFlags.size(); } /** * Returns the drum @ref Voice with the given @p index. * * If you call this method with an invalid parameter, the * result is undefined. * * @return @ref Voice for index */ Voice drum(size_t index) const { return drumFlags[index]; } /** * Returns whether the specified @p voice is defined to be * a drum sound or not (this implies that note data should * be opened in a "drum" editor). * * @return Whether voice is a drum sound */ bool isDrum(const Voice &voice) const; /** * Returns the @ref ControlData for this Instrument, if there * is any defined, or zero if there is none. * * @return ControlData for this instrument */ ControlData *control() const { return _control; } /** * Returns the @ref RpnData for this Instrument, if there * is any defined, or zero if there is none. * * @return RpnData for this instrument */ RpnData *rpn() const { return _rpn; } /** * Returns the @ref NrpnData for this Instrument, if there * is any defined, or zero if there is none. * * @return NrpnData for this instrument */ NrpnData *nrpn() const { return _nrpn; } /** * Write the minimal .ins file for this instrument. * * @param out ostream to write output to */ void write(std::ostream &out); private: /** * Loads the instrument from the given .ins file. * Pre: title has been set up already. Other values have * defaults. */ void load(std::istream &in, TSE3::Progress *progress); /** * Parses a line of the instrument definition. * The istream is not used, but may be passed onto child * objects. */ void parseLine(const std::string &line, std::istream &in); std::string _title; std::string _filename; int _bankSelMethod; bool _useNotesAsControllers; std::vector patches; std::vector banks; std::vector > keys; std::vector drumFlags; ControlData *_control; RpnData *_rpn; NrpnData *_nrpn; }; /** * A base class for instrument data: many .ins file sections are based * on simple lists of 0..127 values. This is a base class for such * lists. * * @short Instrument data container class * @author Pete Goodliffe * @version 3.00 */ class InstrumentData { public: /** * Returns the title of this data group. * * @return Title of the data group */ const std::string &title() const { return _title; } /** * Returns the name of the item with the given @p index. * the index value must be between 0 and 127, or the results * are undefined. * * If no name has been defined for this element, returns * an empty string. * * @return Name of the data element */ const std::string &name(size_t index) const { std::string *s = _names[index]; return s ? *s : empty; } /** * Write the .ins file subsection. * * @param out ostream to write output to */ void write(std::ostream &out) const; protected: /** * Contructor is private since this is a base class. */ InstrumentData(std::string const &title, std::string const &insHeading, std::istream &in); /** * The .ins file heading for this section type. Derived classes * MUST override this for load) to work. * * @see load */ const std::string insHeading; /** * Loads the subsection 'secname' from the .ins section * 'insHeading'. * Pre: title and insHeading have been set up. */ void load(const std::string &secname, std::istream &in); std::string _title; std::string *_names[128]; static std::string empty; }; /** * This class represents a group of related patches - they will have * the same bank select values. * * @short Instrument patch data group * @author Pete Goodliffe * @version 3.00 */ class PatchData : public InstrumentData { public: PatchData(std::string const &title, std::istream &in) : InstrumentData(title, ".Patch Names", in) {} }; /** * This class represents a group of note names. * * @short Instrument note data group * @author Pete Goodliffe * @version 3.00 */ class NoteData : public InstrumentData { public: NoteData(std::string const &title, std::istream &in) : InstrumentData(title, ".Note Names", in) {} }; /** * This class represents a group of MIDI control change defintions. * * @short Instrument MIDI controller data group * @author Pete Goodliffe * @version 3.00 */ class ControlData : public InstrumentData { public: ControlData(std::string const &title, std::istream &in) : InstrumentData(title, ".Controller Names", in) {} }; /** * This class represents a group of NRPN defintions. * * @short Instrument NRPN data group * @author Pete Goodliffe * @version 3.00 */ class NrpnData : public InstrumentData { public: NrpnData(std::string const &title, std::istream &in) : InstrumentData(title, ".NRPN Names", in) {} }; /** * This class represents a group of RPN defintions. * * @short Instrument RPN data group * @author Pete Goodliffe * @version 3.00 */ class RpnData : public InstrumentData { public: RpnData(std::string const &title, std::istream &in) : InstrumentData(title, ".RPN Names", in) {} }; /** * The class represents a Cakewalk .ins file. * * It provides a mechanism for listing all instruments provided by a * particular .ins file, and for creating an Instrument object from it. * * The .ins file format is not documented. However, the documentation * that ships with the TSE3 library contains a description of this * format. * * @short Cakewalk .ins file parser * @author Pete Goodliffe * @version 3.00 * @see Instrument */ class CakewalkInstrumentFile { public: /** * Create an object for the given file. * * @param filename The name of the Cakewalk .ins file */ CakewalkInstrumentFile(const std::string &filename); /** * Returns a set of the instrument titles in the .ins file. * * The first time you call this method, the file will be * searched. Whilst this is being done you can be informted * of progress via the @ref TSE3::Progress interface. * * @param progress @ref TSE3::Progess callback, or zero for no * callback * @return List of instrument titles in the .ins file */ const std::list &instruments(TSE3::Progress *progress = 0); /** * Factory method that creates an Instrument object for the * given instrument title from this CakewalkInstrumentFile. * * You can supply a @ref TSE3::Progess interface to be informed * of progress. * * @param title The title of the instrument to create * @param progress @ref TSE3::Progess callback, or zero for no * callback * @return New instrument object - you must delete this object */ Instrument *instrument(const std::string &title, TSE3::Progress *progress = 0); private: std::string filename; bool searched_yet; std::list ins; }; } } #endif tse3-0.3.1/src/tse3/ins/Makefile.am0000644000175700001440000000036710271145611013613 00000000000000tse3insh_HEADERS = Destination.h Instrument.h tse3inshdir = $(pkgincludedir)/ins noinst_LTLIBRARIES = libtse3ins.la libtse3ins_la_SOURCES = Destination.cpp Instrument.cpp DISTCLEANFILES = ./.deps/* ./.deps/.P INCLUDES = -I$(top_srcdir)/src tse3-0.3.1/src/tse3/ins/Makefile.in0000644000175700017570000003707510302622112013634 00000000000000# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ SOURCES = $(libtse3ins_la_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/tse3/ins DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(tse3insh_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libtse3ins_la_LIBADD = am_libtse3ins_la_OBJECTS = Destination.lo Instrument.lo libtse3ins_la_OBJECTS = $(am_libtse3ins_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libtse3ins_la_SOURCES) DIST_SOURCES = $(libtse3ins_la_SOURCES) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(tse3inshdir)" tse3inshHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(tse3insh_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPP_MM = @CPP_MM@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ HAVE_ALSA_FALSE = @HAVE_ALSA_FALSE@ HAVE_ALSA_TRUE = @HAVE_ALSA_TRUE@ HAVE_ARTS_FALSE = @HAVE_ARTS_FALSE@ HAVE_ARTS_TRUE = @HAVE_ARTS_TRUE@ HAVE_OSS_FALSE = @HAVE_OSS_FALSE@ HAVE_OSS_TRUE = @HAVE_OSS_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTALL_TSE3_DOC_FALSE = @INSTALL_TSE3_DOC_FALSE@ INSTALL_TSE3_DOC_TRUE = @INSTALL_TSE3_DOC_TRUE@ LDFLAGS = @LDFLAGS@ LIBARTS = @LIBARTS@ LIBASOUND = @LIBASOUND@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TSE3_ALSA_PREFIX = @TSE3_ALSA_PREFIX@ TSE3_ALSA_VERSION = @TSE3_ALSA_VERSION@ TSE3_ARTS_PREFIX = @TSE3_ARTS_PREFIX@ TSE3_WITH_ALSA = @TSE3_WITH_ALSA@ TSE3_WITH_ALSA_0_5_X = @TSE3_WITH_ALSA_0_5_X@ TSE3_WITH_ALSA_0_5_X_FALSE = @TSE3_WITH_ALSA_0_5_X_FALSE@ TSE3_WITH_ALSA_0_5_X_TRUE = @TSE3_WITH_ALSA_0_5_X_TRUE@ TSE3_WITH_ALSA_0_9_X = @TSE3_WITH_ALSA_0_9_X@ TSE3_WITH_ALSA_0_9_X_FALSE = @TSE3_WITH_ALSA_0_9_X_FALSE@ TSE3_WITH_ALSA_0_9_X_TRUE = @TSE3_WITH_ALSA_0_9_X_TRUE@ TSE3_WITH_ALSA_FALSE = @TSE3_WITH_ALSA_FALSE@ TSE3_WITH_ALSA_TRUE = @TSE3_WITH_ALSA_TRUE@ TSE3_WITH_ARTS = @TSE3_WITH_ARTS@ TSE3_WITH_ARTS_FALSE = @TSE3_WITH_ARTS_FALSE@ TSE3_WITH_ARTS_TRUE = @TSE3_WITH_ARTS_TRUE@ TSE3_WITH_OSS = @TSE3_WITH_OSS@ TSE3_WITH_OSS_FALSE = @TSE3_WITH_OSS_FALSE@ TSE3_WITH_OSS_TRUE = @TSE3_WITH_OSS_TRUE@ TSE3_WITH_WIN32 = @TSE3_WITH_WIN32@ TSE3_WITH_WIN32_FALSE = @TSE3_WITH_WIN32_FALSE@ TSE3_WITH_WIN32_TRUE = @TSE3_WITH_WIN32_TRUE@ VERSION = @VERSION@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ prefix = @prefix@ program_transform_name = @program_transform_name@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ tse3insh_HEADERS = Destination.h Instrument.h tse3inshdir = $(pkgincludedir)/ins noinst_LTLIBRARIES = libtse3ins.la libtse3ins_la_SOURCES = Destination.cpp Instrument.cpp DISTCLEANFILES = ./.deps/* ./.deps/.P INCLUDES = -I$(top_srcdir)/src all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tse3/ins/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/tse3/ins/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libtse3ins.la: $(libtse3ins_la_OBJECTS) $(libtse3ins_la_DEPENDENCIES) $(CXXLINK) $(libtse3ins_la_LDFLAGS) $(libtse3ins_la_OBJECTS) $(libtse3ins_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Destination.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Instrument.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: install-tse3inshHEADERS: $(tse3insh_HEADERS) @$(NORMAL_INSTALL) test -z "$(tse3inshdir)" || $(mkdir_p) "$(DESTDIR)$(tse3inshdir)" @list='$(tse3insh_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(tse3inshHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(tse3inshdir)/$$f'"; \ $(tse3inshHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(tse3inshdir)/$$f"; \ done uninstall-tse3inshHEADERS: @$(NORMAL_UNINSTALL) @list='$(tse3insh_HEADERS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(tse3inshdir)/$$f'"; \ rm -f "$(DESTDIR)$(tse3inshdir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(tse3inshdir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-tse3inshHEADERS install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am uninstall-tse3inshHEADERS .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip install-tse3inshHEADERS installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-info-am \ uninstall-tse3inshHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: tse3-0.3.1/src/tse3/ins/Destination.cpp0000644000175700001440000001447210271145611014546 00000000000000/* * @(#)Destination.h 3.00 21 August 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/ins/Destination.h" #include "tse3/ins/Instrument.h" #include "tse3/Midi.h" #include #include #include using namespace TSE3::Ins; /****************************************************************************** * DestinationImpl class *****************************************************************************/ namespace { struct DestinationInfo { DestinationInfo() : allChannels(false) { for (int n = 0; n < 16; ++n) instruments[n] = 0; } bool allChannels; Instrument *instruments[16]; }; } class TSE3::Ins::DestinationImpl { public: Instrument *defaultInstrument; std::vector ilist; typedef std::map dmap_type; dmap_type dmap; }; /****************************************************************************** * Destination class *****************************************************************************/ Destination::Destination() : pimpl(new DestinationImpl) { pimpl->defaultInstrument = 0; } Destination::~Destination() { delete pimpl; } Instrument *Destination::defaultInstrument() const { return pimpl->defaultInstrument; } void Destination::setDefaultInstrument(Instrument *instrument) { pimpl->defaultInstrument = instrument; } bool Destination::allChannels(int port) { DestinationImpl::dmap_type::iterator i = pimpl->dmap.find(port); if (i != pimpl->dmap.end()) { return i->second.allChannels; } else { return true; } } Instrument *Destination::port(int port) { DestinationImpl::dmap_type::iterator i = pimpl->dmap.find(port); if (i != pimpl->dmap.end()) { Instrument *instrument = i->second.allChannels ? i->second.instruments[0] : 0; return instrument ? instrument : pimpl->defaultInstrument; } else { return pimpl->defaultInstrument; } } void Destination::setPort(int port, Instrument *instrument) { if (instrument) { pimpl->dmap[port].allChannels = true; pimpl->dmap[port].instruments[0] = instrument; } else { pimpl->dmap.erase(port); } notify(&DestinationListener::Destination_Altered, TSE3::MidiCommand::AllChannels, port, instrument); } Instrument *Destination::channel(int channel, int port) { DestinationImpl::dmap_type::iterator i = pimpl->dmap.find(port); if (i != pimpl->dmap.end() && channel >= 0 && channel < 16) { if (i->second.allChannels) channel = 0; Instrument *instrument = i->second.instruments[channel]; return instrument ? instrument : pimpl->defaultInstrument; } else { return pimpl->defaultInstrument; } } void Destination::setChannel(int channel, int port, Instrument *instrument) { if (channel < 0 || channel >= 16) return; DestinationImpl::dmap_type::iterator i = pimpl->dmap.find(port); if (i != pimpl->dmap.end()) { if (i->second.allChannels) { for (int n = 1; n < 16; n++) { i->second.instruments[n] = i->second.instruments[0]; if (n != channel) { notify(&DestinationListener::Destination_Altered, n, port, i->second.instruments[0]); } } } } pimpl->dmap[port].allChannels = false; pimpl->dmap[port].instruments[channel] = instrument; notify(&DestinationListener::Destination_Altered, channel, port, instrument); } /****************************************************************************** * Destination class: managing the ilist *****************************************************************************/ size_t Destination::numInstruments() const { return pimpl->ilist.size(); } Instrument *Destination::instrument(size_t index) { if (index < pimpl->ilist.size()) { return pimpl->ilist[index]; } else { return 0; } } Instrument *Destination::instrument(const std::string &title) { std::vector::iterator i = pimpl->ilist.begin(); while (i != pimpl->ilist.end() && (*i)->title() != title) { ++i; } return (i == pimpl->ilist.end()) ? 0 : *i; } void Destination::addInstrument(Instrument *instrument) { std::vector::iterator i = pimpl->ilist.begin(); while (i != pimpl->ilist.end() && (*i)->title() < instrument->title()) { ++i; } if (i == pimpl->ilist.end() || instrument->title() != (*i)->title()) { pimpl->ilist.insert(i, instrument); notify(&DestinationListener::Destination_InstrumentAdded, instrument); }; } void Destination::removeInstrument(Instrument *instrument) { // Check its in the managed list std::vector::iterator i = find(pimpl->ilist.begin(), pimpl->ilist.end(), instrument); if (i == pimpl->ilist.end()) return; // Check every destination DestinationImpl::dmap_type::iterator di = pimpl->dmap.begin(); while (di != pimpl->dmap.end()) { int maxc = (di->second.allChannels) ? 1 : 16; for (int channel = 0; channel < maxc; channel++) { if (di->second.instruments[channel] == instrument) { di->second.instruments[channel] = 0; notify(&DestinationListener::Destination_Altered, channel, di->first, (Instrument*)0); } } ++di; } if (pimpl->defaultInstrument == instrument) { pimpl->defaultInstrument = 0; } pimpl->ilist.erase(i); notify(&DestinationListener::Destination_InstrumentRemoved, instrument); } tse3-0.3.1/src/tse3/ins/Instrument.cpp0000644000175700001440000003713510302613332014431 00000000000000/* * @(#)Instrument.h 3.00 3 August 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/ins/Instrument.h" #include "tse3/Progress.h" #include #include #include #include using namespace TSE3; using namespace TSE3::Ins; namespace { /** * The .ins file comment divider. We use this when we write .ins files. * * This is the standard divider from one of Cakewalk's files. */ const char *ins_divider = "; ----------------------------------" "------------------------------------\n"; /** * .ins files come from Windows/MS-DOS. They have ASCII 13 at the ends of * the lines. We need to strip them out before we handle the line. That's * what this we functon does. * * We also need to strip comments from lines. So we do that here too. */ void clean_string(std::string &str) { if (str[str.length()-1] == 13) // for empty lines? { str = str.substr(0, str.length()-1); } if (str.find(';') != str.npos) { str = str.substr(0,str.find(';')); } } } /****************************************************************************** * Voice class *****************************************************************************/ Voice::Voice(int bank, int patch) { first = bank; second = patch; } Voice::Voice(int bankMSB, int bankLSB, int patch) { first = (bankMSB << 7) + bankLSB; second = patch; } int Voice::operator <(const Voice &v) const { if (first != v.first) { return first < v.first; } else { return second < v.second; } } /****************************************************************************** * Instrument class *****************************************************************************/ Instrument::Instrument(const std::string &title, const std::string &filename, TSE3::Progress *p) : _title(title), _filename(filename), _bankSelMethod(0), _useNotesAsControllers(false), _control(0), _rpn(0), _nrpn(0) { std::ifstream in(filename.c_str()); if (in.good()) { load(in, p); } } void Instrument::setTitle(const std::string &n) { _title = n; } void Instrument::setBankSelMethod(int b) { if (b <= BankSelMethod_Normal || b >= BankSelMethod_Patch) return; _bankSelMethod = b; } void Instrument::setUseNotesAsControllers(bool u) { _useNotesAsControllers = u; } int Instrument::bankLSB(int index) const { return banks[index] == -1 ? -1 : banks[index] & 0xff; } int Instrument::bankMSB(int index) const { return banks[index] == -1 ? -1 : banks[index] >> 7; } int Instrument::bank(const Voice &/*voice*/) const { return -2; // XXX #warning This is not implemented } PatchData *Instrument::patchForBank(int bank) const { std::vector::const_iterator i = std::find(banks.begin(), banks.end(), bank); if (i == banks.end() && bank != -1) { // Ok, so that failed. Perhaps there's a catch-all patch set? i = std::find(banks.begin(), banks.end(), -1); } if (i != banks.end()) { return patches[i-banks.begin()]; } else { return 0; } } PatchData *Instrument::patchForBank(int bankLSB, int bankMSB) const { return patchForBank(bankFromBytes(bankLSB, bankMSB)); } NoteData *Instrument::keyForVoice(const Voice &voice) const { std::vector >::const_iterator i = keys.begin(); while (i != keys.end() && i->first != voice) i++; if (i != keys.end()) { return i->second; } else { return 0; } } bool Instrument::isDrum(const Voice &voice) const { return std::find(drumFlags.begin(), drumFlags.end(), voice) != drumFlags.end(); } /****************************************************************************** * Instrument class saving/loading *****************************************************************************/ void Instrument::load(std::istream &in, TSE3::Progress *progress) { if (progress) { progress->progressRange(0, 100); progress->progress(0); } // 1. Find the ".Instrument Definitions" line (0% - 10%) in.seekg(0, std::ios::beg); std::string line; while (!in.eof() && line != ".Instrument Definitions") { std::getline(in, line); clean_string(line); } if (line != ".Instrument Definitions") return; if (progress) { progress->progress(10); } // 2. Find the instrument definition section (10% - 20%) std::string matchstr = std::string("[") + _title + std::string("]"); while (!in.eof() && line != matchstr) { std::getline(in, line); clean_string(line); } if (progress) { progress->progress(20); } // 3. Parse each of the bits in it (20% - 100%) std::streampos defnFilePos = in.tellg(); std::streampos defnEndPos = defnFilePos; if (progress) { // Find how big this section is for %age while (!in.eof() && line.size() != 0) { std::getline(in, line); clean_string(line); if (line[0] == '[') line =""; } defnEndPos = in.tellg(); in.seekg(defnFilePos, std::ios::beg); } line = " "; while (!in.eof() && line.size() != 0) { if (progress) { progress->progress(20 + ((in.tellg()-defnFilePos) * 80 / (defnEndPos - defnFilePos))); } std::getline(in, line); clean_string(line); if (line[0] != '[') { parseLine(line, in); } else { line = ""; } } if (progress) { progress->progress(100); } } void Instrument::parseLine(const std::string &line, std::istream &in) { if (line == "UseNotesAsControllers=1") { _useNotesAsControllers = true; } else if (line.substr(0,8) == "Control=") { std::string title(line.substr(8)); delete _control; _control = new ControlData(title, in); } else if (line.substr(0,4) == "RPN=") { std::string title(line.substr(4)); delete _rpn; _rpn = new RpnData(title, in); } else if (line.substr(0,5) == "NRPN=") { std::string title(line.substr(5)); delete _nrpn; _nrpn = new NrpnData(title, in); } else if (line.substr(0,14) == "BankSelMethod=") { std::istringstream si(line.c_str()+14); si >> _bankSelMethod; } else if (line.substr(0,6) == "Patch[") { std::string bank_s = line.substr(6, line.find(']')-6); int bank = -1; if (bank_s != "*") { std::istringstream si(line.c_str()+6); si >> bank; } std::string title(line.substr(line.find('=')+1)); banks.push_back(bank); patches.push_back(new PatchData(title, in)); } else if (line.substr(0,4) == "Key[") { std::string bank_s(line.substr(4,line.find(',')-4)); int a = line.find(',')+1; std::string patch_s(line.substr(a, line.find(']')-a)); int bank = -1, patch = -1; if (bank_s != "*") { std::istringstream si(bank_s); si >> bank; } if (patch_s != "*") { std::istringstream si(patch_s); si >> patch; } std::string title(line.substr(line.find('=')+1)); // This has been split onto a separate line to keep gcc happy std::pair pr (Voice(bank,patch), new NoteData(title, in)); keys.push_back(pr); } else if (line.substr(0,5) == "Drum[") { std::string bank_s(line.substr(5,line.find(',')-5)); int a = line.find(',')+1; std::string patch_s(line.substr(a, line.find(']')-a)); int bank = -1, patch = -1; if (bank_s != "*") { std::istringstream si(bank_s); si >> bank; } if (patch_s != "*") { std::istringstream si(patch_s); si >> patch; } std::string title(line.substr(line.find('=')+1)); drumFlags.push_back(Voice(bank,patch)); } } void Instrument::write(std::ostream &out) { out << "\n" << ins_divider << "; Instrument definition file save by TSE3 library\n" << "; Defines the " << _title << " instrument only\n" << "; Pete Goodliffe\n\n"; out << ins_divider << "\n.Patch Names\n\n"; { std::vector::iterator ip = patches.begin(); while (ip != patches.end()) { (*ip)->write(out); ++ip; } } out << ins_divider << "\n.Note Names\n\n"; { std::vector >::iterator i = keys.begin(); while (i != keys.end()) { (*i).second->write(out); ++i; } } out << ins_divider << "\n.Controller Names\n\n"; if (_control) _control->write(out); out << ins_divider << "\n.RPN Names\n\n"; // hmm? out << ins_divider << "\n.NRPN Names\n\n"; if (_nrpn) _nrpn->write(out); out << ins_divider << "\n.Instrument Definitions\n\n"; out << "[" << _title << "]\n"; if (_useNotesAsControllers) out << "UseNotesAsControllers=1\n"; if (_control) out << "Control=" << _control->title() << "\n"; if (_nrpn) out << "NRPN=" << _nrpn->title() << "\n"; if (_bankSelMethod) out << "BankSelMethod=" << _bankSelMethod << "\n"; { std::vector::iterator ip = patches.begin(); std::vector::iterator ib = banks.begin(); while (ip != patches.end()) { out << "Patch["; if (*ib == -1) out << "*"; else out << *ib; out << "]=" << (*ip)->title() << "\n"; ++ip; ++ib; } } { std::vector >::iterator i = keys.begin(); while (i != keys.end()) { out << "Key["; if ((*i).first.bank() == -1) out << "*"; else out << (*i).first.bank(); out << ","; if ((*i).first.patch() == -1) out << "*"; else out << (*i).first.patch(); out << "]=" << (*i).second->title() << "\n"; ++i; } } { std::vector::iterator i = drumFlags.begin(); while (i != drumFlags.end()) { out << "Drum["; if ((*i).bank() == -1) out << "*"; else out << (*i).bank(); out << ","; if ((*i).patch() == -1) out << "*"; else out << (*i).patch(); out << "]=1\n"; ++i; } } out << "\n"; } /****************************************************************************** * InstrumentData class *****************************************************************************/ std::string InstrumentData::empty; InstrumentData::InstrumentData(std::string const &title, std::string const &insHeading, std::istream &in) : insHeading(insHeading), _title(title) { for (int n = 0; n < 128; ++n) _names[n] = 0; load(_title, in); } void InstrumentData::load(const std::string &secname, std::istream &in) { //out << "Loading ["< &CakewalkInstrumentFile::instruments (TSE3::Progress *progress) { if (!searched_yet) { size_t progressCount = 0; searched_yet = true; std::ifstream in(filename.c_str()); if (!in.good()) { return ins; } if (progress) { in.seekg(0, std::ios::end); progress->progressRange(0, in.tellg()); in.seekg(0, std::ios::beg); } std::string line; while (!in.eof() && line != ".Instrument Definitions") { std::getline(in, line); clean_string(line); if (progress && !(progressCount%20)) { progress->progress(in.tellg()); } progressCount++; } if (line != ".Instrument Definitions") return ins; while (!in.eof()) { std::getline(in, line); clean_string(line); if (line.size() && line[0] == '[') { ins.push_back(line.substr(1,line.size()-2)); } if (progress && !(progressCount%20)) { progress->progress(in.tellg()); } progressCount++; } } return ins; } Instrument *CakewalkInstrumentFile::instrument(const std::string &title, TSE3::Progress *p) { return new Instrument(title, filename, p); } tse3-0.3.1/src/tse3/plt/0000777000175700017570000000000010310240001011635 500000000000000tse3-0.3.1/src/tse3/plt/Alsa.h0000644000175700001440000001063010271145620012610 00000000000000/* * @(#)plt/Alsa.h 3.00 12 October 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_PLT_ALSA_H #define TSE3_PLT_ALSA_H #include "tse3/MidiScheduler.h" namespace TSE3 { namespace Plt { /** * This is the Alsa @ref MidiScheduler implementation. * * @short Alsa MidiScheduler implementation * @author Pete Goodliffe * @version 0.00 * @see MidiScheduler * @see AlsaMidiSchedulerFactory */ class AlsaMidiScheduler : public MidiScheduler { public: /** * @throws TSE3::MidiSchedulerError */ AlsaMidiScheduler(); virtual ~AlsaMidiScheduler(); protected: /** * @reimplemented */ virtual const char *impl_implementationName() const; /** * @reimplemented */ virtual const char *impl_portName(int port) const; /** * @reimplemented */ virtual const char *impl_portType(int port) const; /** * @reimplemented */ virtual bool impl_portReadable(int port) const; /** * @reimplemented */ virtual bool impl_portWriteable(int port) const; /** * @reimplemented */ virtual void impl_start(Clock clock); /** * @reimplemented */ virtual void impl_stop(Clock clock); /** * @reimplemented */ virtual void impl_moveTo(Clock moveTime, Clock newTime); /** * @reimplemented */ virtual Clock impl_clock(); /** * @reimplemented */ virtual int impl_msecs(); /** * @reimplemented */ virtual void impl_setTempo(int tempo, Clock changeTime); /** * @reimplemented */ virtual bool impl_eventWaiting(); /** * @reimplemented */ virtual MidiEvent impl_rx(); /** * @reimplemented */ virtual void impl_tx(MidiCommand mc); /** * @reimplemented */ virtual void impl_tx(MidiEvent mc); /** * @reimplemented */ virtual void impl_txSysEx(int port, const unsigned char *data, size_t size); private: AlsaMidiScheduler(const AlsaMidiScheduler &); AlsaMidiScheduler &operator=(const AlsaMidiScheduler &); // Private Alsa interface functions /** * Reads the current client/port setup of the machine and puts * this information into the internal "dest" vector. */ void getSystemInfo(); /** * Sends the MidiCommand. If queue SND_SEQ_QUEUE_DIRECT is * specified, it is sent immediately, bypassing the queue. * * In this version of the driver we only support timing in * msecs. Later on we'll hook into Alsa's ticks and then be * able to sync to external timing sources. */ void alsa_tx(MidiCommand mc, int queue, long int sec = 0, long int nsec = 0); class AlsaImpl *pimpl; }; } } #endif tse3-0.3.1/src/tse3/plt/Arts.h0000644000175700001440000000721110271145620012642 00000000000000/* * @(#)plt/Arts.h 3.00 12 October 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_PLT_ARTS_H #define TSE3_PLT_ARTS_H #include "tse3/MidiScheduler.h" namespace TSE3 { namespace Plt { /** * This is the Arts @ref MidiScheduler implementation. * * @short Arts MidiScheduler implementation * @author Pete Goodliffe * @version 0.00 * @see MidiScheduler * @see ArtsMidiSchedulerFactory */ class ArtsMidiScheduler : public MidiScheduler { public: /** * @throws TSE3::MidiSchedulerError */ ArtsMidiScheduler(); virtual ~ArtsMidiScheduler(); protected: /** * @reimplemented */ virtual const char *impl_implementationName() const; /** * @reimplemented */ virtual const char *impl_portName(int port) const; /** * @reimplemented */ virtual const char *impl_portType(int port) const; /** * @reimplemented */ virtual bool impl_portReadable(int port) const; /** * @reimplemented */ virtual bool impl_portWriteable(int port) const; /** * @reimplemented */ virtual void impl_start(Clock clock); /** * @reimplemented */ virtual void impl_stop(Clock clock); /** * @reimplemented */ virtual void impl_moveTo(Clock moveTime, Clock newTime); /** * @reimplemented */ virtual Clock impl_clock(); /** * @reimplemented */ virtual int impl_msecs(); /** * @reimplemented */ virtual void impl_setTempo(int tempo, Clock changeTime); /** * @reimplemented */ virtual bool impl_eventWaiting(); /** * @reimplemented */ virtual MidiEvent impl_rx(); /** * @reimplemented */ virtual void impl_tx(MidiCommand mc); /** * @reimplemented */ virtual void impl_tx(MidiEvent mc); /** * @reimplemented */ virtual void impl_txSysEx(int port, const unsigned char *data, size_t size); private: ArtsMidiScheduler(const ArtsMidiScheduler &); ArtsMidiScheduler &operator=(const ArtsMidiScheduler &); size_t noports; class ArtsImpl *pimpl; }; } } #endif tse3-0.3.1/src/tse3/plt/Factory_Unix.cpp0000644000175700001440000001016210271145620014675 00000000000000/* * @(#)Factory_Unix.cpp 3.00 4 February 2002 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/plt/Factory.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef TSE3_WITH_OSS #include "tse3/plt/OSS.h" #endif #ifdef TSE3_WITH_ALSA #include "tse3/plt/Alsa.h" #endif #ifdef TSE3_WITH_ARTS #include "tse3/plt/Arts.h" #endif #include "tse3/util/MidiScheduler.h" #include "tse3/Error.h" using namespace TSE3::Plt; namespace { TSE3::Plt::UnixMidiSchedulerFactory::UnixPlatform plt = TSE3::Plt::UnixMidiSchedulerFactory::UnixPlatform_Alsa; TSE3::Plt::UnixMidiSchedulerFactory::UnixPlatform cplt = TSE3::Plt::UnixMidiSchedulerFactory::UnixPlatform_Null; /** * Try to create an @ref OSSMidiScheduler. Catch any * exceptions thrown, and return zero if didn't create. */ TSE3::MidiScheduler *createOSS(); /** * Try to create an @ref AlsaMidiScheduler. Catch any * exceptions thrown, and return zero if didn't create. */ TSE3::MidiScheduler *createAlsa(); /** * Try to create an @ref ArtsMidiScheduler. Catch any * exceptions thrown, and return zero if didn't create. */ TSE3::MidiScheduler *createArts(); } namespace TSE3 { namespace Plt { namespace UnixMidiSchedulerFactory { UnixPlatform preferredPlatform() { return plt; } void setPreferredPlatform(UnixPlatform p) { plt = p; } UnixPlatform createdPlatform() { return cplt; } } } } TSE3::MidiSchedulerFactory::MidiSchedulerFactory(bool c) : _canReturnNull(c) { } TSE3::MidiSchedulerFactory::~MidiSchedulerFactory() { } TSE3::MidiScheduler *TSE3::MidiSchedulerFactory::createScheduler() { TSE3::MidiScheduler *ms = 0; switch (plt) { case TSE3::Plt::UnixMidiSchedulerFactory::UnixPlatform_OSS: { ms = createOSS(); if (!ms) { ms = createAlsa(); } break; } case TSE3::Plt::UnixMidiSchedulerFactory::UnixPlatform_Alsa: { ms = createAlsa(); if (!ms) { ms = createOSS(); } break; } case TSE3::Plt::UnixMidiSchedulerFactory::UnixPlatform_Arts: { ms = createArts(); if (!ms) { ms = createAlsa(); } if (!ms) { ms = createOSS(); } break; } default: { break; } } if (!ms) { if (_canReturnNull) { ms = new TSE3::Util::NullMidiScheduler(); } else { throw MidiSchedulerError(MidiSchedulerCreateErr); } } return ms; } namespace { TSE3::MidiScheduler *createOSS() { TSE3::MidiScheduler *ms = 0; #ifdef TSE3_WITH_OSS try { // Create the scheduler ms = new OSSMidiScheduler(); cplt = TSE3::Plt::UnixMidiSchedulerFactory::UnixPlatform_OSS; } catch (TSE3::Error) { } #endif return ms; } TSE3::MidiScheduler *createAlsa() { TSE3::MidiScheduler *ms = 0; #ifdef TSE3_WITH_ALSA try { // Create the scheduler ms = new AlsaMidiScheduler(); cplt = TSE3::Plt::UnixMidiSchedulerFactory::UnixPlatform_Alsa; } catch (TSE3::Error) { } #endif return ms; } TSE3::MidiScheduler *createArts() { TSE3::MidiScheduler *ms = 0; #ifdef TSE3_WITH_ARTS try { // Create the scheduler ms = new ArtsMidiScheduler(); cplt = TSE3::Plt::UnixMidiSchedulerFactory::UnixPlatform_Arts; } catch (TSE3::Error) { } #endif return ms; } } tse3-0.3.1/src/tse3/plt/OSS.h0000644000175700001440000002242310271145620012377 00000000000000/* * @(#)plt/OSS.h 3.00 20 July 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_PLT_OSS_H #define TSE3_PLT_OSS_H #include "tse3/MidiScheduler.h" #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef TSE3_WITH_OSS #include #else struct synth_info; struct midi_info; #endif namespace TSE3 { namespace Plt { class OSSMidiScheduler_SynthDevice; /** * This is the Open Sound System @ref MidiScheduler implementation. * It requires OSS version 3.60. * * Since it opens /dev/sequencer (the OSS sequencer interface) there * can only ever be one of these objects instantiated at any given time. * Subsequent instanitations will throw an exception. * * Before you create an object of this type you may want to call the * following static member functions to set the location of patches * files: * * @li @ref OSSMidiScheduler_FMDevice::setPatchesDirectory * @li @ref OSSMidiScheduler_GUSDevice::setPatchesDirectory * * @short OSS MidiScheduler implemtation * @author Pete Goodliffe * @version 0.00 * @see MidiScheduler * @see OSSMidiSchedulerFactory */ class OSSMidiScheduler : public MidiScheduler { public: /** * @throws TSE3::MidiSchedulerError */ OSSMidiScheduler(); virtual ~OSSMidiScheduler(); /************************************************************** * OSS specific settings *************************************************************/ /** * This returns in which directory the device will look for * FM patch files. This must be set before the device is * created. * * The patches directory path can contain multiple paths, * separated by colons. * * @see setFmPatchesDirectory */ static std::string &fmPatchesDirectory(); /** * Call this before creating the @ref OSSMidiScheduler object * to set up where to look for FM patches files. * * @see fmPatchesDirectory */ static void setFmPatchesDirectory(const std::string &dir); /** * This returns in which directory the device will look for * GUD patch files. This must be set before the device is * created. (In fact, it must be set before each GUS voice is * loaded - they are loaded on demand. However, it is safest to * set this before creating the device.) * * The patches directory path can contain multiple paths, * separated by colons. * * @see setGusPatchesDirectory */ static std::string &gusPatchesDirectory(); /** * Call this before creating the @ref OSSMidiScheduler object * to set up where to look for GUS patches files. * * @see gusPatchesDirectory */ static void setGusPatchesDirectory(const std::string &dir); protected: /** * @reimplemented */ virtual const char *impl_implementationName() const; /** * @reimplemented */ virtual const char *impl_portName(int port) const; /** * @reimplemented */ virtual const char *impl_portType(int port) const; /** * @reimplemented */ virtual bool impl_portReadable(int port) const; /** * @reimplemented */ virtual bool impl_portWriteable(int port) const; /** * @reimplemented */ virtual void impl_start(Clock clock); /** * @reimplemented */ virtual void impl_stop(Clock clock); /** * @reimplemented */ virtual void impl_moveTo(Clock moveTime, Clock newTime); /** * @reimplemented */ virtual Clock impl_clock(); /** * @reimplemented */ virtual int impl_msecs(); /** * @reimplemented */ virtual void impl_setTempo(int tempo, Clock changeTime); /** * @reimplemented */ virtual bool impl_eventWaiting(); /** * @reimplemented */ virtual MidiEvent impl_rx(); /** * @reimplemented */ virtual void impl_tx(MidiCommand mc); /** * @reimplemented */ virtual void impl_tx(MidiEvent mc); /** * @reimplemented */ virtual void impl_txSysEx(int port, const unsigned char *data, size_t size); private: OSSMidiScheduler(const OSSMidiScheduler &); OSSMidiScheduler &operator=(const OSSMidiScheduler &); /** * Does the tx. If outOfBand is false, sends data to the * end of the playback queue. If outOfBand is true, it * sends data immediately. */ void tx(const MidiCommand mc, bool outOfBand); unsigned char *running; // running status values bool *useRunning; // does device support running sts? unsigned int nosynths; // no of internal synth devices unsigned int nomidis; // no of MIDI ports unsigned int nodevices; // nosynths + nomidis int rate; // sequencer timer rate (in ms) int rateDivisor; // value to / timer by to get ms synth_info *synthinfo; // synth_info for each synth device midi_info *midiinfo; // midi_info for each MIDI device // In C we write SEQ_DEFINEBUF(1024); to set up some OSS magic // which creates a buffer that the OSS macros write data into. // However, this won't work in a class declaration. Sigh. // So this is how we do it. int seqfd; // file descfor /dev/sequencer unsigned char *_seqbuf; // buffer for /dev/sequencer data int _seqbuflen; // size of _seqbuf int _seqbufptr; // pointer to end of pending data void seqbuf_dump(); // wrts _seqbuf to /dev/sequencer void seqbuf_clean(); // flushes the buffer // For a given port (TSE3 speak, same as OSS device number) is // it a synth or MIDI device? bool isSynth(unsigned int port) const { return port < nosynths; } bool isMidi(unsigned int port) const { return port >= nosynths; } // MIDI devices are easy to send data too, but the synths need // some special massaging. The classes held in this table do // just that. OSSMidiScheduler_SynthDevice **devices; // Output malarky Clock lastTxTime; // Time last MidiCommand was scheduled // Input malarky bool input; // true if there is an input command MidiCommand command; // if input is true, this holds the input Clock time; // time of the input MidiCommand /** * Performs input scan of the /dev/sequencer device and * interprets what it reads. If there is any input, then * the input variable is set to true. When you've read the * input, then set it to false. */ void readInput(); }; } } #endif tse3-0.3.1/src/tse3/plt/midiswis.h0000644000175700001440000000453710271145620013571 00000000000000/* * @(#)plt/midiswi.h 3.00 28 June 1995 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ /* * These are SWI defintions used by the RISC OS MidiScheduler implementation. */ #ifndef __midiswis_h #define __midiswis_h #define MIDI_Sound_Enable 0x404c0 #define MIDI_SetMode 0x404c1 #define MIDI_SetTxChannel 0x404c2 #define MIDI_SetTxActiveSensing 0x404c3 #define MIDI_InqSongPositionPointer 0x404c4 #define MIDI_InqBufferSize 0x404c5 #define MIDI_InqError 0x404c6 #define MIDI_RxByte 0x404c7 #define MIDI_RxCommand 0x404c8 #define MIDI_TxByte 0x404c9 #define MIDI_TxCommand 0x404ca #define MIDI_TxNoteOff 0x404cb #define MIDI_TxNoteOn 0x404cc #define MIDI_TxPolyKeyPressure 0x404cd #define MIDI_TxControlChange 0x404ce #define MIDI_TxLocalControl 0x404cf #define MIDI_TxAllNotesOff 0x404d0 #define MIDI_TxOmniOff 0x404d1 #define MIDI_TxOmniModeOn 0x404d2 #define MIDI_TxMonoModeOn 0x404d3 #define MIDI_TxPolyModeOn 0x404d4 #define MIDI_TxProgramChange 0x404d5 #define MIDI_TxChannelPressure 0x404d6 #define MIDI_TxPitchWheel 0x404d7 #define MIDI_TxSongPositionPointer 0x404d8 #define MIDI_TxSongSelect 0x404d9 #define MIDI_TxTuneRequest 0x404da #define MIDI_TxStart 0x404db #define MIDI_TxContinue 0x404dc #define MIDI_TxStop 0x404dd #define MIDI_TxSystemReset 0x404de #define MIDI_IgnoreTiming 0x404df #define MIDI_SynchSoundScheduler 0x404e0 #define MIDI_FastClock 0x404e1 #define MIDI_Init 0x404e2 #define MIDI_SetBufferSize 0x404e3 #define MIDI_Interface 0x404e4 #endif tse3-0.3.1/src/tse3/plt/README0000644000175700001440000000032010271145620012432 00000000000000TSE3 RISC OS version -------------------- This hasn't been finished off yet and as such should not be compiled. It would be a shame not to do this since TSE originally came from that platform. We'll see... tse3-0.3.1/src/tse3/plt/Win32.h0000644000175700001440000000754510271145620012645 00000000000000/* * @(#)plt/Win32.h 1.00 30 November 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_PLT_WIN32_H #define TSE3_PLT_WIN32_H #include "tse3/MidiScheduler.h" #include namespace TSE3 { namespace Plt { /** * This is the Win32 (Windows) @ref MidiScheduler implementation. * * @short Win32 MidiScheduler implemtation * @author Jose Maria Sanchez Saez * @author Pete Goodliffe * @version 0.00 * @see MidiScheduler * @see Win32MidiSchedulerFactory */ class Win32MidiScheduler : public MidiScheduler { public: /** * Creates the Win32MidiScheduler object. */ Win32MidiScheduler(); // throw (Win32MidiSchedulerException); virtual ~Win32MidiScheduler(); protected: /** * @reimplemented */ virtual const char *impl_implementationName() const; /** * @reimplemented */ virtual const char *impl_portName(int port) const; /** * @reimplemented */ virtual const char *impl_portType(int port) const; /** * @reimplemented */ virtual bool impl_portReadable(int port) const; /** * @reimplemented */ virtual bool impl_portWriteable(int port) const; /** * @reimplemented */ virtual void impl_start(Clock clock); /** * @reimplemented */ virtual void impl_stop(Clock clock); /** * @reimplemented */ virtual void impl_moveTo(Clock moveTime, Clock newTime); /** * @reimplemented */ virtual Clock impl_clock(); /** * @reimplemented */ virtual int impl_msecs(); /** * @reimplemented */ virtual void impl_setTempo(int tempo, Clock changeTime); /** * @reimplemented */ virtual bool impl_eventWaiting(); /** * @reimplemented */ virtual MidiEvent impl_rx(); /** * @reimplemented */ virtual void impl_tx(MidiCommand mc); /** * @reimplemented */ virtual void impl_tx(MidiEvent mc); /** * @reimplemented */ virtual void impl_txSysEx(int port, const unsigned char *data, size_t size); private: union HMIDI { HMIDIOUT out; HMIDIIN in; }; HMIDI *hMidi; UINT nMidi; void runMidiData(HMIDIOUT, MidiCommand); static void callback(UINT, UINT, DWORD, DWORD, DWORD); }; } } #endif tse3-0.3.1/src/tse3/plt/Factory_Win32.cpp0000644000175700001440000000216010271145620014653 00000000000000/* * @(#)Factry_Win32.cpp 3.00 5 February 2002 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/plt/Factory.h" #ifdef CONFIG_H #include "config.h" #endif #include "tse3/plt/Win32.h" #include "tse3/util/MidiScheduler.h" #include "tse3/Error.h" using namespace TSE3::Plt; TSE3::MidiSchedulerFactory::MidiSchedulerFactory(bool c) : _canReturnNull(c) { } TSE3::MidiSchedulerFactory::~MidiSchedulerFactory() { } TSE3::MidiScheduler *TSE3::MidiSchedulerFactory::createScheduler() { try { Win32MidiScheduler *ms = new Win32MidiScheduler(); return ms; } catch (...) { cout << "Failed to create a Win32MidiScheduler\n"; throw; } } tse3-0.3.1/src/tse3/plt/RiscOS.h0000644000175700001440000000703110271145620013073 00000000000000/* * @(#)plt/RiscOS.h 3.00 20 July 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_PLT_RISCOS_H #define TSE3_PLT_RISCOS_H #include "tse3/MidiScheduler.h" namespace TSE3 { namespace Plt { /** * This is the RISC OS standard MIDI @ref MidiScheduler implementation. * * @short RISC OS MidiScheduler implementation * @author Pete Goodliffe * @version 3.00 * @see MidiScheduler * @see MidiSchedulerFactory */ class RiscOsMidiScheduler : public MidiScheduler { public: RiscOsMidiScheduler(); virtual ~RiscOsMidiScheduler(); protected: /** * @reimplemented */ virtual const char *impl_implementationName() const; /** * @reimplemented */ virtual const char *impl_portName(int port) const; /** * @reimplemented */ virtual const char *impl_portType(int port) const; /** * @reimplemented */ virtual bool impl_portReadable(int port) const; /** * @reimplemented */ virtual bool impl_portWriteable(int port) const; /** * @reimplemented */ virtual void impl_start(Clock clock); /** * @reimplemented */ virtual void impl_stop(Clock clock); /** * @reimplemented */ virtual void impl_moveTo(Clock moveTime, Clock newTime); /** * @reimplemented */ virtual Clock impl_clock(); /** * @reimplemented */ virtual int impl_msecs(); /** * @reimplemented */ virtual void impl_setTempo(int tempo, Clock changeTime); /** * @reimplemented */ virtual bool impl_eventWaiting(); /** * @reimplemented */ virtual MidiEvent impl_rx(); /** * @reimplemented */ virtual void impl_tx(MidiCommand mc); /** * @reimplemented */ virtual void impl_tx(MidiEvent mc); /** * @reimplemented */ virtual void impl_txSysEx(int port, const unsigned char *data, size_t size); private: RiscOSMidiScheduler(const RiscOSMidiScheduler &); RiscOSMidiScheduler &operator=(const RiscOSMidiScheduler &); int maxPort; }; } } #endif tse3-0.3.1/src/tse3/plt/Arts.cpp0000644000175700001440000001065210302616224013176 00000000000000/* * @(#)Arts.cpp 3.00 12 October 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/plt/Arts.h" #include "tse3/Error.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif // The prefix for this include is now worked out by configure script #include #include #include #include using namespace TSE3; using namespace TSE3::Plt; namespace { /** * this is a singleton shared by all aRts midi schedulers (if there might * be many?) to prevent the MCOP protocol from being initialized more than * once */ class ArtsCommon { public: Arts::Dispatcher dispatcher; Arts::MidiManager manager; Arts::MidiClient client; Arts::MidiPort port; int offsetSec; bool alive; ArtsCommon() { alive = false; manager = Arts::Reference("global:Arts_MidiManager"); if (manager.isNull()) { std::cerr << "TSE3: Arts MidiManager isNull\n"; throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } std::string title = "TSE3"; client = manager.addClient(Arts::mcdPlay, Arts::mctApplication, title,"tse3"); port = client.addOutputPort(); offsetSec = port.time().sec; alive = true; } }; ArtsCommon *artsCommon = 0; int artsCommonInit = 0; } ArtsMidiScheduler::ArtsMidiScheduler() { if(!artsCommonInit) { assert(!artsCommon); artsCommon = new ArtsCommon(); } artsCommonInit++; addPort(1, true); // XXX is internal? } ArtsMidiScheduler::~ArtsMidiScheduler() { artsCommonInit--; if(!artsCommonInit) { delete artsCommon; artsCommon = 0; } } const char *ArtsMidiScheduler::impl_implementationName() const { return "ArtsMidiScheduler version 1.00"; } const char *ArtsMidiScheduler::impl_portName(int /*port*/) const { return "Single aRts MIDI output port"; } const char *ArtsMidiScheduler::impl_portType(int /*port*/) const { return "aRts MIDI port"; } bool ArtsMidiScheduler::impl_portReadable(int /*port*/) const { return false; } bool ArtsMidiScheduler::impl_portWriteable(int /*port*/) const { return true; } void ArtsMidiScheduler::impl_tx(MidiCommand mc) { if(!artsCommon->alive) return; Arts::MidiCommand command(mc.status << 4 | mc.channel, mc.data1, mc.data2); artsCommon->port.processCommand(command); } void ArtsMidiScheduler::impl_start(Clock startTime) { clockStarted(startTime); } void ArtsMidiScheduler::impl_stop(Clock stopTime) { clockStopped(stopTime); } void ArtsMidiScheduler::impl_moveTo(Clock moveTime, Clock newTime) { clockMoved(moveTime, newTime); } Clock ArtsMidiScheduler::impl_clock() { return msToClock(impl_msecs()); } int ArtsMidiScheduler::impl_msecs() { Arts::TimeStamp time = artsCommon->port.time(); time.sec -= artsCommon->offsetSec; /* to reduce the risk of overflows */ return time.sec*1000 + time.usec/1000; } void ArtsMidiScheduler::impl_setTempo(int newTempo, Clock changeTime) { tempoChanged(newTempo, changeTime); } bool ArtsMidiScheduler::impl_eventWaiting() { return false; } MidiEvent ArtsMidiScheduler::impl_rx() { return MidiEvent(); } void ArtsMidiScheduler::impl_txSysEx(int /*port*/, const unsigned char * /*data*/, size_t /*size*/) { } void ArtsMidiScheduler::impl_tx(MidiEvent e) { if(!artsCommon->alive) return; Arts::TimeStamp time(clockToMs(e.time)/1000, (clockToMs(e.time)%1000)*1000); MidiCommand& mc = e.data; Arts::MidiCommand command(mc.status << 4 | mc.channel, mc.data1, mc.data2); artsCommon->port.processEvent(Arts::MidiEvent(time,command)); } tse3-0.3.1/src/tse3/plt/Makefile.am0000644000175700001440000000414310271145620013615 00000000000000tse3plth_HEADERS = Alsa.h OSS.h RiscOS.h Factory.h Win32.h Arts.h tse3plth_HEADERS += RiscOS.cpp Win32.cpp tse3plthdir = $(pkgincludedir)/plt noinst_LTLIBRARIES = libtse3plt.la libtse3plt_la_SOURCES = OSS.cpp EXTRA_DIST = Arts.cpp Win32.cpp RiscOS.cpp Factory_Unix.cpp Factory_Win32.cpp Alsa-0.5.cpp Alsa-0.9.cpp midiswis.h DISTCLEANFILES = ./.deps/* ./.deps/.P INCLUDES = -I$(top_srcdir)/src ############################################################################### # Conditional on what interface support is being built in... # Factory if TSE3_WITH_WIN32 libtse3plt_la_SOURCES_factory = Factory_Win32.cpp else libtse3plt_la_SOURCES_factory = Factory_Unix.cpp endif libtse3plt_la_SOURCES += $(libtse3plt_la_SOURCES_factory) # Alsa if TSE3_WITH_ALSA if TSE3_WITH_ALSA_0_5_X libtse3plt_la_SOURCES_alsa = Alsa-0.5.cpp else libtse3plt_la_SOURCES_alsa = Alsa-0.9.cpp endif libtse3plt_la_LIBADD_alsa = $(LIBASOUND) else libtse3plt_la_SOURCES_alsa = libtse3plt_la_LIBADD_alsa = endif # Arts if TSE3_WITH_ARTS tse3plth_HEADERS_arts = Arts.h libtse3plt_la_SOURCES_arts = Arts.cpp libtse3plt_la_LIBADD_arts = $(LIBARTS) -lartsmidi INCLUDES_arts = -I$(TSE3_ARTS_PREFIX) else tse3plth_HEADERS_arts = libtse3plt_la_SOURCES_arts = libtse3plt_la_LIBADD_arts = INCLUDES_arts = endif tse3plth_HEADERS += $(tse3plth_HEADERS_arts) libtse3plt_la_SOURCES += $(libtse3plt_la_SOURCES_alsa) $(libtse3plt_la_SOURCES_arts) libtse3plt_la_LIBADD = $(libtse3plt_la_LIBADD_alsa) $(libtse3plt_la_LIBADD_arts) INCLUDES += $(INCLUDES_arts) # Win32 (obviously, under cygwin or mingw32) if TSE3_WITH_WIN32 tse3plth_HEADERS_win32 = Win32.h libtse3plt_la_SOURCES_win32 = Win32.cpp libtse3plt_la_LIBADD_win32 = INCLUDES_wind32 = else tse3plth_HEADERS_win32 = libtse3plt_la_SOURCES_win32 = libtse3plt_la_LIBADD_win32 = INCLUDES_win32 = endif tse3plth_HEADERS += $(tse3plth_HEADERS_win32) libtse3plt_la_SOURCES += $(libtse3plt_la_SOURCES_win32) libtse3plt_la_LIBADD += $(libtse3plt_la_LIBADD_win32) INCLUDES += $(INCLUDES_win32) tse3-0.3.1/src/tse3/plt/Makefile.in0000644000175700017570000004552210302622113013637 00000000000000# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ SOURCES = $(libtse3plt_la_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/tse3/plt DIST_COMMON = README $(am__tse3plth_HEADERS_DIST) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = @TSE3_WITH_ALSA_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) @TSE3_WITH_ARTS_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) libtse3plt_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \ $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1) am__libtse3plt_la_SOURCES_DIST = OSS.cpp Factory_Unix.cpp \ Factory_Win32.cpp Alsa-0.9.cpp Alsa-0.5.cpp Arts.cpp Win32.cpp @TSE3_WITH_WIN32_FALSE@am__objects_1 = Factory_Unix.lo @TSE3_WITH_WIN32_TRUE@am__objects_1 = Factory_Win32.lo @TSE3_WITH_ALSA_0_5_X_FALSE@@TSE3_WITH_ALSA_TRUE@am__objects_2 = \ @TSE3_WITH_ALSA_0_5_X_FALSE@@TSE3_WITH_ALSA_TRUE@ Alsa-0.9.lo @TSE3_WITH_ALSA_0_5_X_TRUE@@TSE3_WITH_ALSA_TRUE@am__objects_2 = \ @TSE3_WITH_ALSA_0_5_X_TRUE@@TSE3_WITH_ALSA_TRUE@ Alsa-0.5.lo @TSE3_WITH_ARTS_TRUE@am__objects_3 = Arts.lo @TSE3_WITH_WIN32_TRUE@am__objects_4 = Win32.lo am_libtse3plt_la_OBJECTS = OSS.lo $(am__objects_1) $(am__objects_2) \ $(am__objects_3) $(am__objects_4) libtse3plt_la_OBJECTS = $(am_libtse3plt_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libtse3plt_la_SOURCES) DIST_SOURCES = $(am__libtse3plt_la_SOURCES_DIST) am__tse3plth_HEADERS_DIST = Alsa.h OSS.h RiscOS.h Factory.h Win32.h \ Arts.h RiscOS.cpp Win32.cpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(tse3plthdir)" tse3plthHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(tse3plth_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPP_MM = @CPP_MM@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ HAVE_ALSA_FALSE = @HAVE_ALSA_FALSE@ HAVE_ALSA_TRUE = @HAVE_ALSA_TRUE@ HAVE_ARTS_FALSE = @HAVE_ARTS_FALSE@ HAVE_ARTS_TRUE = @HAVE_ARTS_TRUE@ HAVE_OSS_FALSE = @HAVE_OSS_FALSE@ HAVE_OSS_TRUE = @HAVE_OSS_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTALL_TSE3_DOC_FALSE = @INSTALL_TSE3_DOC_FALSE@ INSTALL_TSE3_DOC_TRUE = @INSTALL_TSE3_DOC_TRUE@ LDFLAGS = @LDFLAGS@ LIBARTS = @LIBARTS@ LIBASOUND = @LIBASOUND@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TSE3_ALSA_PREFIX = @TSE3_ALSA_PREFIX@ TSE3_ALSA_VERSION = @TSE3_ALSA_VERSION@ TSE3_ARTS_PREFIX = @TSE3_ARTS_PREFIX@ TSE3_WITH_ALSA = @TSE3_WITH_ALSA@ TSE3_WITH_ALSA_0_5_X = @TSE3_WITH_ALSA_0_5_X@ TSE3_WITH_ALSA_0_5_X_FALSE = @TSE3_WITH_ALSA_0_5_X_FALSE@ TSE3_WITH_ALSA_0_5_X_TRUE = @TSE3_WITH_ALSA_0_5_X_TRUE@ TSE3_WITH_ALSA_0_9_X = @TSE3_WITH_ALSA_0_9_X@ TSE3_WITH_ALSA_0_9_X_FALSE = @TSE3_WITH_ALSA_0_9_X_FALSE@ TSE3_WITH_ALSA_0_9_X_TRUE = @TSE3_WITH_ALSA_0_9_X_TRUE@ TSE3_WITH_ALSA_FALSE = @TSE3_WITH_ALSA_FALSE@ TSE3_WITH_ALSA_TRUE = @TSE3_WITH_ALSA_TRUE@ TSE3_WITH_ARTS = @TSE3_WITH_ARTS@ TSE3_WITH_ARTS_FALSE = @TSE3_WITH_ARTS_FALSE@ TSE3_WITH_ARTS_TRUE = @TSE3_WITH_ARTS_TRUE@ TSE3_WITH_OSS = @TSE3_WITH_OSS@ TSE3_WITH_OSS_FALSE = @TSE3_WITH_OSS_FALSE@ TSE3_WITH_OSS_TRUE = @TSE3_WITH_OSS_TRUE@ TSE3_WITH_WIN32 = @TSE3_WITH_WIN32@ TSE3_WITH_WIN32_FALSE = @TSE3_WITH_WIN32_FALSE@ TSE3_WITH_WIN32_TRUE = @TSE3_WITH_WIN32_TRUE@ VERSION = @VERSION@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ prefix = @prefix@ program_transform_name = @program_transform_name@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ tse3plth_HEADERS = Alsa.h OSS.h RiscOS.h Factory.h Win32.h Arts.h \ RiscOS.cpp Win32.cpp $(tse3plth_HEADERS_arts) \ $(tse3plth_HEADERS_win32) tse3plthdir = $(pkgincludedir)/plt noinst_LTLIBRARIES = libtse3plt.la libtse3plt_la_SOURCES = OSS.cpp $(libtse3plt_la_SOURCES_factory) \ $(libtse3plt_la_SOURCES_alsa) $(libtse3plt_la_SOURCES_arts) \ $(libtse3plt_la_SOURCES_win32) EXTRA_DIST = Arts.cpp Win32.cpp RiscOS.cpp Factory_Unix.cpp Factory_Win32.cpp Alsa-0.5.cpp Alsa-0.9.cpp midiswis.h DISTCLEANFILES = ./.deps/* ./.deps/.P INCLUDES = -I$(top_srcdir)/src $(INCLUDES_arts) $(INCLUDES_win32) @TSE3_WITH_WIN32_FALSE@libtse3plt_la_SOURCES_factory = Factory_Unix.cpp ############################################################################### # Conditional on what interface support is being built in... # Factory @TSE3_WITH_WIN32_TRUE@libtse3plt_la_SOURCES_factory = Factory_Win32.cpp @TSE3_WITH_ALSA_0_5_X_FALSE@@TSE3_WITH_ALSA_TRUE@libtse3plt_la_SOURCES_alsa = Alsa-0.9.cpp # Alsa @TSE3_WITH_ALSA_0_5_X_TRUE@@TSE3_WITH_ALSA_TRUE@libtse3plt_la_SOURCES_alsa = Alsa-0.5.cpp @TSE3_WITH_ALSA_FALSE@libtse3plt_la_SOURCES_alsa = @TSE3_WITH_ALSA_FALSE@libtse3plt_la_LIBADD_alsa = @TSE3_WITH_ALSA_TRUE@libtse3plt_la_LIBADD_alsa = $(LIBASOUND) @TSE3_WITH_ARTS_FALSE@tse3plth_HEADERS_arts = # Arts @TSE3_WITH_ARTS_TRUE@tse3plth_HEADERS_arts = Arts.h @TSE3_WITH_ARTS_FALSE@libtse3plt_la_SOURCES_arts = @TSE3_WITH_ARTS_TRUE@libtse3plt_la_SOURCES_arts = Arts.cpp @TSE3_WITH_ARTS_FALSE@libtse3plt_la_LIBADD_arts = @TSE3_WITH_ARTS_TRUE@libtse3plt_la_LIBADD_arts = $(LIBARTS) -lartsmidi @TSE3_WITH_ARTS_FALSE@INCLUDES_arts = @TSE3_WITH_ARTS_TRUE@INCLUDES_arts = -I$(TSE3_ARTS_PREFIX) libtse3plt_la_LIBADD = $(libtse3plt_la_LIBADD_alsa) \ $(libtse3plt_la_LIBADD_arts) $(libtse3plt_la_LIBADD_win32) @TSE3_WITH_WIN32_FALSE@tse3plth_HEADERS_win32 = # Win32 (obviously, under cygwin or mingw32) @TSE3_WITH_WIN32_TRUE@tse3plth_HEADERS_win32 = Win32.h @TSE3_WITH_WIN32_FALSE@libtse3plt_la_SOURCES_win32 = @TSE3_WITH_WIN32_TRUE@libtse3plt_la_SOURCES_win32 = Win32.cpp @TSE3_WITH_WIN32_FALSE@libtse3plt_la_LIBADD_win32 = @TSE3_WITH_WIN32_TRUE@libtse3plt_la_LIBADD_win32 = @TSE3_WITH_WIN32_TRUE@INCLUDES_wind32 = @TSE3_WITH_WIN32_FALSE@INCLUDES_win32 = all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tse3/plt/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/tse3/plt/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libtse3plt.la: $(libtse3plt_la_OBJECTS) $(libtse3plt_la_DEPENDENCIES) $(CXXLINK) $(libtse3plt_la_LDFLAGS) $(libtse3plt_la_OBJECTS) $(libtse3plt_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Alsa-0.5.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Alsa-0.9.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Arts.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Factory_Unix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Factory_Win32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OSS.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Win32.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: install-tse3plthHEADERS: $(tse3plth_HEADERS) @$(NORMAL_INSTALL) test -z "$(tse3plthdir)" || $(mkdir_p) "$(DESTDIR)$(tse3plthdir)" @list='$(tse3plth_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(tse3plthHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(tse3plthdir)/$$f'"; \ $(tse3plthHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(tse3plthdir)/$$f"; \ done uninstall-tse3plthHEADERS: @$(NORMAL_UNINSTALL) @list='$(tse3plth_HEADERS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(tse3plthdir)/$$f'"; \ rm -f "$(DESTDIR)$(tse3plthdir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(tse3plthdir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-tse3plthHEADERS install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am uninstall-tse3plthHEADERS .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip install-tse3plthHEADERS installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-info-am \ uninstall-tse3plthHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: tse3-0.3.1/src/tse3/plt/Alsa-0.5.cpp0000644000175700001440000005650310271145620013454 00000000000000/* * @(#)Alsa-0.5.cpp 3.00 12 October 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/plt/Alsa.h" #include "tse3/Error.h" #include "tse3/util/MulDiv.h" #ifdef HAVE_CONFIG_H #include #else #define HAVE_SYS_ASOUNDLIB_H #endif #define _GNU_SOURCE #include #include #include #ifdef HAVE_SYS_ASOUNDLIB_H #include #elif HAVE_ALSA_ASOUNDLIB_H #include #endif #include #include #include using namespace TSE3; using namespace TSE3::Plt; namespace { // Temporary data areas where we store return values char tmpPortNameBuffer[64 + 20]; // + 20 because I add " client:port" char tmpGroupNameBuffer[64]; } /****************************************************************************** * AlsaImpl class *****************************************************************************/ /** * Note that this class is a private implementation class, but it is not self * contained, the Alsa driving logic is split between this and the * AlsaMidiScheduler class. This class does all the good initialisation, * though. * * @short Alsa MidiScheduler private implementation * @author Pete Goodliffe * @version 0.00 * @see AlsaMidiScheduler */ class TSE3::Plt::AlsaImpl { public: /* * Internal Alsa implementation state data */ snd_seq_t *handle; // our handle onto Alsa snd_seq_client_info_t client_info; // info about ourself snd_seq_port_info_t port_info; // info about our port int queue; // the id of the queue we create // Alsa destinations are client/port pairs. Whilst the MidiScheduler // API supports ports numbered 0-X, in Alsa these numbers are // non-contiguous. Therefore this vector holds a lookup table for // destination info. It is a pair containing . typedef std::pair dest_type; std::vector dest; std::vector running; std::vector > sysex; // sysex buffers /* * Private APIs */ AlsaImpl(); ~AlsaImpl(); /** * Sends the MidiCommand. If no queue is specified, it is sent * immediately, bypassing the queue. * * In this version of the driver we only support timing in msecs. * Later on we'll hook into Alsa's ticks and then be able to sync * to external timing sources. */ void tx(MidiCommand mc, int queue = SND_SEQ_QUEUE_DIRECT, long int sec = 0, long int nsec = 0); }; TSE3::Plt::AlsaImpl::AlsaImpl() { // Check for ALSA support on machine struct stat buf; stat("/proc/asound", &buf); if ((stat("/proc/asound", &buf) != 0 ) || !(S_ISDIR(buf.st_mode))) { std::cerr << "TSE3: Alsa scheduler error.\n" << " Alsa is not running on this machine\n"; throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } int r = snd_seq_open(&handle, SND_SEQ_OPEN); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error. Couldn't open sequencer\n" << " (" << snd_strerror(r) << ")\n"; throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } // Get info about ourself r = snd_seq_get_client_info(handle, &client_info); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error. Couldn't get client info\n" << " (" << snd_strerror(r) << ")\n"; throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } // Create a port to connect to all output ports available std::memset(&port_info, 0, sizeof(port_info)); std::strcpy(port_info.name, "TSE3"); std::strcpy(port_info.group, SND_SEQ_GROUP_APPLICATION); port_info.capability = SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_DUPLEX; port_info.cap_group = port_info.capability; port_info.type = SND_SEQ_PORT_TYPE_APPLICATION; r = snd_seq_create_port(handle, &port_info); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error. Couldn't create port\n" << " (" << snd_strerror(r) << ")\n"; snd_seq_close(handle); throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } // Create a queue to schedule data on queue = snd_seq_alloc_named_queue(handle, "TSE3 queue"); if (queue < 0) { std::cerr << "TSE3: Alsa scheduler error. Couldn't allocate queue\n" << " (" << snd_strerror(r) << ")\n"; snd_seq_close(handle); throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } } TSE3::Plt::AlsaImpl::~AlsaImpl() { snd_seq_close(handle); } /* * This was in the AlsaImpl, an internal API. However, the need to all * addPort and removePort means that I have to make it a member of * the AlsaMidiScheduler */ void TSE3::Plt::AlsaMidiScheduler::getSystemInfo() { // Remove all devices from the public API { int index = 0; std::vector::iterator i = pimpl->dest.begin(); while (i != pimpl->dest.end()) { removePort(index); ++index; ++i; } } pimpl->dest.clear(); snd_seq_client_info_t ci; int r = 0; ci.client = -1; do { std::strcpy(ci.name, ""); std::strcpy(ci.group, ""); r = snd_seq_query_next_client(pimpl->handle, &ci); if (r >= 0 // more clients to poll && ci.client != 0 // no system clients && ci.client != pimpl->client_info.client) // not ourselves { snd_seq_port_info_t pi; int r2 = 0; pi.client = ci.client; pi.port = -1; do { std::strcpy(pi.name, ""); std::strcpy(pi.group, ""); r2 = snd_seq_query_next_port(pimpl->handle, &pi); if (r2 >= 0) { unsigned int outcaps = SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_WRITE; unsigned int incaps = SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_READ; // "&& pi.type" weeds out system devices if ((pi.capability & outcaps) && pi.type) { pimpl->dest.push_back (AlsaImpl::dest_type(pi.client, pi.port)); snd_seq_connect_to(pimpl->handle, pimpl->port_info.port, pi.client, pi.port); } if ((pi.capability & incaps)) { snd_seq_port_subscribe_t subs; std::memset(&subs, 0, sizeof(subs)); subs.sender.client = pi.client; subs.sender.port = pi.port; subs.dest.client = pimpl->port_info.client; subs.dest.port = pimpl->port_info.port; subs.queue = pimpl->queue; subs.realtime = 0; subs.exclusive = 0; subs.convert_time = 1; subs.midi_channels = 0; subs.midi_voices = 0; subs.synth_voices = 0; int r3 = snd_seq_subscribe_port(pimpl->handle, &subs); if (r3 < 0) { std::cerr << "TSE3: Cannot subscribe to " << pi.client << ":" << pi.port << "\n" << " (" << snd_strerror(r3) << ")\n"; } } } } while (r2 >= 0); } } while (r >= 0); pimpl->running.clear(); pimpl->running.insert(pimpl->running.begin(), pimpl->dest.size(), 0); pimpl->sysex.clear(); pimpl->sysex.insert(pimpl->sysex.begin(), pimpl->dest.size(), std::vector()); // Now let the public API know about these devices { int index = 0; std::vector::iterator i = pimpl->dest.begin(); while (i != pimpl->dest.end()) { addPort(index, i->first < 64, i->first); // isInternal correct? ++index; ++i; } } } void TSE3::Plt::AlsaImpl::tx(MidiCommand mc, int queue, long int sec, long int nsec) { snd_seq_event_t ev; if (mc.port > (int)dest.size()-1) { mc.port = dest.size()-1; } snd_seq_ev_clear(&ev); snd_seq_ev_set_dest(&ev, dest[mc.port].first, dest[mc.port].second); snd_seq_ev_set_source(&ev, port_info.port); snd_seq_real_time_t time = { sec, nsec }; snd_seq_ev_schedule_real(&ev, queue, 0 /*absolute*/, &time); switch (mc.status) { case MidiCommand_NoteOn: { if (mc.data2) { snd_seq_ev_set_noteon(&ev, mc.channel, mc.data1, mc.data2); break; } // Intentional fallthrough } case MidiCommand_NoteOff: { snd_seq_ev_set_noteoff(&ev, mc.channel, mc.data1, mc.data2); break; } case MidiCommand_KeyPressure: { snd_seq_ev_set_keypress(&ev, mc.channel, mc.data1, mc.data2); break; } case MidiCommand_ProgramChange: { snd_seq_ev_set_pgmchange(&ev, mc.channel, mc.data1); break; } case MidiCommand_ChannelPressure: { snd_seq_ev_set_chanpress(&ev, mc.channel, mc.data1); break; } case MidiCommand_PitchBend: { int pb = (mc.data1 << 7) | (mc.data2 & 0x7f); snd_seq_ev_set_pitchbend(&ev, mc.channel, pb); break; } case MidiCommand_ControlChange: { snd_seq_ev_set_controller(&ev, mc.channel, mc.data1, mc.data2); break; } case MidiCommand_System: { switch (mc.channel) { case MidiSystem_SysExStart: { if (running[mc.port] != (mc.status<<4) + mc.channel) { sysex[mc.port].clear(); sysex[mc.port].push_back((mc.status<<4) + mc.channel); } sysex[mc.port].push_back(mc.data1); break; } case MidiSystem_SysExEnd: { sysex[mc.port].push_back((mc.status<<4) + mc.channel); snd_seq_ev_set_sysex(&ev, sysex[mc.port].size(), &(sysex[mc.port][0])); break; } } break; } default: { return; } } snd_seq_event_output(handle, &ev); snd_seq_flush_output(handle); running[mc.port] = (mc.status<<4) + mc.channel; } /****************************************************************************** * AlsaMidiScheduler class (0.5 version) *****************************************************************************/ AlsaMidiScheduler::AlsaMidiScheduler() : pimpl(new AlsaImpl()) { // Get system info getSystemInfo(); } AlsaMidiScheduler::~AlsaMidiScheduler() { // if playing, stop first! if (running()) stop(-1); delete pimpl; } const char *AlsaMidiScheduler::impl_implementationName() const { return "AlsaMidiScheduler version [0.5] 1.01"; } const char *AlsaMidiScheduler::impl_portName(int port) const { if (port < (int)pimpl->dest.size()) { snd_seq_port_info_t port_info; int r = snd_seq_get_any_port_info(pimpl->handle, pimpl->dest[port].first, pimpl->dest[port].second, &port_info); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error reading port name\n" << " (" << snd_strerror(r) << ")\n"; return "TSE3: No port name"; } std::sprintf(tmpPortNameBuffer, "%s %d:%d", port_info.name, pimpl->dest[port].first, pimpl->dest[port].second); return tmpPortNameBuffer; } else { return "Invalid port"; } } const char *AlsaMidiScheduler::impl_portType(int port) const { if (port < (int)pimpl->dest.size()) { snd_seq_port_info_t port_info; int r = snd_seq_get_any_port_info(pimpl->handle, pimpl->dest[port].first, pimpl->dest[port].second, &port_info); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error reading port type\n" << " (" << snd_strerror(r) << ")\n"; return "TSE3: No port type"; } std::strcpy(tmpGroupNameBuffer, port_info.group); return tmpGroupNameBuffer; } else { return "Invalid port"; } } bool AlsaMidiScheduler::impl_portReadable(int port) const { if (port < (int)pimpl->dest.size()) { snd_seq_port_info_t port_info; int r = snd_seq_get_any_port_info(pimpl->handle, pimpl->dest[port].first, pimpl->dest[port].second, &port_info); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error reading port readable\n" << " (" << snd_strerror(r) << ")\n"; return false; } return port_info.capability & SND_SEQ_PORT_CAP_READ; } return false; } bool AlsaMidiScheduler::impl_portWriteable(int port) const { if (port < (int)pimpl->dest.size()) { snd_seq_port_info_t port_info; int r = snd_seq_get_any_port_info(pimpl->handle, pimpl->dest[port].first, pimpl->dest[port].second, &port_info); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error reading port writeable\n" << " (" << snd_strerror(r) << ")\n"; return false; } return port_info.capability & SND_SEQ_PORT_CAP_WRITE; } return false; } void AlsaMidiScheduler::impl_tx(MidiCommand mc) { pimpl->tx(mc, SND_SEQ_QUEUE_DIRECT); } void AlsaMidiScheduler::impl_start(const Clock s) { if (!running()) { startClock = s; snd_seq_queue_tempo_t tempo; int r = snd_seq_get_queue_tempo(pimpl->handle, pimpl->queue, &tempo); tempo.tempo = 10; tempo.ppq = Clock::PPQN; r = snd_seq_set_queue_tempo(pimpl->handle, pimpl->queue, &tempo); // Start system clock snd_seq_event_t ev; ev.queue = pimpl->queue; ev.dest.client = SND_SEQ_CLIENT_SYSTEM; ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; ev.data.queue.queue = pimpl->queue; ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL; ev.time.time.tv_sec = 0; ev.time.time.tv_nsec = 0; ev.type = SND_SEQ_EVENT_START; snd_seq_event_output(pimpl->handle, &ev); snd_seq_flush_output(pimpl->handle); r = snd_seq_start_queue(pimpl->handle, pimpl->queue, NULL); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error starting queue\n" << " (" << snd_strerror(r) << ")\n"; } clockStarted(s); } } void AlsaMidiScheduler::impl_stop(Clock t) { if (!running()) return; int r = snd_seq_stop_queue(pimpl->handle, pimpl->queue, NULL); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error stopping queue\n" << " (" << snd_strerror(r) << ")\n"; } // Stop system clock snd_seq_event_t ev; ev.queue = pimpl->queue; ev.dest.client = SND_SEQ_CLIENT_SYSTEM; ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; ev.data.queue.queue = pimpl->queue; ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL; ev.time.time.tv_sec = 0; ev.time.time.tv_nsec = 0; ev.type = SND_SEQ_EVENT_STOP; snd_seq_event_output(pimpl->handle, &ev); snd_seq_flush_output(pimpl->handle); clockStopped(t); } void AlsaMidiScheduler::impl_moveTo(const Clock moveTime, const Clock newTime) { clockMoved(moveTime, newTime); } Clock AlsaMidiScheduler::impl_clock() { snd_seq_queue_status_t status; int r; // This loop fixes an Alsa 0.5.x bug where nsecs can be reported // erroneously do { r = snd_seq_get_queue_status(pimpl->handle, pimpl->queue, &status); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error getting queue status\n" << " (" << snd_strerror(r) << ")\n"; } if ((unsigned long) status.time.tv_nsec > (unsigned long) 999999999) { // cout << "once again\n"; continue; } int milli = status.time.tv_sec*1000 + status.time.tv_nsec/1000000; return msToClock(milli); } while(1); } int AlsaMidiScheduler::impl_msecs() { snd_seq_queue_status_t status; int r; // This loop fixes an Alsa 0.5.x bug where nsecs can be reported // erroneously do { r = snd_seq_get_queue_status(pimpl->handle, pimpl->queue, &status); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error getting queue status\n" << " (" << snd_strerror(r) << ")\n"; } if (status.time.tv_nsec > 999999999) { // cout << "once again\n"; continue; } return status.time.tv_sec*1000 + status.time.tv_nsec/1000000; } while(1); } void AlsaMidiScheduler::impl_setTempo(int newTempo, Clock changeTime) { tempoChanged(newTempo, changeTime); /* int r = snd_seq_change_queue_tempo(pimpl->handle, pimpl->queue, newTempo, NULL); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error getting queue tempo\n" << " (" << snd_strerror(r) << ")\n"; }*/ } bool AlsaMidiScheduler::impl_eventWaiting() { return snd_seq_event_input_pending(pimpl->handle, 1); } TSE3::MidiEvent AlsaMidiScheduler::impl_rx() { if (!impl_eventWaiting()) return MidiEvent(); snd_seq_event_t *ev; int r = snd_seq_event_input(pimpl->handle, &ev); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error getting input event\n" << " (" << snd_strerror(r) << ")\n"; return MidiEvent(); } MidiEvent e; switch (ev->type) { case SND_SEQ_EVENT_NOTE: case SND_SEQ_EVENT_KEYPRESS: case SND_SEQ_EVENT_SYSEX: { // Hopefully this can't be read from the sequencer XXX std::cerr << "TSE3: Alsa: Received invalid input type " << ev->type << "\n"; break; } case SND_SEQ_EVENT_NOTEON: { e = MidiEvent(MidiCommand(MidiCommand_NoteOn, ev->data.note.channel, 0 /*port*/, ev->data.note.note, ev->data.note.velocity), msToClock(msecs())); break; } case SND_SEQ_EVENT_NOTEOFF: { e = MidiEvent(MidiCommand(MidiCommand_NoteOff, ev->data.note.channel, 0 /*port*/, ev->data.note.note, ev->data.note.velocity), msToClock(msecs())); break; } case SND_SEQ_EVENT_CONTROLLER: { e = MidiEvent(MidiCommand(MidiCommand_ControlChange, ev->data.control.channel, 0 /*port*/, ev->data.control.param, ev->data.control.value), msToClock(msecs())); break; } case SND_SEQ_EVENT_PGMCHANGE: { e = MidiEvent(MidiCommand(MidiCommand_ProgramChange, ev->data.control.channel, 0 /*port*/, ev->data.control.value), msToClock(msecs())); break; } case SND_SEQ_EVENT_PITCHBEND: { e = MidiEvent(MidiCommand(MidiCommand_PitchBend, ev->data.control.channel, 0 /*port*/, ev->data.control.value >> 7, ev->data.control.value & 0x7f), msToClock(msecs())); break; } case SND_SEQ_EVENT_CHANPRESS: { e = MidiEvent(MidiCommand(MidiCommand_ChannelPressure, ev->data.control.channel, 0 /*port*/, ev->data.control.value), msToClock(msecs())); break; } } snd_seq_free_event(ev); return e; } void AlsaMidiScheduler::impl_tx(MidiEvent e) { pimpl->tx(e.data, pimpl->queue, clockToMs(e.time)/1000, (clockToMs(e.time)%1000)*1000000); } void AlsaMidiScheduler::impl_txSysEx(int port, const unsigned char *data, size_t size) { snd_seq_event_t event; snd_seq_ev_clear(&event); snd_seq_ev_set_sysex(&event, size, (void *)data); snd_seq_ev_set_dest(&event, pimpl->dest[port].first, pimpl->dest[port].second); snd_seq_ev_set_source(&event, pimpl->port_info.port); snd_seq_real_time_t time = { 0, 0 }; snd_seq_ev_schedule_real(&event, SND_SEQ_QUEUE_DIRECT, 0/*abslt*/, &time); snd_seq_event_output(pimpl->handle, &event); snd_seq_flush_output(pimpl->handle); } tse3-0.3.1/src/tse3/plt/Alsa-0.9.cpp0000644000175700001440000005404710271145620013461 00000000000000/* * @(#)Alsa-0.9.cpp 3.00 28 March 2002 * * Copyright (c) 2002 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/plt/Alsa.h" #include "tse3/Error.h" #include "tse3/util/MulDiv.h" #ifdef HAVE_CONFIG_H #include #else #define HAVE_SYS_ASOUNDLIB_H #endif #define _GNU_SOURCE #include #include #include #if HAVE_ALSA_ASOUNDLIB_H #include #elif HAVE_SYS_ASOUNDLIB_H #include #endif #include #include #include using namespace TSE3; using namespace TSE3::Plt; namespace { // Temporary data areas where we store return values char tmpPortNameBuffer[64 + 20]; // + 20 because I add " client:port" } /****************************************************************************** * AlsaImpl class *****************************************************************************/ /** * Note that this class is a private implementation class, but it is not self * contained, the Alsa driving logic is split between this and the * AlsaMidiScheduler class. This class does all the good initialisation, * though. * * @short Alsa MidiScheduler private implementation * @author Pete Goodliffe * @version 0.00 * @see AlsaMidiScheduler */ class TSE3::Plt::AlsaImpl { public: /* * Internal Alsa implementation state data */ snd_seq_t *handle; // our handle onto Alsa snd_seq_client_info_t *client_info; // info about ourself snd_seq_port_info_t *port_info; // info about our port int my_port; int queue; // the id of the queue we create // Alsa destinations are client/port pairs. Whilst the MidiScheduler // API supports ports numbered 0-X, in Alsa these numbers are // non-contiguous. Therefore this vector holds a lookup table for // destination info. It is a pair containing . typedef std::pair dest_type; std::vector dest; std::vector running; std::vector > sysex; // sysex buffers /* * Private APIs */ AlsaImpl(); ~AlsaImpl(); /** * Sends the MidiCommand. If no queue is specified, it is sent * immediately, bypassing the queue. * * In this version of the driver we only support timing in msecs. * Later on we'll hook into Alsa's ticks and then be able to sync * to external timing sources. */ void tx(MidiCommand mc, int queue = SND_SEQ_QUEUE_DIRECT, long int sec = 0, long int nsec = 0); }; TSE3::Plt::AlsaImpl::AlsaImpl() : handle(0), client_info(0), port_info(0) { // Check for ALSA support on machine struct stat buf; stat("/proc/asound", &buf); if ((stat("/proc/asound", &buf) != 0 ) || !(S_ISDIR(buf.st_mode))) { std::cerr << "TSE3: Alsa scheduler error.\n" << " Alsa is not running on this machine\n"; throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } int r = snd_seq_open(&handle, "hw", SND_SEQ_OPEN_DUPLEX, 0); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error. Couldn't open sequencer\n" << " (" << snd_strerror(r) << ")\n"; throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } // Get info about ourself snd_seq_client_info_malloc(&client_info); r = snd_seq_get_client_info(handle, client_info); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error. Couldn't get client info\n" << " (" << snd_strerror(r) << ")\n"; throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } // Create a port to connect to all output ports available snd_seq_port_info_malloc(&port_info); snd_seq_port_info_set_name(port_info, "TSE3"); snd_seq_port_info_set_capability(port_info, SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_DUPLEX); snd_seq_port_info_set_type(port_info, SND_SEQ_PORT_TYPE_APPLICATION); r = snd_seq_create_port(handle, port_info); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error. Couldn't create port\n" << " (" << snd_strerror(r) << ")\n"; snd_seq_close(handle); throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } my_port = snd_seq_port_info_get_port(port_info); // Create a queue to schedule data on queue = snd_seq_alloc_named_queue(handle, "TSE3 queue"); if (queue < 0) { std::cerr << "TSE3: Alsa scheduler error. Couldn't allocate queue\n" << " (" << snd_strerror(r) << ")\n"; snd_seq_close(handle); throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } } TSE3::Plt::AlsaImpl::~AlsaImpl() { if (handle) snd_seq_close(handle); if (client_info) snd_seq_client_info_free(client_info); if (port_info) snd_seq_port_info_free(port_info); } /* * This was in the AlsaImpl, an internal API. However, the need to all * addPort and removePort means that I have to make it a member of * the AlsaMidiScheduler */ void TSE3::Plt::AlsaMidiScheduler::getSystemInfo() { // Remove all devices from the public API { int index = 0; std::vector::iterator i = pimpl->dest.begin(); while (i != pimpl->dest.end()) { removePort(index); ++index; ++i; } } pimpl->dest.clear(); snd_seq_client_info_t *ci; snd_seq_client_info_alloca(&ci); snd_seq_client_info_set_client(ci, 0); while (snd_seq_query_next_client(pimpl->handle, ci) >= 0) { int c = snd_seq_client_info_get_client(ci); if (c == snd_seq_client_info_get_client(pimpl->client_info)) { continue; // not ourselves } snd_seq_port_info_t *pi; snd_seq_port_info_alloca(&pi); // XXX free? snd_seq_port_info_set_client(pi, c); snd_seq_port_info_set_port(pi, -1); while (snd_seq_query_next_port(pimpl->handle, pi) >= 0) { int p = snd_seq_port_info_get_port(pi); unsigned int outcaps = SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_WRITE; unsigned int incaps = SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_READ; // "&& pi.type" weeds out system devices if (snd_seq_port_info_get_capability(pi) & outcaps) { pimpl->dest.push_back(AlsaImpl::dest_type(c, p)); snd_seq_connect_to(pimpl->handle, pimpl->my_port, c, p); } if (snd_seq_port_info_get_capability(pi) & incaps) { snd_seq_port_subscribe_t *subs; snd_seq_port_subscribe_alloca(&subs); snd_seq_port_subscribe_set_sender (subs, snd_seq_port_info_get_addr(pi)); snd_seq_port_subscribe_set_dest (subs, snd_seq_port_info_get_addr(pimpl->port_info)); snd_seq_port_subscribe_set_queue(subs, pimpl->queue); snd_seq_port_subscribe_set_time_update(subs, 1); int r3 = snd_seq_subscribe_port(pimpl->handle, subs); if (r3 < 0) { std::cerr << "TSE3: Cannot subscribe to " << c << ":" << p << "\n" << " (" << snd_strerror(r3) << ")\n"; } } } } pimpl->running.clear(); pimpl->running.insert(pimpl->running.begin(), pimpl->dest.size(), 0); pimpl->sysex.clear(); pimpl->sysex.insert(pimpl->sysex.begin(), pimpl->dest.size(), std::vector()); // Now let the public API know about these devices { int index = 0; std::vector::iterator i = pimpl->dest.begin(); while (i != pimpl->dest.end()) { addPort(index, i->first < 64, i->first); // XXX isInternal correct? ++index; ++i; } } } void TSE3::Plt::AlsaImpl::tx(MidiCommand mc, int queue, long int sec, long int nsec) { snd_seq_event_t ev; if (mc.port > (int)dest.size()-1) { mc.port = dest.size()-1; } snd_seq_ev_clear(&ev); snd_seq_ev_set_dest(&ev, dest[mc.port].first, dest[mc.port].second); snd_seq_ev_set_source(&ev, my_port); snd_seq_real_time_t time = { sec, nsec }; snd_seq_ev_schedule_real(&ev, queue, 0 /*absolute*/, &time); switch (mc.status) { case MidiCommand_NoteOn: { if (mc.data2) { snd_seq_ev_set_noteon(&ev, mc.channel, mc.data1, mc.data2); break; } // Intentional fallthrough } case MidiCommand_NoteOff: { snd_seq_ev_set_noteoff(&ev, mc.channel, mc.data1, mc.data2); break; } case MidiCommand_KeyPressure: { snd_seq_ev_set_keypress(&ev, mc.channel, mc.data1, mc.data2); break; } case MidiCommand_ProgramChange: { snd_seq_ev_set_pgmchange(&ev, mc.channel, mc.data1); break; } case MidiCommand_ChannelPressure: { snd_seq_ev_set_chanpress(&ev, mc.channel, mc.data1); break; } case MidiCommand_PitchBend: { int pb = (mc.data1 << 7) | (mc.data2 & 0x7f); snd_seq_ev_set_pitchbend(&ev, mc.channel, pb); break; } case MidiCommand_ControlChange: { snd_seq_ev_set_controller(&ev, mc.channel, mc.data1, mc.data2); break; } case MidiCommand_System: { switch (mc.channel) { case MidiSystem_SysExStart: { if (running[mc.port] != (mc.status<<4) + mc.channel) { sysex[mc.port].clear(); sysex[mc.port].push_back((mc.status<<4) + mc.channel); } sysex[mc.port].push_back(mc.data1); break; } case MidiSystem_SysExEnd: { sysex[mc.port].push_back((mc.status<<4) + mc.channel); snd_seq_ev_set_sysex(&ev, sysex[mc.port].size(), &(sysex[mc.port][0])); break; } } break; } default: { return; } } snd_seq_event_output(handle, &ev); snd_seq_drain_output(handle); running[mc.port] = (mc.status<<4) + mc.channel; } /****************************************************************************** * AlsaMidiScheduler class (0.9 version) *****************************************************************************/ AlsaMidiScheduler::AlsaMidiScheduler() : pimpl(new AlsaImpl()) { // Get system info getSystemInfo(); } AlsaMidiScheduler::~AlsaMidiScheduler() { // if playing, stop first! if (running()) stop(-1); delete pimpl; } const char *AlsaMidiScheduler::impl_implementationName() const { return "AlsaMidiScheduler version [0.9] 1.02"; } const char *AlsaMidiScheduler::impl_portName(int port) const { if (port < (int)pimpl->dest.size()) { snd_seq_port_info_t *port_info; snd_seq_port_info_alloca(&port_info); int r = snd_seq_get_any_port_info(pimpl->handle, pimpl->dest[port].first, pimpl->dest[port].second, port_info); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error reading port name\n" << " (" << snd_strerror(r) << ")\n"; return "TSE3: No port name"; } std::sprintf(tmpPortNameBuffer, "%s %d:%d", snd_seq_port_info_get_name(port_info), pimpl->dest[port].first, pimpl->dest[port].second); return tmpPortNameBuffer; } else { return "Invalid port"; } } const char *AlsaMidiScheduler::impl_portType(int) const { return "ALSA MIDI port"; } bool AlsaMidiScheduler::impl_portReadable(int port) const { if (port < (int)pimpl->dest.size()) { snd_seq_port_info_t *port_info; snd_seq_port_info_alloca(&port_info); int r = snd_seq_get_any_port_info(pimpl->handle, pimpl->dest[port].first, pimpl->dest[port].second, port_info); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error reading port readable\n" << " (" << snd_strerror(r) << ")\n"; return false; } return snd_seq_port_info_get_capability(port_info) & SND_SEQ_PORT_CAP_READ; } return false; } bool AlsaMidiScheduler::impl_portWriteable(int port) const { if (port < (int)pimpl->dest.size()) { snd_seq_port_info_t *port_info; snd_seq_port_info_alloca(&port_info); int r = snd_seq_get_any_port_info(pimpl->handle, pimpl->dest[port].first, pimpl->dest[port].second, port_info); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error reading port writeable\n" << " (" << snd_strerror(r) << ")\n"; return false; } return snd_seq_port_info_get_capability(port_info) & SND_SEQ_PORT_CAP_WRITE; } return false; } void AlsaMidiScheduler::impl_tx(MidiCommand mc) { pimpl->tx(mc); } void AlsaMidiScheduler::impl_start(const Clock s) { if (!running()) { startClock = s; snd_seq_queue_tempo_t *tempo; snd_seq_queue_tempo_alloca(&tempo); int r = snd_seq_get_queue_tempo(pimpl->handle, pimpl->queue, tempo); snd_seq_queue_tempo_set_tempo(tempo, 10); snd_seq_queue_tempo_set_ppq(tempo, Clock::PPQN); r = snd_seq_set_queue_tempo(pimpl->handle, pimpl->queue, tempo); // Start system clock snd_seq_event_t ev; ev.queue = pimpl->queue; ev.dest.client = SND_SEQ_CLIENT_SYSTEM; ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; ev.data.queue.queue = pimpl->queue; ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL; ev.time.time.tv_sec = 0; ev.time.time.tv_nsec = 0; ev.type = SND_SEQ_EVENT_START; snd_seq_event_output(pimpl->handle, &ev); snd_seq_drain_output(pimpl->handle); r = snd_seq_start_queue(pimpl->handle, pimpl->queue, NULL); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error starting queue\n" << " (" << snd_strerror(r) << ")\n"; } clockStarted(s); } } void AlsaMidiScheduler::impl_stop(Clock t) { if (!running()) return; int r = snd_seq_stop_queue(pimpl->handle, pimpl->queue, NULL); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error stopping queue\n" << " (" << snd_strerror(r) << ")\n"; } // Stop system clock snd_seq_event_t ev; ev.queue = pimpl->queue; ev.dest.client = SND_SEQ_CLIENT_SYSTEM; ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; ev.data.queue.queue = pimpl->queue; ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL; ev.time.time.tv_sec = 0; ev.time.time.tv_nsec = 0; ev.type = SND_SEQ_EVENT_STOP; snd_seq_event_output(pimpl->handle, &ev); snd_seq_drain_output(pimpl->handle); clockStopped(t); } void AlsaMidiScheduler::impl_moveTo(const Clock moveTime, const Clock newTime) { clockMoved(moveTime, newTime); } Clock AlsaMidiScheduler::impl_clock() { snd_seq_queue_status_t *status; snd_seq_queue_status_alloca(&status); int r; r = snd_seq_get_queue_status(pimpl->handle, pimpl->queue, status); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error getting queue status\n" << " (" << snd_strerror(r) << ")\n"; } snd_seq_real_time_t rt = *snd_seq_queue_status_get_real_time(status); int milli = rt.tv_sec*1000 + rt.tv_nsec/1000000; return msToClock(milli); } int AlsaMidiScheduler::impl_msecs() { snd_seq_queue_status_t *status; snd_seq_queue_status_alloca(&status); int r; r = snd_seq_get_queue_status(pimpl->handle, pimpl->queue, status); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error getting queue status\n" << " (" << snd_strerror(r) << ")\n"; } snd_seq_real_time_t rt = *snd_seq_queue_status_get_real_time(status); return rt.tv_sec*1000 + rt.tv_nsec/1000000; } void AlsaMidiScheduler::impl_setTempo(int newTempo, Clock changeTime) { tempoChanged(newTempo, changeTime); /* int r = snd_seq_change_queue_tempo(pimpl->handle, pimpl->queue, newTempo, NULL); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error getting queue tempo\n" << " (" << snd_strerror(r) << ")\n"; }*/ } bool AlsaMidiScheduler::impl_eventWaiting() { return snd_seq_event_input_pending(pimpl->handle, 1); } TSE3::MidiEvent AlsaMidiScheduler::impl_rx() { if (!impl_eventWaiting()) return MidiEvent(); snd_seq_event_t *ev; int r = snd_seq_event_input(pimpl->handle, &ev); if (r < 0) { std::cerr << "TSE3: Alsa scheduler error getting input event\n" << " (" << snd_strerror(r) << ")\n"; return MidiEvent(); } MidiEvent e; switch (ev->type) { case SND_SEQ_EVENT_NOTE: case SND_SEQ_EVENT_KEYPRESS: case SND_SEQ_EVENT_SYSEX: { // Hopefully this can't be read from the sequencer XXX std::cerr << "TSE3: Alsa: Received invalid input type " << ev->type << "\n"; break; } case SND_SEQ_EVENT_NOTEON: { e = MidiEvent(MidiCommand(MidiCommand_NoteOn, ev->data.note.channel, 0 /*port*/, ev->data.note.note, ev->data.note.velocity), msToClock(msecs())); break; } case SND_SEQ_EVENT_NOTEOFF: { e = MidiEvent(MidiCommand(MidiCommand_NoteOff, ev->data.note.channel, 0 /*port*/, ev->data.note.note, ev->data.note.velocity), msToClock(msecs())); break; } case SND_SEQ_EVENT_CONTROLLER: { e = MidiEvent(MidiCommand(MidiCommand_ControlChange, ev->data.control.channel, 0 /*port*/, ev->data.control.param, ev->data.control.value), msToClock(msecs())); break; } case SND_SEQ_EVENT_PGMCHANGE: { e = MidiEvent(MidiCommand(MidiCommand_ProgramChange, ev->data.control.channel, 0 /*port*/, ev->data.control.value), msToClock(msecs())); break; } case SND_SEQ_EVENT_PITCHBEND: { e = MidiEvent(MidiCommand(MidiCommand_PitchBend, ev->data.control.channel, 0 /*port*/, ev->data.control.value >> 7, ev->data.control.value & 0x7f), msToClock(msecs())); break; } case SND_SEQ_EVENT_CHANPRESS: { e = MidiEvent(MidiCommand(MidiCommand_ChannelPressure, ev->data.control.channel, 0 /*port*/, ev->data.control.value), msToClock(msecs())); break; } } snd_seq_free_event(ev); return e; } void AlsaMidiScheduler::impl_tx(MidiEvent e) { pimpl->tx(e.data, pimpl->queue, clockToMs(e.time)/1000, (clockToMs(e.time)%1000)*1000000); } void AlsaMidiScheduler::impl_txSysEx(int port, const unsigned char *data, size_t size) { snd_seq_event_t event; snd_seq_ev_clear(&event); snd_seq_ev_set_sysex(&event, size, (void *)data); snd_seq_ev_set_dest(&event, pimpl->dest[port].first, pimpl->dest[port].second); snd_seq_ev_set_source(&event, pimpl->my_port); snd_seq_real_time_t time = { 0, 0 }; snd_seq_ev_schedule_real(&event, SND_SEQ_QUEUE_DIRECT, 0/*abslt*/, &time); snd_seq_event_output(pimpl->handle, &event); snd_seq_drain_output(pimpl->handle); } tse3-0.3.1/src/tse3/plt/OSS.cpp0000644000175700001440000021636510271145620012744 00000000000000/* * @(#)OSS.cpp 3.00 20 July 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/plt/OSS.h" #include "tse3/Error.h" #include "tse3/util/MulDiv.h" #include #include #include #include #include #include // These #includes are linux specific and I need to do some autoconf // magic to work out how to conditionally include them #include #ifdef HAVE_LINUX_AWE_VOICE_H #include #elif HAVE_AWE_VOICE_H #include #elif HAVE__USR_SRC_SYS_I386_ISA_SOUND_AWE_VOICE_H #include "/usr/src/sys/i386/isa/sound/awe_voice.h" #elif HAVE__USR_SRC_SYS_GNU_I386_ISA_SOUND_AWE_VOICE_H #include "/usr/src/sys/gnu/i386/isa/sound/awe_voice.h" #endif #ifndef TSE3_WITH_OSS // Euch! // This is a somewhat nasty hack that will make the file compile quietly // if we're not building with OSS support. struct synth_info { int nr_voices; }; struct midi_info { int fish; }; #endif #include using namespace TSE3; using namespace TSE3::Plt; /****************************************************************************** * Private implementation classes *****************************************************************************/ namespace TSE3 { namespace Plt { /** * An class that provides support for dynamic voice id allocation for * soundcard MIDI output emulation. * * MIDI devices will accept MidiCommand_NoteOns as they come in. If * they get too many then they will have a policy to deal with it: * perhaps not play the additional notes, perhaps switch off the oldest * note, perhaps something more elaborate. Soundcards, on the other * hand, generally have a fixed number of voice generators that one * must address individually. In this case we need a list of which * voices are not yet in use to play a new note along side others. We * also need a list of which voice is assigned to which note (and with * which patch) so that we can switch off the correct voice. That's the * functionality provided by this class. * * It is used by versions of the @ref OSSMidiScheduler_SynthDevice * class to manage which voices are being played at any time. * * This is an internal class - you don't need to directly manipulate it * unless you specifically require it's functionality. * * @short Soundcard voice id allocator * @author Pete Goodliffe * @version 0.00 * @internal */ class VoiceManager { public: /** * Create a VoiceManager that will handle noVoices voices. */ VoiceManager(int noVoices); ~VoiceManager(); /** * Allocate a voice from those available for the * given soundcard. Returns an ID handle for the voice. * * It will first attempt to allocate a currently unused voice. * If there are no unused voices then it will reallocate the * last used voice. * * This method will not perform any OSS system calls to set the * voice up. */ int allocate(int channel, int note); /** * Deallocate a previously allocated voice. * * This method will not perform any OSS system calls to shut * a voice down - it must have been stopped before deallocate * is called. */ void deallocate(int id); /** * Perform a search throught the currently allocated voices * for one matching the given channel. * * Call first time with pos = -1. If returns -1 then there * are no voices on the given channel. Call subsequently * with pos set to the return ID to get the next match. */ int search(int channel, int pos); /** * Similar to search above, but includes the note as a * search criteria. */ int search(int channel, int note, int pos); private: int noVoices; struct Voice { const int id; int channel; int note; bool used; Voice(int id) : id(id), used(false) {} }; Voice **voices; // array of all Voice structs std::list usedVoices; // used voices pushed on back std::list unusedVoices; // unused voices stored here }; /** * A base class for classes that handle different types of OSS device. * * The class uses a number of member variables of the * @ref OSSMidiScheduler object - these are the OSS interface data * memebers that the OSS macros write to. They either have to be shared * in this manner, or the functionality for each type of device must be * rolled into the @ref OSSMidiScheduler class (which is the least * desirable of the two). * * This is an internal class - you don't need to directly manipulate it * unless you specifically require it's functionality. * * @short Soundcard playback handler * @author Pete Goodliffe * @version 0.00 * @internal */ class OSSMidiScheduler_SynthDevice { public: /** * Constructor. Pass in the OSS interface data and the * device number that the class is to provice support for. */ OSSMidiScheduler_SynthDevice(int deviceno, synth_info &synthinfo, int seqfd, unsigned char *&_seqbuf, int &_seqbuflen, int &_seqbufptr); virtual ~OSSMidiScheduler_SynthDevice() = 0; virtual void noteOff(int ch, int note, int vel) = 0; virtual void noteOn(int ch, int note, int vel) = 0; virtual void keyPressure(int ch, int note, int vel) = 0; virtual void controlChange(int ch, int ctrl, int val) = 0; virtual void programChange(int ch, int prog) = 0; virtual void channelPressure(int ch, int vel) = 0; virtual void pitchBend(int ch, int lsb, int msb) = 0; protected: int deviceno; // OSS device the class handles // These data members are created by the OSSMidiScheduler class // and we use them here. We do not delete them in the // constructor. int seqfd; synth_info &synthinfo; unsigned char *&_seqbuf; int &_seqbuflen; int &_seqbufptr; void seqbuf_dump(); void seqbuf_clean(); // Cached information about each channel's state unsigned char _programChange[16]; unsigned char _pitchBendLSB[16]; unsigned char _pitchBendMSB[16]; unsigned char _channelPressure[16]; }; /** * OSS NULL device handler - it does nothing. * * This is an internal class, used by the @ref OSSMidiScheduler class. * * @short Unknown soundcard playback handler * @author Pete Goodliffe * @version 0.00 * @internal */ class OSSMidiScheduler_NULLDevice : public OSSMidiScheduler_SynthDevice { public: OSSMidiScheduler_NULLDevice(int deviceno, synth_info &synthinfo, int seqfd, unsigned char *&_seqbuf, int &_seqbuflen, int &_seqbufptr); virtual ~OSSMidiScheduler_NULLDevice(); /** * @reimplemented */ virtual void noteOff(int ch, int note, int vel); /** * @reimplemented */ virtual void noteOn(int ch, int note, int vel); /** * @reimplemented */ virtual void keyPressure(int ch, int note, int vel); /** * @reimplemented */ virtual void controlChange(int ch, int ctrl, int val); /** * @reimplemented */ virtual void programChange(int ch, int prog); /** * @reimplemented */ virtual void channelPressure(int ch, int vel); /** * @reimplemented */ virtual void pitchBend(int ch, int lsb, int msb); }; /** * OSS FM synth device handler. * * This is an internal class, used by the @ref OSSMidiScheduler class. * However, you will need to call @ref setPatchesDirectory() * before you create an OSSMidiScheduler. * * @short FM soundcard playback handler * @author Pete Goodliffe * @version 0.00 * @internal */ class OSSMidiScheduler_FMDevice : public OSSMidiScheduler_SynthDevice { public: OSSMidiScheduler_FMDevice(int deviceno, synth_info &synthinfo, int seqfd, unsigned char *&_seqbuf, int &_seqbuflen, int &_seqbufptr); virtual ~OSSMidiScheduler_FMDevice(); /** * @reimplemented */ virtual void noteOff(int ch, int note, int vel); /** * @reimplemented */ virtual void noteOn(int ch, int note, int vel); /** * @reimplemented */ virtual void keyPressure(int ch, int note, int vel); /** * @reimplemented */ virtual void controlChange(int ch, int ctrl, int val); /** * @reimplemented */ virtual void programChange(int ch, int prog); /** * @reimplemented */ virtual void channelPressure(int ch, int vel); /** * @reimplemented */ virtual void pitchBend(int ch, int lsb, int msb); /** * This returns in which directory the device will look for * patch files. This must be set before the device is created. * * The patches directory path can contain multiple paths, * separated by colons. * * @see setPatchesDirectory */ static std::string &patchesDirectory() { return _patchesDirectory; } /** * Call this before creating the @ref OSSMidiScheduler object * to set up where to look for FM patches files. * * @see patchesDirectory */ static void setPatchesDirectory(const std::string &dir); private: VoiceManager voiceman; bool patchLoaded[256]; // 0-127 patches, 128-255 drums. void loadPatches(); // Load the patches into the device. int getPatch(int patchNo); // returns patchNo if that patchNo // is loaded, else another patch no // or 256 if couldn't find any. static std::string _patchesDirectory; int opl; // for FM devices whether to do opl 3 (== 3) }; /** * OSS AWE synth device handler. * * This is an internal class, used by the @ref OSSMidiScheduler class. * * @short AWE soundcard playback handler * @author Pete Goodliffe * @version 0.00 * @internal */ class OSSMidiScheduler_AWEDevice : public OSSMidiScheduler_SynthDevice { public: OSSMidiScheduler_AWEDevice(int deviceno, synth_info &synthinfo, int seqfd, unsigned char *&_seqbuf, int &_seqbuflen, int &_seqbufptr); virtual ~OSSMidiScheduler_AWEDevice(); /** * @reimplemented */ virtual void noteOff(int ch, int note, int vel); /** * @reimplemented */ virtual void noteOn(int ch, int note, int vel); /** * @reimplemented */ virtual void keyPressure(int ch, int note, int vel); /** * @reimplemented */ virtual void controlChange(int ch, int ctrl, int val); /** * @reimplemented */ virtual void programChange(int ch, int prog); /** * @reimplemented */ virtual void channelPressure(int ch, int vel); /** * @reimplemented */ virtual void pitchBend(int ch, int lsb, int msb); }; /** * OSS GUS synth device handler. * * This is an internal class, used by the @ref OSSMidiScheduler class. * However, you will need to call @ref setPatchesDirectory() * before you create an OSSMidiScheduler. * * @short GUS soundcard playback handler * @author Pete Goodliffe * @version 0.00 * @internal */ class OSSMidiScheduler_GUSDevice : public OSSMidiScheduler_SynthDevice { public: OSSMidiScheduler_GUSDevice(int deviceno, synth_info &synthinfo, int seqfd, unsigned char *&_seqbuf, int &_seqbuflen, int &_seqbufptr); virtual ~OSSMidiScheduler_GUSDevice(); /** * @reimplemented */ virtual void noteOff(int ch, int note, int vel); /** * @reimplemented */ virtual void noteOn(int ch, int note, int vel); /** * @reimplemented */ virtual void keyPressure(int ch, int note, int vel); /** * @reimplemented */ virtual void controlChange(int ch, int ctrl, int val); /** * @reimplemented */ virtual void programChange(int ch, int prog); /** * @reimplemented */ virtual void channelPressure(int ch, int vel); /** * @reimplemented */ virtual void pitchBend(int ch, int lsb, int msb); /** * This returns in which directory the device will look for * patch files. This must be set before the device is created. * (In fact, it must be set before each voice is loaded - they * are loaded on demand. However, it is safest to set this * before creating the device.) * * The patches directory path can contain multiple paths, * separated by colons. * * @see setPatchesDirectory */ static std::string &patchesDirectory() { return _patchesDirectory; } /** * Call this before creating the @ref OSSMidiScheduler object * to set up where to look for GUS patches files. * * @see patchesDirectory */ static void setPatchesDirectory(const std::string &dir); private: VoiceManager voiceman; size_t nobits; // patch resolution; 8 or 16 int totalMemory; // total memory in soundcard int freeMemory; // free memory in soundcard bool patchLoaded[256]; // 0-127 patches, 128-255 drums. bool patchLoadedFailed[256]; // whether a load attempy failed int getPatch(int patchNo); // returns patchNo if that // patchNo is loaded, else // another patch no or 256 if // couldn't find any. static std::string _patchesDirectory; /** * Returns the filename for the given program change number. * Calls @ref loadPatch() if the patch hasn't been loaded yet. */ static char *patchName(int pgm); /** * Load a patch. 0..127 is a GM program, 128-255 is a drum * patch. Sets patchLoaded and patchLoadedFailed appropriately. * * @return Boolean indicating sucess. */ bool loadPatch(int patch); }; } } /****************************************************************************** * Patch filename search facilities *****************************************************************************/ namespace { /** * The delimiter that separates paths */ const char PATH_DELIM = ':'; const char DEF_PATH[] = "/etc/midi:/etc"; /** * Looks for the file named @p leaf in the directories held in * @p path. There can be more than one directory path in @path, each * separated by a colon. * * The opened file handle that is returned has been opened in "rb" mode. * * @param leaf File's leaf name * @param path Directory path to search in * @return File handle of an open path */ FILE *findFileInPaths(std::string &leaf, std::string &path) { size_t noPaths = std::count(path.begin(), path.end(), PATH_DELIM)+1; std::string::iterator pos1 = path.begin(); std::string::iterator pos2 = find(path.begin(), path.end()-1, PATH_DELIM); FILE *f = 0; while (!f && noPaths) { std::string path(pos1, pos2); std::string file = path + "/" + leaf; pos1 = pos2+1; pos2 = find(pos1, path.end()-1, PATH_DELIM); noPaths--; f = fopen(file.c_str(), "rb"); } return f; } } /****************************************************************************** * The following stuff is used in the GUS device handler *****************************************************************************/ #ifdef TSE3_WITH_OSS namespace { struct pat_header { char magic[12]; char version[10]; char description[60]; unsigned char instruments; char voices; char channels; unsigned short nr_waveforms; unsigned short master_volume; unsigned long data_size; }; struct sample_header { char name[7]; unsigned char fractions; long len; long loop_start; long loop_end; unsigned short base_freq; long low_note; long high_note; long base_note; short detune; unsigned char panning; unsigned char envelope_rate[6]; unsigned char envelope_offset[6]; unsigned char tremolo_sweep; unsigned char tremolo_rate; unsigned char tremolo_depth; unsigned char vibrato_sweep; unsigned char vibrato_rate; unsigned char vibrato_depth; char modes; short scale_frequency; unsigned short scale_factor; }; int get_dint(unsigned char *p) { unsigned int v=0; for (int i=0;i<4;++i) { v |= (p[i] << (i*8)); } return (int)v; } unsigned short get_word(unsigned char *p) { unsigned short v=0; for (int i=0;i<2;++i) v |= (*p++ << (i*8)); return (short)v; } /** * This massive structure holds file names for GUS patches. */ char GUSDevice_PatchNames[256][9] = { /* 0 */ "acpiano", /* 1 */ "britepno", /* 2 */ "synpiano", /* 3 */ "honky", /* 4 */ "epiano1", /* 5 */ "epiano2", /* 6 */ "hrpschrd", /* 7 */ "clavinet", /* 8 */ "celeste", /* 9 */ "glocken", /* 10 */ "musicbox", /* 11 */ "vibes", /* 12 */ "marimba", /* 13 */ "xylophon", /* 14 */ "tubebell", /* 15 */ "santur", /* 16 */ "homeorg", /* 17 */ "percorg", /* 18 */ "rockorg", /* 19 */ "church", /* 20 */ "reedorg", /* 21 */ "accordn", /* 22 */ "harmonca", /* 23 */ "concrtna", /* 24 */ "nyguitar", /* 25 */ "acguitar", /* 26 */ "jazzgtr", /* 27 */ "cleangtr", /* 28 */ "mutegtr", /* 29 */ "odguitar", /* 30 */ "distgtr", /* 31 */ "gtrharm", /* 32 */ "acbass", /* 33 */ "fngrbass", /* 34 */ "pickbass", /* 35 */ "fretless", /* 36 */ "slapbas1", /* 37 */ "slapbas2", /* 38 */ "synbass1", /* 39 */ "synbass2", /* 40 */ "violin", /* 41 */ "viola", /* 42 */ "cello", /* 43 */ "contraba", // /* 44 */ "marcato", /* 44 */ "tremstr", /* 45 */ "pizzcato", /* 46 */ "harp", /* 47 */ "timpani", /* 48 */ "marcato", /* 49 */ "slowstr", /* 50 */ "synstr1", /* 51 */ "synstr2", /* 52 */ "choir", /* 53 */ "doo", /* 54 */ "voices", /* 55 */ "orchhit", /* 56 */ "trumpet", /* 57 */ "trombone", /* 58 */ "tuba", /* 59 */ "mutetrum", /* 60 */ "frenchrn", /* 61 */ "hitbrass", /* 62 */ "synbras1", /* 63 */ "synbras2", /* 64 */ "sprnosax", /* 65 */ "altosax", /* 66 */ "tenorsax", /* 67 */ "barisax", /* 68 */ "oboe", /* 69 */ "englhorn", /* 70 */ "bassoon", /* 71 */ "clarinet", /* 72 */ "piccolo", /* 73 */ "flute", /* 74 */ "recorder", /* 75 */ "woodflut", /* 76 */ "bottle", /* 77 */ "shakazul", /* 78 */ "whistle", /* 79 */ "ocarina", /* 80 */ "sqrwave", /* 81 */ "sawwave", /* 82 */ "calliope", /* 83 */ "chiflead", // /* 84 */ "voxlead", /* 84 */ "charang", /* 85 */ "voxlead", /* 86 */ "lead5th", /* 87 */ "basslead", /* 88 */ "fantasia", /* 89 */ "warmpad", /* 90 */ "polysyn", /* 91 */ "ghostie", /* 92 */ "bowglass", /* 93 */ "metalpad", /* 94 */ "halopad", /* 95 */ "sweeper", /* 96 */ "aurora", /* 97 */ "soundtrk", /* 98 */ "crystal", /* 99 */ "atmosphr", /* 100 */ "freshair", /* 101 */ "unicorn", // /* 102 */ "sweeper", /* 102 */ "echovox", /* 103 */ "startrak", /* 104 */ "sitar", /* 105 */ "banjo", /* 106 */ "shamisen", /* 107 */ "koto", /* 108 */ "kalimba", /* 109 */ "bagpipes", /* 110 */ "fiddle", /* 111 */ "shannai", /* 112 */ "carillon", /* 113 */ "agogo", /* 114 */ "steeldrm", /* 115 */ "woodblk", /* 116 */ "taiko", /* 117 */ "toms", /* 118 */ "syntom", /* 119 */ "revcym", /* 120 */ "fx-fret", /* 121 */ "fx-blow", /* 122 */ "seashore", /* 123 */ "jungle", /* 124 */ "telephon", /* 125 */ "helicptr", /* 126 */ "applause", /* 127 */ "pistol", "", /* 128 = drum 0*/ "", /* 129 = drum 1*/ "", /* 130 = drum 2*/ "", /* 131 = drum 3*/ "", /* 132 = drum 4*/ "", /* 133 = drum 5*/ "", /* 134 = drum 6*/ "", /* 135 = drum 7*/ "", /* 136 = drum 8*/ "", /* 137 = drum 9*/ "", /* 138 = drum 10*/ "", /* 139 = drum 11*/ "", /* 140 = drum 12*/ "", /* 141 = drum 13*/ "", /* 142 = drum 14*/ "", /* 143 = drum 15*/ "", /* 144 = drum 16*/ "", /* 145 = drum 17*/ "", /* 146 = drum 18*/ "", /* 147 = drum 19*/ "", /* 148 = drum 20*/ "", /* 149 = drum 21*/ "", /* 150 = drum 22*/ "", /* 151 = drum 23*/ "", /* 152 = drum 24*/ "", /* 153 = drum 25*/ "", /* 154 = drum 26*/ "highq", /* 155 = drum 27*/ "slap", /* 156 = drum 28*/ "scratch1", /* 157 = drum 29*/ "scratch2", /* 158 = drum 30*/ "sticks", /* 159 = drum 31*/ "sqrclick", /* 160 = drum 32*/ "metclick", /* 161 = drum 33*/ "metbell", /* 162 = drum 34*/ "kick1", /* 163 = drum 35*/ "kick2", /* 164 = drum 36*/ "stickrim", /* 165 = drum 37*/ "snare1", /* 166 = drum 38*/ "claps", /* 167 = drum 39*/ "snare2", /* 168 = drum 40*/ "tomlo2", /* 169 = drum 41*/ "hihatcl", /* 170 = drum 42*/ "tomlo1", /* 171 = drum 43*/ "hihatpd", /* 172 = drum 44*/ "tommid2", /* 173 = drum 45*/ "hihatop", /* 174 = drum 46*/ "tommid1", /* 175 = drum 47*/ "tomhi2", /* 176 = drum 48*/ "cymcrsh1", /* 177 = drum 49*/ "tomhi1", /* 178 = drum 50*/ "cymride1", /* 179 = drum 51*/ "cymchina", /* 180 = drum 52*/ "cymbell", /* 181 = drum 53*/ "tamborin", /* 182 = drum 54*/ "cymsplsh", /* 183 = drum 55*/ "cowbell", /* 184 = drum 56*/ "cymcrsh2", /* 185 = drum 57*/ "vibslap", /* 186 = drum 58*/ "cymride2", /* 187 = drum 59*/ "bongohi", /* 188 = drum 60*/ "bongolo", /* 189 = drum 61*/ "congahi1", /* 190 = drum 62*/ "congahi2", /* 191 = drum 63*/ "congalo", /* 192 = drum 64*/ "timbaleh", /* 193 = drum 65*/ "timbalel", /* 194 = drum 66*/ "agogohi", /* 195 = drum 67*/ "agogolo", /* 196 = drum 68*/ "cabasa", /* 197 = drum 69*/ "maracas", /* 198 = drum 70*/ "whistle1", /* 199 = drum 71*/ "whistle2", /* 200 = drum 72*/ "guiro1", /* 201 = drum 73*/ "guiro2", /* 202 = drum 74*/ "clave", /* 203 = drum 75*/ "woodblk1", /* 204 = drum 76*/ "woodblk2", /* 205 = drum 77*/ "cuica1", /* 206 = drum 78*/ "cuica2", /* 207 = drum 79*/ "triangl1", /* 208 = drum 80*/ "triangl2", /* 209 = drum 81*/ "shaker", /* 210 = drum 82*/ "jingles", /* 211 = drum 83*/ "belltree", /* 212 = drum 84*/ "castinet", /* 213 = drum 85*/ "surdo1", /* 214 = drum 86*/ "surdo2", /* 215 = drum 87*/ "", /* 216 = drum 88*/ "", /* 217 = drum 89*/ "", /* 218 = drum 90*/ "", /* 219 = drum 91*/ "", /* 220 = drum 92*/ "", /* 221 = drum 93*/ "", /* 222 = drum 94*/ "", /* 223 = drum 95*/ "", /* 224 = drum 96*/ "", /* 225 = drum 97*/ "", /* 226 = drum 98*/ "", /* 227 = drum 99*/ "", /* 228 = drum 100*/ "", /* 229 = drum 101*/ "", /* 230 = drum 102*/ "", /* 231 = drum 103*/ "", /* 232 = drum 104*/ "", /* 233 = drum 105*/ "", /* 234 = drum 106*/ "", /* 235 = drum 107*/ "", /* 236 = drum 108*/ "", /* 237 = drum 109*/ "", /* 238 = drum 110*/ "", /* 239 = drum 111*/ "", /* 240 = drum 112*/ "", /* 241 = drum 113*/ "", /* 242 = drum 114*/ "", /* 243 = drum 115*/ "", /* 244 = drum 116*/ "", /* 245 = drum 117*/ "", /* 246 = drum 118*/ "", /* 247 = drum 119*/ "", /* 248 = drum 120*/ "", /* 249 = drum 121*/ "", /* 250 = drum 122*/ "", /* 251 = drum 123*/ "", /* 252 = drum 124*/ "", /* 253 = drum 125*/ "", /* 254 = drum 126*/ "" /* 255 = drum 127*/ }; } #endif /****************************************************************************** * VoiceManager class *****************************************************************************/ VoiceManager::VoiceManager(int noVoices) : noVoices(noVoices) { voices = new Voice*[noVoices]; for (int n = 0; n < noVoices; ++n) { voices[n] = new Voice(n); unusedVoices.push_back(voices[n]); } } VoiceManager::~VoiceManager() { for (int n = 0; n < noVoices; ++n) { delete voices[n]; } delete [] voices; } int VoiceManager::allocate(int channel, int note) { Voice *voice = 0; if (unusedVoices.size()) { voice = *(unusedVoices.begin()); unusedVoices.remove(voice); } else { voice = *(usedVoices.begin()); usedVoices.remove(voice); } voice->channel = channel; voice->note = note; voice->used = true; usedVoices.push_back(voice); return voice->id; } void VoiceManager::deallocate(int id) { Voice *voice = voices[id]; if (!voice->used) return; voice->used = false; usedVoices.remove(voice); unusedVoices.push_back(voice); } int VoiceManager::search(int channel, int pos) { for (int n = pos+1; n < noVoices; ++n) { if (voices[n]->used && voices[n]->channel == channel) return n; } return -1; } int VoiceManager::search(int channel, int note, int pos) { for (int n = pos+1; n < noVoices; ++n) { if (voices[n]->used && voices[n]->channel == channel && voices[n]->note == note) return n; } return -1; } /****************************************************************************** * OSSMidiScheduler_SynthDevice class *****************************************************************************/ OSSMidiScheduler_SynthDevice::OSSMidiScheduler_SynthDevice( int deviceno, synth_info &synthinfo, int seqfd, unsigned char *&_seqbuf, int &_seqbuflen, int &_seqbufptr) : deviceno(deviceno), seqfd(seqfd), synthinfo(synthinfo), _seqbuf(_seqbuf), _seqbuflen(_seqbuflen), _seqbufptr(_seqbufptr) { for (int ch = 0; ch < 16; ++ch) { _programChange[ch] = 0; _pitchBendLSB[ch] = 0; _pitchBendMSB[ch] = 0x40; _channelPressure[ch] = 127; } } OSSMidiScheduler_SynthDevice::~OSSMidiScheduler_SynthDevice() { } void OSSMidiScheduler_SynthDevice::seqbuf_dump() { #ifdef TSE3_WITH_OSS // This is canonical OSS code: after OSS macros are used to fill the // buffer defined by SEQ_DEFINEBUF (or rather, our class private version // of it) if (_seqbufptr) if (write(seqfd, _seqbuf, _seqbufptr) == -1) perror("Can't write to MIDI device"); _seqbufptr = 0; #endif } void OSSMidiScheduler_SynthDevice::seqbuf_clean() { _seqbufptr = 0; } /****************************************************************************** * OSSMidiScheduler_NULLDevice class *****************************************************************************/ OSSMidiScheduler_NULLDevice::OSSMidiScheduler_NULLDevice( int deviceno, synth_info &synthinfo, int seqfd, unsigned char *&_seqbuf, int &_seqbuflen, int &_seqbufptr) : OSSMidiScheduler_SynthDevice(deviceno, synthinfo, seqfd, _seqbuf, _seqbuflen, _seqbufptr) { } OSSMidiScheduler_NULLDevice::~OSSMidiScheduler_NULLDevice() { } void OSSMidiScheduler_NULLDevice::noteOff(int /*ch*/, int /*note*/, int /*vel*/) { } void OSSMidiScheduler_NULLDevice::noteOn(int /*ch*/, int /*note*/, int /*vel*/) { } void OSSMidiScheduler_NULLDevice::keyPressure(int /*ch*/, int /*note*/, int /*vel*/) { } void OSSMidiScheduler_NULLDevice::controlChange(int /*ch*/, int /*ctrl*/, int /*val*/) { } void OSSMidiScheduler_NULLDevice::programChange(int /*ch*/, int /*prog*/) { } void OSSMidiScheduler_NULLDevice::channelPressure(int /*ch*/, int /*vel*/) { } void OSSMidiScheduler_NULLDevice::pitchBend(int /*ch*/, int /*lsb*/, int /*msb*/) { } /****************************************************************************** * OSSMidiScheduler_FMDevice class *****************************************************************************/ OSSMidiScheduler_FMDevice::OSSMidiScheduler_FMDevice(int deviceno, synth_info &synthinfo, int seqfd, unsigned char *&_seqbuf, int &_seqbuflen, int &_seqbufptr) : OSSMidiScheduler_SynthDevice(deviceno, synthinfo, seqfd, _seqbuf, _seqbuflen, _seqbufptr), voiceman(synthinfo.nr_voices), opl(2) { #ifdef TSE3_WITH_OSS if (opl == 3) ioctl(seqfd, SNDCTL_FM_4OP_ENABLE, &deviceno); SEQ_VOLUME_MODE(deviceno, VOL_METHOD_LINEAR); for (int n = 0; n < synthinfo.nr_voices; ++n) { SEQ_CONTROL(deviceno, n, SEQ_VOLMODE, VOL_METHOD_LINEAR); // SEQ_STOP_NOTE(deviceno, n, vman->note(n), 64); } // We load every FM patch before the device is used loadPatches(); #endif } OSSMidiScheduler_FMDevice::~OSSMidiScheduler_FMDevice() { } void adjustfm(char *buf, int key) { #ifdef TSE3_WITH_OSS bool reverb = true; unsigned char pan = ((rand() % 3) + 1) << 4; if (key == FM_PATCH) { buf[39] &= 0xc0; if (buf[46] & 1) buf[38] &= 0xc0; buf[46] = (buf[46] & 0xcf) | pan; if (reverb) { unsigned val; val = buf[43] & 0x0f; if (val > 0) val--; buf[43] = (buf[43] & 0xf0) | val; } } else { int mode; if (buf[46] & 1) mode = 2; else mode = 0; if (buf[57] & 1) ++mode; buf[50] &= 0xc0; if (mode == 3) buf[49] &= 0xc0; if (mode == 1) buf[39] &= 0xc0; if (mode == 2 || mode == 3) buf[38] &= 0xc0; buf[46] = (buf[46] & 0xcf) | pan; buf[57] = (buf[57] & 0xcf) | pan; if (mode == 1 && reverb) { unsigned val; val = buf[43] & 0x0f; if (val > 0) val--; buf[43] = (buf[43] & 0xf0) | val; val = buf[54] & 0x0f; if (val > 0) val--; buf[54] = (buf[54] & 0xf0) | val; } } #else buf = buf; key = key; #endif } void OSSMidiScheduler_FMDevice::loadPatches() { #ifdef TSE3_WITH_OSS if (0) std::cerr << "FM: Loading patches\n"; for (int n = 0; n < 256; ++n) patchLoaded[n] = false; if (0) std::cerr << "opl is " << opl << "\n"; /************************************************************************** * Normal voice patches *************************************************************************/ // Find the patches file std::string leaf; size_t size; if (opl == 3) { leaf = "std.o3"; size = 60; } else { leaf = "std.sb"; size = 52; } FILE *f = findFileInPaths(leaf, _patchesDirectory); if (!f) { std::cerr << "Opening FM patch file failed\n"; return; } // Load the patches file if (0) std::cerr << "Success: loading patches \n"; char tmp[60]; sbi_instrument instr; for (int n = 0; n < 128; ++n) { if (fread(tmp, 1, size, f) != size) { std::cerr << "TSE3: (OSS) FM patch load error (" << n << ")\n"; } patchLoaded[n] = true; if (0) std::cerr << "[" << n << "] " ; instr.key = (strncmp(tmp, "4OP", 3) == 0) ? OPL3_PATCH : FM_PATCH; int datasize = (strncmp(tmp, "4OP", 3) == 0) ? 22 : 11; instr.device = deviceno; instr.channel = n; //tmp[46] = (tmp[46] & 0xcf) | ((++stereoeffect)<<4); // stereo //steroeffect=stereoeffect%3; adjustfm(tmp, instr.key); for (int j = 0; j < 32; ++j) { instr.operators[j] = (j < datasize) ? tmp[j+36] : 0; } SEQ_WRPATCH(&instr,sizeof(instr)); } if (0) std::cerr << "\n"; fclose(f); /************************************************************************** * Drum patches *************************************************************************/ // Find the patches file if (opl == 3) { leaf = "drums.o3"; } else { leaf = "drums.sb"; } f = findFileInPaths(leaf, _patchesDirectory); if (!f) { std::cerr << "Opening FM patch file failed\n"; return; } // Load the patches file if (0) std::cerr << "Success\n"; for (int n = 128; n < 256; ++n) { if (0) std::cerr << "[" << n << "] " ; if (fread(tmp, 1, size, f) != size) { std::cerr << "TSE3: (OSS) FM drum patch load error (" << n << ")\n"; } patchLoaded[n] = true; instr.key = (strncmp(tmp, "4OP", 3) == 0) ? OPL3_PATCH : FM_PATCH; int datasize = (strncmp(tmp, "4OP", 3) == 0) ? 22 : 11; instr.device = deviceno; instr.channel = n; // stereo effect same as before if you want it adjustfm(tmp, instr.key); for (int j = 0; j < 32; ++j) { instr.operators[j] = (j < datasize) ? tmp[j+36] : 0; } SEQ_WRPATCH(&instr, sizeof(instr)); } if (0) std::cerr << "\n"; fclose(f); #endif } std::string OSSMidiScheduler_FMDevice::_patchesDirectory = DEF_PATH; void OSSMidiScheduler_FMDevice::setPatchesDirectory(const std::string &dir) { if (0) std::cerr << "FM: Setting patches dir to " << dir << "\n"; _patchesDirectory = dir; } int OSSMidiScheduler_FMDevice::getPatch(int patchNo) { if (patchLoaded[patchNo]) return patchNo; patchNo = (patchNo < 128) ? 0 : 128; while (patchNo < 256 && !patchLoaded[patchNo]) { ++patchNo; } return patchNo; } void OSSMidiScheduler_FMDevice::noteOff(int ch, int note, int vel) { #ifdef TSE3_WITH_OSS if (0) std::cerr << "FM_noteOff (" << deviceno << "," << ch << ": " << note << "," << vel << ") "; int n = -1; while ((n = voiceman.search(ch, note, n)) != -1) { SEQ_STOP_NOTE(deviceno, n, note, vel); voiceman.deallocate(n); } #else ch = ch; note = note; vel = vel; #endif } void OSSMidiScheduler_FMDevice::noteOn(int ch, int note, int vel) { #ifdef TSE3_WITH_OSS if (0) std::cerr << "FM_noteOn (" << deviceno << "," << ch << ": " << note << "," << vel << ") "; if (vel == 0) { noteOff(ch, note, vel); return; } if ((ch == 9 && !patchLoaded[note+128]) || !patchLoaded[_programChange[ch]]) { if (0) std::cerr << "no patch loaded - I'll use the nearest\n"; //return; } int voice = voiceman.allocate(ch, note); if (ch == 9) { SEQ_SET_PATCH(deviceno, voice, getPatch(note+128)); if (note+128 < 175) return; } else { SEQ_SET_PATCH(deviceno, voice, getPatch(_programChange[ch])); } SEQ_BENDER(deviceno, voice, (_pitchBendLSB[ch]&0x7f)|(_pitchBendMSB[ch]<<7)); SEQ_START_NOTE(deviceno, voice, note, vel); SEQ_CHN_PRESSURE(deviceno, voice, _channelPressure[ch]); // pan #else ch = ch; note = note; vel = vel; #endif } void OSSMidiScheduler_FMDevice::keyPressure(int ch, int note, int vel) { #ifdef TSE3_WITH_OSS if (ch == 9) return; // don't do this for percussion XXX WHY NOT??? int n = -1; while ((n = voiceman.search(ch, note, n)) != -1) { SEQ_KEY_PRESSURE(deviceno, n, note, vel); } #else ch = ch; note = note; vel = vel; #endif } void OSSMidiScheduler_FMDevice::controlChange(int /*ch*/, int /*ctrl*/, int /*val*/) { // TODO } void OSSMidiScheduler_FMDevice::programChange(int ch, int prog) { if (0) std::cerr << "FM_programChange: (" << deviceno << "," << ch << ": " << prog << ")\n"; _programChange[ch] = prog; } void OSSMidiScheduler_FMDevice::channelPressure(int ch, int vel) { #ifdef TSE3_WITH_OSS _channelPressure[ch] = vel; int n = -1; while ((n = voiceman.search(ch, n)) != -1) { SEQ_CHN_PRESSURE(deviceno, n, vel); } #else ch = ch; vel = vel; #endif } void OSSMidiScheduler_FMDevice::pitchBend(int ch, int lsb, int msb) { #ifdef TSE3_WITH_OSS _pitchBendLSB[ch] = lsb; _pitchBendMSB[ch] = msb; int n = -1; while ((n = voiceman.search(ch, n)) != -1) { SEQ_BENDER(deviceno, n, (lsb&0x7f)|(msb<<7)); } #else ch = ch; lsb = lsb; msb = msb; #endif } /****************************************************************************** * OSSMidiScheduler_AWEDevice class *****************************************************************************/ OSSMidiScheduler_AWEDevice::OSSMidiScheduler_AWEDevice( int deviceno, synth_info &synthinfo, int seqfd, unsigned char *&_seqbuf, int &_seqbuflen, int &_seqbufptr) : OSSMidiScheduler_SynthDevice(deviceno, synthinfo, seqfd, _seqbuf, _seqbuflen, _seqbufptr) { #ifdef TSE3_WITH_OSS // Happily, if you switch -pedantic on in gcc these macros will always // throw up warnings. Marvel at the beauty of awe_voice.h for reasons why. AWE_SET_CHANNEL_MODE(deviceno, AWE_PLAY_MULTI); AWE_SET_CHANNEL_MODE(deviceno, 1); AWE_DRUM_CHANNELS(deviceno, 1<<9); AWE_TERMINATE_ALL(deviceno); seqbuf_dump(); #endif } OSSMidiScheduler_AWEDevice::~OSSMidiScheduler_AWEDevice() { } void OSSMidiScheduler_AWEDevice::noteOff(int ch, int note, int vel) { #ifdef TSE3_WITH_OSS SEQ_STOP_NOTE(deviceno, ch, note, vel); #else ch = ch; note = note; vel = vel; #endif } void OSSMidiScheduler_AWEDevice::noteOn(int ch, int note, int vel) { #ifdef TSE3_WITH_OSS if (vel == 0) { SEQ_STOP_NOTE(deviceno, ch, note, vel); } else { SEQ_START_NOTE(deviceno, ch, note, vel); } #else ch = ch; note = note; vel = vel; #endif } void OSSMidiScheduler_AWEDevice::keyPressure(int ch, int note, int vel) { #ifdef TSE3_WITH_OSS SEQ_KEY_PRESSURE(deviceno, ch, note, vel); #else ch = ch; note = note; vel = vel; #endif } void OSSMidiScheduler_AWEDevice::controlChange(int ch, int ctrl, int val) { #ifdef TSE3_WITH_OSS SEQ_CONTROL(deviceno, ch, ctrl, val); #else ch = ch; ctrl = ctrl; val = val; #endif } void OSSMidiScheduler_AWEDevice::programChange(int ch, int prog) { #ifdef TSE3_WITH_OSS _programChange[ch] = prog; SEQ_SET_PATCH(deviceno, ch, prog); #else ch = ch; prog = prog; #endif } void OSSMidiScheduler_AWEDevice::channelPressure(int ch, int vel) { #ifdef TSE3_WITH_OSS _channelPressure[ch] = vel; SEQ_CHN_PRESSURE(deviceno, ch, vel); #else ch = ch; vel = vel; #endif } void OSSMidiScheduler_AWEDevice::pitchBend(int ch, int lsb, int msb) { #ifdef TSE3_WITH_OSS _pitchBendLSB[ch] = lsb; _pitchBendMSB[ch] = msb; SEQ_BENDER(deviceno, ch, (lsb&0x7f)|(msb<<7)); #else ch = ch; lsb = lsb; msb = msb; #endif } /****************************************************************************** * OSSMidiScheduler_GUSDevice class *****************************************************************************/ OSSMidiScheduler_GUSDevice::OSSMidiScheduler_GUSDevice( int deviceno, synth_info &synthinfo, int seqfd, unsigned char *&_seqbuf, int &_seqbuflen, int &_seqbufptr) : OSSMidiScheduler_SynthDevice(deviceno, synthinfo, seqfd, _seqbuf, _seqbuflen, _seqbufptr), voiceman(synthinfo.nr_voices), nobits(16), totalMemory(0) { #ifdef TSE3_WITH_OSS for (size_t n = 0; n < 256; ++n) { patchLoaded[n] = false; patchLoadedFailed[n] = false; } // Establish how much memory is available on the synth ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &deviceno); totalMemory = deviceno; ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &totalMemory); freeMemory = totalMemory; for (int n = 0; n < synthinfo.nr_voices; ++n) { SEQ_CONTROL(deviceno, n, SEQ_VOLMODE, VOL_METHOD_LINEAR); // stop notes for all channels } // Patches are loaded on demand, so we don't need to initialise them here #endif } OSSMidiScheduler_GUSDevice::~OSSMidiScheduler_GUSDevice() { } std::string OSSMidiScheduler_GUSDevice::_patchesDirectory = DEF_PATH; void OSSMidiScheduler_GUSDevice::setPatchesDirectory(const std::string &dir) { if (0) std::cerr << "GUS: Setting patches dir to " << dir << "\n"; _patchesDirectory = dir; } int OSSMidiScheduler_GUSDevice::getPatch(int patchNo) { if (patchLoaded[patchNo] || loadPatch(patchNo)) return patchNo; patchNo = (patchNo < 128) ? 0 : 128; while (patchNo < 256 && !patchLoaded[patchNo]) ++patchNo; return patchNo; } char *OSSMidiScheduler_GUSDevice::patchName(int pgm) { #ifdef TSE3_WITH_OSS if (pgm > 0 && pgm < 256) { return GUSDevice_PatchNames[pgm]; } else #else pgm = pgm; #endif { return 0; } } bool OSSMidiScheduler_GUSDevice::loadPatch(int pgm) { #ifdef TSE3_WITH_OSS if (patchLoaded[pgm]) { std::cerr << "TSE3: (OSS) Attempting to reload a patch. Oops!\n"; return false; } if (!patchName(pgm) || !(patchName(pgm)[0])) { std::cerr << "TSE3: (OSS) No GUS name for this patch. Oops!\n"; patchLoadedFailed[pgm] = true; return false; } // Find the patche file std::string leaf = std::string(patchName(pgm)) + ".pat"; FILE *f = findFileInPaths(leaf, _patchesDirectory); if (!f) std::cerr << "TSE3: (OSS) Opening GUS patch file failed\n"; if (!f) patchLoadedFailed[pgm] = true; if (!f) return false; if (0) std::cerr << "Success: loading patch \n"; // Read file unsigned char tmp[256]; if (fread(tmp, 1, 0xef, f) != 0xef) { fclose(f); std::cerr << "TSE3: (OSS) GUS file was trucated.\n"; patchLoadedFailed[pgm] = true; return false; } // Patch header pat_header header; memcpy((char *) &header, tmp, sizeof(header)); if (strncmp(header.magic, "GF1PATCH110", 12)) { fclose(f); std::cerr << "TSE3: (OSS) GUS file is corrupt\n"; patchLoadedFailed[pgm] = true; return false; } if (!strncmp(header.version, "ID#0000002", 10)) { fclose(f); std::cerr << "TSE3: (OSS) GUS file version unknown\n"; patchLoadedFailed[pgm] = true; return false; } // Load patch waves unsigned short nWaves = *(unsigned short *)&tmp[85]; size_t offset = 0xef; for (size_t i = 0; i < nWaves; ++i) { fseek(f, offset, SEEK_SET); sample_header sample; if (fread(tmp, 1, sizeof(sample), f) != sizeof(sample)) { fclose(f); std::cerr << "TSE3: (OSS) GUS file is truncated in waves\n"; patchLoadedFailed[pgm] = true; return false; } memcpy((char *) &sample, tmp, sizeof(sample)); sample.fractions = (char)tmp[7]; sample.len = get_dint(&tmp[8]); sample.loop_start = get_dint(&tmp[12]); sample.loop_end = get_dint(&tmp[16]); sample.base_freq = get_word(&tmp[20]); sample.low_note = get_dint(&tmp[22]); sample.high_note = get_dint(&tmp[26]); sample.base_note = get_dint(&tmp[30]); sample.detune = (short)get_word(&tmp[34]); sample.panning = (unsigned char) tmp[36]; memcpy(sample.envelope_rate, &tmp[37], 6); memcpy(sample.envelope_offset, &tmp[43], 6); sample.tremolo_sweep = (unsigned char) tmp[49]; sample.tremolo_rate = (unsigned char) tmp[50]; sample.tremolo_depth = (unsigned char) tmp[51]; sample.vibrato_sweep = (unsigned char) tmp[52]; sample.vibrato_rate = (unsigned char) tmp[53]; sample.vibrato_depth = (unsigned char) tmp[54]; sample.modes = (unsigned char) tmp[55]; sample.scale_frequency = (short)get_word(&tmp[56]); sample.scale_factor = get_word(&tmp[58]); offset = offset + 96; char *patch_char = new char[sizeof(patch_info)+sample.len]; patch_info *patch = reinterpret_cast(patch_char); patch->key = GUS_PATCH; patch->device_no = deviceno; patch->instr_no = pgm; patch->mode = sample.modes | WAVE_TREMOLO | WAVE_VIBRATO | WAVE_SCALE; patch->len = sample.len; patch->loop_start = sample.loop_start; patch->loop_end = sample.loop_end; patch->base_note = sample.base_note; patch->high_note = sample.high_note; patch->low_note = sample.low_note; patch->base_freq = sample.base_freq; patch->detuning = sample.detune; patch->panning = (sample.panning - 7) * 16; memcpy(patch->env_rate, sample.envelope_rate, 6); memcpy(patch->env_offset, sample.envelope_offset, 6); patch->tremolo_sweep = sample.tremolo_sweep; patch->tremolo_rate = sample.tremolo_rate; patch->tremolo_depth = sample.tremolo_depth; patch->vibrato_sweep = sample.vibrato_sweep; patch->vibrato_rate = sample.vibrato_rate; patch->vibrato_depth = sample.vibrato_depth; patch->scale_frequency = sample.scale_frequency; patch->scale_factor = sample.scale_factor; patch->volume = header.master_volume; if (fseek(f, offset, 0) == -1) { fclose(f); std::cerr << "TSE3: (OSS) GUS file seek error\n"; patchLoadedFailed[pgm] = true; return false; } if ((long)fread(patch->data, 1, sample.len, f) != sample.len) { fclose(f); std::cerr << "TSE3: (OSS) GUS truncation after waves\n"; patchLoadedFailed[pgm] = true; return false; } SEQ_WRPATCH(patch, sizeof(*patch) + sample.len); offset += sample.len; delete patch_char; } patchLoaded[pgm] = true; fclose(f); freeMemory = deviceno; ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &freeMemory); return true; #else pgm = pgm; return false; #endif } void OSSMidiScheduler_GUSDevice::noteOff(int ch, int note, int vel) { #ifdef TSE3_WITH_OSS int n = -1; while ((n = voiceman.search(ch, note, n)) != -1) { SEQ_STOP_NOTE(deviceno, n, note, vel); voiceman.deallocate(n); } #else ch = ch; note = note; vel = vel; #endif } void OSSMidiScheduler_GUSDevice::noteOn(int ch, int note, int vel) { #ifdef TSE3_WITH_OSS if (vel == 0) { noteOff(ch, note, vel); return; } if ((ch == 9 && !patchLoaded[note+128]) || !patchLoaded[_programChange[ch]]) { if (0) std::cerr << "no patch loaded - I'll use the nearest\n"; //return; } int voice = voiceman.allocate(ch, note); if (ch == 9) { SEQ_SET_PATCH(deviceno, voice, getPatch(note+128)); } else { SEQ_SET_PATCH(deviceno, voice, getPatch(_programChange[ch])); } SEQ_BENDER(deviceno, voice, (_pitchBendLSB[ch]&0x7f)|(_pitchBendMSB[ch]<<7)); SEQ_START_NOTE(deviceno, voice, note, vel); //SEQ_CONTROL(deviceno, voice, CTL_MAIN_VOLUME, something); SEQ_CHN_PRESSURE(deviceno, voice, _channelPressure[ch]); #else ch = ch; note = note; vel = vel; #endif } void OSSMidiScheduler_GUSDevice::keyPressure(int ch, int note, int vel) { #ifdef TSE3_WITH_OSS if (ch == 9) return; // don't do this for percussion XXX WHY NOT??? int n = -1; while ((n = voiceman.search(ch, note, n)) != -1) { SEQ_KEY_PRESSURE(deviceno, n, note, vel); } #else ch = ch; note = note; vel = vel; #endif } void OSSMidiScheduler_GUSDevice::controlChange(int ch, int ctrl, int val) { #ifdef TSE3_WITH_OSS int n = -1; while ((n = voiceman.search(ch, n)) != -1) { SEQ_CONTROL(deviceno, n, ctrl, val); } #else ch = ch; ctrl = ctrl; val = val; #endif } void OSSMidiScheduler_GUSDevice::programChange(int ch, int prog) { if (ch == 9) { //if (!patchLoaded[prog]) return; return; } _programChange[ch] = prog; } void OSSMidiScheduler_GUSDevice::channelPressure(int ch, int vel) { #ifdef TSE3_WITH_OSS _channelPressure[ch] = vel; int n = -1; while ((n = voiceman.search(ch, n)) != -1) { SEQ_CHN_PRESSURE(deviceno, n, vel); } #else ch = ch; vel = vel; #endif } void OSSMidiScheduler_GUSDevice::pitchBend(int ch, int lsb, int msb) { #ifdef TSE3_WITH_OSS _pitchBendLSB[ch] = lsb; _pitchBendMSB[ch] = msb; int n = -1; while ((n = voiceman.search(ch, n)) != -1) { SEQ_BENDER(deviceno, n, (lsb&0x7f)|(msb<<7)); } #else ch = ch; lsb = lsb; msb = msb; #endif } /****************************************************************************** * OSSMidiScheduler class *****************************************************************************/ OSSMidiScheduler::OSSMidiScheduler() : seqfd(-1), lastTxTime(0) { #ifdef TSE3_WITH_OSS // What SEQ_DEFINEBUF would have done _seqbuflen = 1024; _seqbuf = new unsigned char[_seqbuflen]; // XXX this must be tidied later _seqbufptr = 0; // Open /dev/sequencer and work out what we're attached to seqfd = open("/dev/sequencer", O_RDWR|O_NONBLOCK); if (seqfd == -1) { throw TSE3::MidiSchedulerError(TSE3::MidiSchedulerCreateErr); } int i = 0; if (ioctl(seqfd, SNDCTL_MIDI_PRETIME, &i) == -1) { perror("SNDCTL_MIDI_PRETIME"); } if (ioctl(seqfd, SNDCTL_SEQ_NRSYNTHS, &nosynths)) { // there is no soundcard throw TSE3::MidiSchedulerError(TSE3::MidiSchedulerCreateErr); } ioctl(seqfd, SNDCTL_SEQ_NRMIDIS, &nomidis); rate = 0; ioctl(seqfd, SNDCTL_SEQ_CTRLRATE, &rate); if (rate == -1 || rate <= 0) rate = 100; rateDivisor = 1000/rate; nodevices = nosynths + nomidis; synthinfo = new synth_info[nosynths]; midiinfo = new midi_info[nomidis]; devices = new OSSMidiScheduler_SynthDevice*[nosynths]; running = new unsigned char[nodevices]; useRunning = new bool[nodevices]; for (size_t n = 0; n < nodevices; n++) { running[n] = 0; useRunning[n] = true; } const int verbose = 0; if (verbose) std::cout << nosynths << " synth devices available:\n"; for (unsigned int n = 0; n < nosynths; ++n) { synthinfo[n].device = n; if (ioctl(seqfd, SNDCTL_SYNTH_INFO, &synthinfo[n]) != -1) { if (verbose) { std::cout << "Synth device " << n << ": " << synthinfo[n].name << "("; switch (synthinfo[n].synth_type) { case SYNTH_TYPE_FM: std::cout << "FM\n"; break; case SYNTH_TYPE_SAMPLE: std::cout << "sample\n"; break; case SYNTH_TYPE_MIDI: std::cout << "MIDI\n"; break; default: std::cout << "?\n"; break; } std::cout << "-"; switch (synthinfo[n].synth_subtype) { case FM_TYPE_ADLIB: std::cout << "Adlib"; break; case FM_TYPE_OPL3: std::cout << "OPL3"; break; case MIDI_TYPE_MPU401: std::cout << "MPU-401"; break; case SAMPLE_TYPE_GUS: std::cout << "GUS"; break; default: std::cout << "?"; break; } std::cout << ")\n"; } if (synthinfo[n].synth_type == SYNTH_TYPE_SAMPLE && synthinfo[n].synth_subtype == SAMPLE_TYPE_AWE32) { devices[n] = new OSSMidiScheduler_AWEDevice(n, synthinfo[n], seqfd, _seqbuf, _seqbuflen, _seqbufptr); if (verbose) std::cout << " -- awe type device\n"; } else if (synthinfo[n].synth_type == SYNTH_TYPE_SAMPLE && synthinfo[n].synth_subtype == SAMPLE_TYPE_GUS) { devices[n] = new OSSMidiScheduler_GUSDevice(n, synthinfo[n], seqfd, _seqbuf, _seqbuflen, _seqbufptr); if (verbose) std::cout << " -- gus type device\n"; } else if (synthinfo[n].synth_type == SYNTH_TYPE_FM )//|| synthinfo[n].synth_subtype == FM_TYPE_OPL3) { devices[n] = new OSSMidiScheduler_FMDevice(n, synthinfo[n], seqfd, _seqbuf, _seqbuflen, _seqbufptr); if (verbose) std::cout << " -- fm type device\n"; } else { devices[n] = new OSSMidiScheduler_NULLDevice(n, synthinfo[n], seqfd, _seqbuf, _seqbuflen, _seqbufptr); if (verbose) std::cout << " -- null type device\n"; } } } if (verbose) std::cout << "\n" << nomidis << " MIDI devices available:\n"; for (unsigned int n = 0; n < nomidis; ++n) { midiinfo[n].device = n; if (ioctl(seqfd, SNDCTL_MIDI_INFO, &midiinfo[n]) != -1) { if (verbose) std::cout << "MIDI device: " << n << ": " << midiinfo[n].name << "(" << midiinfo[n].dev_type << ")\n"; if (!std::strcmp(midiinfo[n].name, "AWE Midi Emu")) { useRunning[n] = false; if (verbose) std::cout << " -- this device has broken OSS running " << "status support. Disabling running status\n"; } } } // Now let the public API know about these devices for (unsigned int n = 0; n < nodevices; ++n) { addPort(n, n >= nosynths, n); // XXX isInternal correct? } ioctl(seqfd, SNDCTL_SEQ_RESET); // XXX perhaps send a panic on all devices? #else throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); #endif } OSSMidiScheduler::~OSSMidiScheduler() { // if playing, stop first! if (MidiScheduler::running()) stop(); #ifdef TSE3_WITH_OSS close(seqfd); delete [] _seqbuf; delete [] midiinfo; delete [] synthinfo; for (unsigned int n = 0; n < nosynths; ++n) delete devices[n]; delete [] devices; delete [] running; delete [] useRunning; #endif } const char *OSSMidiScheduler::impl_implementationName() const { #ifdef TSE3_WITH_OSS return "OSSMidiScheduler version 1.00"; #else return "Unsupported OSS device. Will not work!"; #endif } const char *OSSMidiScheduler::impl_portName(int port) const { #ifdef TSE3_WITH_OSS if (isSynth(port)) { return synthinfo[port].name; } else { return midiinfo[port-nosynths].name; } #else port = port; return "None"; #endif } const char *OSSMidiScheduler::impl_portType(int port) const { #ifdef TSE3_WITH_OSS if (isSynth(port)) { switch (synthinfo[port].synth_subtype) { case FM_TYPE_ADLIB: return "Adlib"; case FM_TYPE_OPL3: return "FM"; case MIDI_TYPE_MPU401: return "MPU 401"; case SAMPLE_TYPE_GUS: return "GUS"; default: return "Unknown"; } } else { return "External MIDI port"; } #else port = port; return "None"; #endif } bool OSSMidiScheduler::impl_portReadable(int port) const { #ifdef TSE3_WITH_OSS return isMidi(port); #else port = port; return false; #endif } bool OSSMidiScheduler::impl_portWriteable(int /*port*/) const { #ifdef TSE3_WITH_OSS return true; #else return false; #endif } void OSSMidiScheduler::impl_tx(MidiCommand mc) { tx(mc, true); } void OSSMidiScheduler::tx(MidiCommand mc, bool outOfBand) { #ifdef TSE3_WITH_OSS //std::cout << "Trying to output MIDI with " << MidiCommand_NoDataBytes[mc.status] << " data bytes: (" // << mc.status << ":" << mc.channel << ":" // << mc.data1 << ":" << mc.data2 << ")\n"; if (mc.port >= (int)nodevices || mc.status == MidiCommand_Invalid) return; if (isMidi(mc.port)) { // MIDI output: easy mc.port -= nosynths; unsigned char status = (mc.status<<4) + mc.channel; if (!useRunning[mc.port] || status != running[mc.port]) { SEQ_MIDIOUT(mc.port, status); running[mc.port] = status; } SEQ_MIDIOUT(mc.port, mc.data1); if (MidiCommand_NoDataBytes[mc.status] == 2) { SEQ_MIDIOUT(mc.port, mc.data2); } } else { // Soundcard (synth) output: passed on to a handler object switch (mc.status) { case MidiCommand_NoteOff: devices[mc.port]->noteOff(mc.channel, mc.data1, mc.data2); break; case MidiCommand_NoteOn: devices[mc.port]->noteOn(mc.channel, mc.data1, mc.data2); break; case MidiCommand_KeyPressure: devices[mc.port]->keyPressure(mc.channel, mc.data1, mc.data2); break; case MidiCommand_ControlChange: devices[mc.port] ->controlChange(mc.channel, mc.data1, mc.data2); break; case MidiCommand_ProgramChange: devices[mc.port]->programChange(mc.channel, mc.data1); break; case MidiCommand_ChannelPressure: devices[mc.port]->channelPressure(mc.channel, mc.data1); break; case MidiCommand_PitchBend: devices[mc.port]->pitchBend(mc.channel, mc.data1, mc.data2); break; } } if (!outOfBand) { seqbuf_dump(); } else { for (int n = 0; n < _seqbufptr; n += 4) { // What happens to the race conditions *in the driver*? // (i.e. we're half way through sending the three MIDI bytes, and // a timed event goes off sending another three in the middle of // them) ioctl(seqfd, SNDCTL_SEQ_OUTOFBAND, _seqbuf+n); } seqbuf_clean(); } #else mc = mc; outOfBand = outOfBand; #endif } void OSSMidiScheduler::impl_start(const Clock start) { lastTxTime = start; time = 0; // set tempo ??? #ifdef TSE3_WITH_OSS SEQ_START_TIMER(); seqbuf_dump(); #endif clockStarted(start); } void OSSMidiScheduler::impl_stop(Clock t) { if (t != -1) { #ifdef TSE3_WITH_OSS SEQ_WAIT_TIME(clockToMs(t)/rateDivisor); #endif } #ifdef TSE3_WITH_OSS SEQ_STOP_TIMER(); seqbuf_dump(); // *** these are probably in the wrong order if (t == -1) { //ioctl(seqfd, SNDCTL_SEQ_RESET); //ioctl(seqfd, SNDCTL_SEQ_PANIC); } //ioctl(seqfd, SNDCTL_SEQ_SYNC); #endif clockStopped(t); } void OSSMidiScheduler::impl_moveTo(const Clock moveTime, const Clock newTime) { lastTxTime = newTime; clockMoved(moveTime, newTime); } Clock OSSMidiScheduler::impl_clock() { int centi = 0; #ifdef TSE3_WITH_OSS ioctl(seqfd, SNDCTL_SEQ_GETTIME, ¢i); #endif return msToClock(centi*rateDivisor); } int OSSMidiScheduler::impl_msecs() { int centi = 0; #ifdef TSE3_WITH_OSS ioctl(seqfd, SNDCTL_SEQ_GETTIME, ¢i); #endif return centi * rateDivisor; } void OSSMidiScheduler::impl_setTempo(int newTempo, Clock changeTime) { #ifdef TSE3_WITH_OSS SEQ_SET_TEMPO(newTempo); // XXX ? is this necessary seqbuf_dump(); #endif tempoChanged(newTempo, changeTime); } void OSSMidiScheduler::readInput() { #ifdef TSE3_WITH_OSS static const int inputBufferSize = 4; // OSS input size static unsigned char inputBuffer[inputBufferSize]; // OSS input buffer static int lastStatusByte = 0x90; // running status static int noDataBytesLeft = 2; // OSS input status static int noDataBytes = 0; // OSS input status static int data[2]; // OSS input data if (input) return; while (!input) { int out = read(seqfd, &inputBuffer, inputBufferSize); if (out < 1) return; if (out != 4) { std::cerr << "TSE3: (OSS) Input was not 4 bytes from OSS input. " << "Arse.\n"; } switch (inputBuffer[0]) { case SEQ_WAIT: time = msToClock( ((inputBuffer[3]<<16) | (inputBuffer[2]<<8) | (inputBuffer[1])) * rateDivisor); break; case SEQ_ECHO: std::cerr << "TSE3: (OSS) Input SEQ_ECHO event.\n"; break; case SEQ_MIDIPUTC: if (inputBuffer[1] & 0x80) { // it was a status byte lastStatusByte = inputBuffer[1]; if (inputBuffer[1] == MidiCommand_System) { std::cerr << "TSE3: (OSS) System byte received\n"; } else { noDataBytesLeft = MidiCommand_NoDataBytes[inputBuffer[1]>>4]; noDataBytes = 0; } } else { data[noDataBytes++] = inputBuffer[1]; noDataBytesLeft--; if (!noDataBytesLeft) { command = MidiCommand(lastStatusByte >> 4, lastStatusByte & 0x0f, 0, data[0], data[1]); input = true; noDataBytesLeft = MidiCommand_NoDataBytes[lastStatusByte>>4]; noDataBytes = 0; } } break; } } #endif } bool OSSMidiScheduler::impl_eventWaiting() { readInput(); return input; } MidiEvent OSSMidiScheduler::impl_rx() { readInput(); if (!input) return MidiEvent(); MidiEvent e(command, time); input = false; return e; } void OSSMidiScheduler::impl_tx(MidiEvent e) { #ifdef TSE3_WITH_OSS if (e.time > lastTxTime) { SEQ_WAIT_TIME(clockToMs(e.time)/rateDivisor); lastTxTime = e.time; } tx(e.data, false); #else e = e; #endif } void OSSMidiScheduler::impl_txSysEx(int /*port*/, const unsigned char * /*data*/, size_t /*size*/) { // TODO XXX std::cerr << "TSE3: (OSS) OSSMidiScheduler::txSysEx not implemented\n"; } void OSSMidiScheduler::seqbuf_dump() { #ifdef TSE3_WITH_OSS // This is canonical OSS code: after OSS macros are used to fill the // buffer defined by SEQ_DEFINEBUF (or rather, our class private version // of it) if (_seqbufptr) if (write(seqfd, _seqbuf, _seqbufptr) == -1) perror("Can't write to MIDI device"); _seqbufptr = 0; #endif } void OSSMidiScheduler::seqbuf_clean() { _seqbufptr = 0; } std::string &OSSMidiScheduler::fmPatchesDirectory() { return OSSMidiScheduler_FMDevice::patchesDirectory(); } void OSSMidiScheduler::setFmPatchesDirectory(const std::string &dir) { OSSMidiScheduler_FMDevice::setPatchesDirectory(dir); } std::string &OSSMidiScheduler::gusPatchesDirectory() { return OSSMidiScheduler_GUSDevice::patchesDirectory(); } void OSSMidiScheduler::setGusPatchesDirectory(const std::string &dir) { OSSMidiScheduler_GUSDevice::setPatchesDirectory(dir); } tse3-0.3.1/src/tse3/plt/Factory.h0000644000175700001440000000572710271145620013352 00000000000000/* * @(#)plt/Unix.h 3.00 15 October 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_PLT_UNIX_H #define TSE3_PLT_UNIX_H #include "tse3/MidiScheduler.h" namespace TSE3 { /** * The Plt namespace contains classes that provide particular * platform @ref TSE3::MidiScheduler classes for different hardware * or software platforms. * * @short @ref TSE3::MidiScheduler platform implementations * @author Pete Goodliffe * @version 3.00 * @see TSE3 */ namespace Plt { /** * This is the set of Unix platform additional APIs for the * @ref MidiSchedulerFactory. * * The MidiSchedulerFactory will (depending on availablity and * compile-time options) create either: * @li An @ref OSSMidiScheduler * @li An @ref AlsaMidiScheduler * @li An @ref ArtsMidiScheduler * * @short Unix platform MidiSchedulerFactory settings * @author Pete Goodliffe * @version 1.00 */ namespace UnixMidiSchedulerFactory { /** * enum type describing a type of Unix @ref MidiScheduler * class. */ enum UnixPlatform { UnixPlatform_OSS, UnixPlatform_Alsa, UnixPlatform_Arts, UnixPlatform_Null }; /** * Returns the currently set preferred platform. * * The default is UnixPlatform_Alsa. * * @return Preferred platform * @see setPreferredPlatform */ UnixPlatform preferredPlatform(); /** * Sets the preferred platform. You will need to call * this prior to the @ref createScheduler method being * called if you require behaviour different from the default. * * The default is UnixPlatform_Alsa. * * @param p Preferred platform type * @see preferredPlatform */ void setPreferredPlatform(UnixPlatform p); /** * Returns the type of platform that has been created by the * MidiScheduler. * * The result is only valid after @ref createScheduler has been * called, and if the MidiSchedulerFactory really is a Unix * version. */ UnixPlatform createdPlatform(); } } } #endif tse3-0.3.1/src/tse3/plt/Win32.cpp0000644000175700001440000001641610271145620013175 00000000000000/* * @(#)Win32.cpp 1.00 30NocemberJuly 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ /* * NOTE: This has neither been tested or even compiled. I've just had a quick * stab at a Win32 implemetation based on some docs I've found. * In fact, it's pretty half baked ;-) */ #include "tse3/plt/Win32.h" #include "tse3/Error.h" #include "tse3/util/MulDiv.h" #include using namespace TSE3; using namespace TSE3::Plt; static char *STR_MOD_FMSYNTH = "FM synthesizer"; static char *STR_MOD_MAPPER = "MIDI mapper"; static char *STR_MOD_MIDIPORT = "MIDI hardware port"; static char *STR_MOD_SQSYNTH = "Square wave synthesizer"; static char *STR_MOD_SYNTH = "Synthesizer"; static char *STR_MOD_UNKNOWN = "Unknown MIDI device"; /****************************************************************************** * Win32 MidiSchedulerFactory class *****************************************************************************/ MidiSchedulerFactory::MidiSchedulerFactory(bool b) : _canReturnNull(b) { } MidiSchedulerFactory::~MidiSchedulerFactory() { } MidiScheduler *MidiSchedulerFactory::createScheduler() { try { Win32MidiScheduler *ms = new Win32MidiScheduler(); cout << "Created new Win32MidiScheduler seccussfully\n"; return ms; } catch (Win32MidiSchedulerException) { cout << "Failed to create a Win32MidiScheduler\n"; if (_canReturnNull) { return new NullMidiScheduler(); } else { throw; } } } /****************************************************************************** * Win32MidiScheduler class *****************************************************************************/ Win32MidiScheduler::Win32MidiScheduler() : hMidi(NULL), nMidi(0) { unsigned int nMidiIn = midiInGetNumDevs(); nMidi = midiOutGetNumDevs() + nMidiIn; hMidi = new HMIDI[nMidi]; for (unsigned int i = 0; i < nMidi; i++) { hMidi[i].in = NULL; } for (unsigned int i = 0; i < nMidi; i++) { if (i < nMidiIn) { if (midiInOpen(&(hMidi[i].in), i, 0, 0, 0) != MMSYSERR_NOERROR) throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } else { if (midiOutOpen(&(hMidi[i].out), i - nMidiIn, 0, 0, 0) != MMSYSERR_NOERROR) throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } addPort(i, false, i); } // int error = midiOutOpen(&hMidiOut, MIDI_MAPPER, 0, 0, 0); // if (error != MMSYSERR_NOERROR) // throw TSE3::MidiSchedulerError(MidiSchedulerCreateErr); } Win32MidiScheduler::~Win32MidiScheduler() { // if playing, stop first! if (running()) stop(-1); unsigned int nMidiIn = midiInGetNumDevs(); for (unsigned int i = 0; i < nMidi; i++) { if (i < nMidiIn) { midiInClose(hMidi[i].in); } else { midiOutClose(hMidi[i].out); } } } const char* Win32MidiScheduler::impl_implementationName() { return "Win32MidiScheduler version 0.00 [dev]."; } const char* Win32MidiScheduler::impl_portName(int port) const { if (port > ports()) return NULL; else if (port < midiInGetNumDevs()) { MIDIINCAPS m; midiInGetDevCaps(port, &m, sizeof(m)); return m.szPname; } else { MIDIOUTCAPS m; midiOutGetDevCaps(port - midiInGetNumDevs(), &m, sizeof(m)); return m.szPname; } } const char* Win32MidiScheduler::impl_portType(int port) const { if (port > ports()) return NULL; if (port < midiInGetNumDevs()) { return "MIDI Input Device"; } else { MIDIOUTCAPS m; midiOutGetDevCaps(port - midiInGetNumDevs(), &m, sizeof(m)); switch(m.wTechnology) { case MOD_FMSYNTH: return STR_MOD_FMSYNTH; case MOD_MAPPER: return STR_MOD_MAPPER; case MOD_MIDIPORT: return STR_MOD_MIDIPORT; case MOD_SQSYNTH: return STR_MOD_SQSYNTH; case MOD_SYNTH: return STR_MOD_SYNTH; default: return STR_MOD_UNKNOWN; } } } bool Win32MidiScheduler::impl_portReadable(int port) const { if (port < midiInGetNumDevs()) return true; else return false; } bool Win32MidiScheduler::impl_portWriteable(int port) const { return !portReadable(port); } void Win32MidiScheduler::impl_tx(MidiCommand mc) { if (mc.port < midiInGetNumDevs()) return; runMidiData(hMidi[mc.port].out, mc); // midiShortMsg((int)mc); } void Win32MidiScheduler::impl_runMidiData(HMIDIOUT o, MidiCommand mc) { union { DWORD dwData; BYTE bData[4]; } u; u.bData[0] = (mc.status<<4) + mc.channel; u.bData[1] = mc.data1; u.bData[2] = mc.data2; u.bData[3] = 0; midiOutShortMsg(o, u.dwData); } void Win32MidiScheduler::impl_start(Clock s) { if (!_running) { TIMECAPS timecaps; timeGetDevCaps(&timecaps, sizeof(timecaps)); timeBeginPeriod(10); startTime = timeGetTime(); clockStarted(s); } } void Win32MidiScheduler::impl_stop(Clock t) { if (!_running) return; if (t != -1) { restingClock = t; } else { restingClock = clock(); } timeEndPeriod(10); clockStopped(t); } void Win32MidiScheduler::impl_moveTo(Clock moveTime, Clock newTime) { clockMoved(moveTime, newTime); } Clock Win32MidiScheduler::impl_clock() { int time = timeGetTime() - startTime; return msToClock(time); } int Win32MidiScheduler::impl_msecs() { return timeGetTime() - startTime; } void Win32MidiScheduler::impl_setTempo(int newTempo, Clock changeTime) { tempoChanged(newTempo, changeTime); /* MIDIPROPTEMPO m; m.cbStruct = sizeof(m); m.dwTempo = newTempo; for (unsigned int i = 0; i < nMidiOut; i++) { midiStreamProperty(hMidiOut[i], MIDIPROP_SET | MIDIPROP_TEMPO, &m); }*/ } bool Win32MidiScheduler::impl_eventWaiting() { return false; } MidiEvent Win32MidiScheduler::impl_rx() { return MidiEvent(); } struct CallbackData { HMIDIOUT port; MidiCommand e; Win32MidiScheduler* sch; }; void Win32MidiScheduler::impl_callback(UINT uID, UINT uMsg, DWORD _data, DWORD dw1, DWORD dw2) { CallbackData *data = (CallbackData*) _data; data->sch->runMidiData(data->port, data->e); delete data; } void Win32MidiScheduler::impl_tx(MidiEvent e) { unsigned int msecs = clockToMs(e.time); if (msecs > timeGetTime()) { if ( e.data.port < midiInGetNumDevs() || e.data.port > ports()) return; CallbackData* data = new CallbackData; data->port = hMidi[e.data.port].out; data->e = e.data; data->sch = this; timeSetEvent(msecs-timeGetTime(), 10, &callback, (DWORD) data, TIME_ONESHOT); } else tx(e.data); } void Win32MidiScheduler::impl_txSysEx(int port, const unsigned char* data, size_t size) { std::cerr << "No implemented Sys Ex in Win32" << endl; } tse3-0.3.1/src/tse3/plt/RiscOS.cpp0000644000175700001440000001366610271145620013441 00000000000000/* * @(#)RiscOS.cpp 3.00 20 July 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/platform/RiscOS.h" #include "tse3/platform/midisswis.h" #include "kernel.h" using namespace TSE3; using namespace TSE3::Plt; /* * NB: * * This is all hypothetical code since I've not been able to test it on a * RISC OS platform. There isn't a decent C++ compiler, and the Acorn CFront * isn't quite good enough ;-) * * I include it here for completeness, and to exorcise the demons. * */ /****************************************************************************** * RISC OS MidiSchedulerFactory class *****************************************************************************/ MidiSchedulerFactory::MidiSchedulerFactory(bool b) { } MidiSchedulerFactory::~MidiSchedulerFactory() { } MidiScheduler *MidiSchedulerFactory::createScheduler() { return new RiscOsMidiScheduler(); } /****************************************************************************** * RiscOsMidiScheduler class *****************************************************************************/ RiscOsMidiScheduler::RiscOsMidiScheduler() { std::cout << "RiscOsMidiScheduler created (" << implementationName() << ")\n"; _swix(MIDI_Init, _IN(0) | _OUT(0), 0, &(maxPort)); for (int p = 0; p < maxPort; ++p) { addPort(p, false, p); } } RiscOsMidiScheduler::~RiscOsMidiScheduler() { std::cout << "** RiscOsMidiScheduler deleted.\n"; } const char *RiscOSMidiScheduler::impl_implementationName() const { return "RiscOsMidiScheduler version 0.00 [dev]."; } const char *NullMidiScheduler::impl_portName(int /*port*/) const { return "RISC OS MIDI port"; } const char *NullMidiScheduler::impl_portType(int /*port*/) const { return "RISC OS MIDI port"; } bool NullMidiScheduler::impl_portReadable(int /*port*/) const { return true; } bool NullMidiScheduler::impl_portWriteable(int /*port*/) const { return true; } void RiscOsMidiScheduler::impl_tx(MidiCommand mc) { std::cout << "RiscOsMidiScheduler::tx - (now): " << mc.status << " on (" << mc.channel << "," << mc.port << ") with " << mc.data1 << ", " << mc.data2 << "\n"; int command = mc.channel + (mc.status << 4) + (mc.data1 << 8) + (mc.data2 << 16) + (mc.port << 28) _swix(MIDI_TxCommand, _INR(0,1), command, 0); } void RiscOsMidiScheduler::impl_start(Clock start) { std::cout << "RiscOsMidiScheduler::start(" << start << ")\n"; // start the fast clock if (_tempo == 0) _tempo = 120; _swix(MIDI_FastClock, _INR(0,1), 2500 / _tempo, 0); // start the interface sending timing clocks then send a midi stop // so that the instrument doesn't play itself away! _swix(MIDI_TxStart, 0); _swix(MIDI_TxCommand, _INR(0,1), 0xfc, 0); clockStarted(start); } void RiscOsMidiScheduler::impl_stop(Clock stop) { std::cout << "RiscOsMidiScheduler::stopped at " << stop << "\n"; _swix(MIDI_TxStop, 0); clockStopped(stop); } void RiscOsMidiScheduler::impl_moveTo(Clock moveTime, Clock newTime) { clockMoved(moveTime, newTime); } Clock RiscOsMidiScheduler::impl_clock() { int fcval; _swix(MIDI_FastClock, _IN(0) | _OUT(1), -1, &fcval); return msToClock(fcval); } int RiscOsMidiScheduler::impl_msecs() { int fcval; _swix(MIDI_FastClock, _IN(0) | _OUT(1), -1, &fcval); return fcval; } void RiscOsMidiScheduler::impl_setTempo(int newTempo, Clock changeTime) { tempoChanged(newTempo, changeTime); } bool RiscOsMidiScheduler::impl_eventWaiting() { // find input buffer size // SHOULD THIS BE HELD IN VARIABLE? int buffer_size; _swix(MIDI_SetBufferSize, _INR(0,1) | _OUT(0), 0, 0, &buffer_size); for (int n = 0; n <= maxPort; ++n) { // find number of free bytes in input buffer int bufsize; _swix(MIDI_InqBufferSize, _IN(0) | _OUT(0), n<<1, &bufsize); // event waiting if the two aren't equal if (buffer_size != bufsize) return 1; } return 0; // all buffers empty } MidiEvent RiscOsMidiScheduler::impl_rx() { int c /*command*/, t /*time*/; _swix(MIDI_RxCommand, _IN(0) | _OUTR(0,1), -1, &c, &t); // return false if no event is pending if (c == 0) return MidiEvent(); return MidiEvent(MidiCommand((c>>4)&0xf0, c&0xf, (c>>28)&0xf, (c>>8)&0x7f, (c>>16)&0x7f), msToClock(t)); remoteControl(e); return e; } void RiscOsMidiScheduler::impl_tx(MidiEvent e) { if (e.event.data.status == MidiCommand_Invalid) return; std::cout << "RiscOsMidiScheduler::tx - " << e.event.time << ": " << e.event.data.status << " on (" << e.event.data.channel << "," << e.event.data.port << ") with " << e.event.data.data1 << ", " << e.event.data.data2 << "\n"; int command = mc.channel + (mc.status << 4) + (mc.data1 << 8) + (mc.data2 << 16) + (mc.port << 28) _swix(MIDI_TxCommand, _INR(0,1), command, clockToMs(time)); } void RiscOSMidiScheduler::impl_txSysEx(int port, const unsigned char *data, size_t size) { std::cout << "RiscOsMidiScheduler::txByte - (now) " << byte << "\n"; _swix(MIDI_TxByte, _IN(0), MidiSystem_SysExStart); // XXX port for (size_t n = 0; n < size; n++) { _swix(MIDI_TxByte, _IN(0), data[n]); } _swix(MIDI_TxByte, _IN(0), MidiSystem_SysExStop); } tse3-0.3.1/src/tse3/PhraseList.h0000644000175700001440000002057710271145624013226 00000000000000/* * @(#)PhraseList.h 3.00 14 May 1999 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_PHRASELIST_H #define TSE3_PHRASELIST_H #include "tse3/listen/PhraseList.h" #include "tse3/Notifier.h" #include "tse3/Serializable.h" #include "tse3/listen/Phrase.h" #include #include #include namespace TSE3 { /** * A list of @ref Phrases within a certain @ref Song. * * @sect Command classes * * Use the following command classes to manipute this object in a undo/redo * environment. * * @li @ref TSE3::Cmd::Phrase_Create * @li @ref TSE3::Cmd::Phrase_Erase * * @short A list of Phrases * @author Pete Goodliffe * @version 3.00 * @see Phrase * @see Song */ class PhraseList : public Notifier, public Listener, public Serializable { public: /** * The base name to use when creating a new @ref Phrase. * * @see newPhraseTitle */ static const std::string newPhraseString; /** * The base name to use when creating a new @ref Phrase that has * been imported. * * @see newPhraseTitle */ static const std::string importedString; /** * The base name to use when creating a new @ref Phrase that has * been merged into the @ref PhraseList. * * @see newPhraseTitle */ static const std::string mergedPhraseString; /** * The base name to use when creating a new @ref Phrase that has * been 'exploded' by a Phrase Utility. * * @see newPhraseTitle */ static const std::string explodedPhraseString; /** * Creates an empty PhraseList */ PhraseList(); /** * The destructor: all @ref Phrases contained in the PhraseList will * also be deleted. */ virtual ~PhraseList(); /** * Returns the number of @ref Phrases in the PhraseList. * * @return Number of @ref Phrases */ size_t size() const { return list.size(); } /** * Returns the @ref Phrase at positon n * * The value returned for an index that is out of range is * undefined. The @ref size method describes the valid * values. * * @param n Index * @return @ref Phrase at index n */ Phrase *operator[](size_t n) const { return list[n]; } /** * Returns the @ref Phrase with the given title. * * @param title Unique @ref Phrase reference title * @return Phrase with given name */ Phrase *phrase(const std::string &title) const; /** * Returns the index of the given @ref Phrase. If the @ref Phrase * is no in the PhraseList, returns the value of @ref size(). * * @param phrase @ref Phrase to search for * @return index of @ref Phraes in PhraseList, or @ref size() */ size_t index(const Phrase *phrase) const; /** * Deletes the @ref Phrase (consequently removing it from the * PhraseList). If the @ref Phrase is not in the PhraseList no * error is raised. * * It is also safe to just delete a @ref Phrase through a pointer * to it. However, that's a little 'unconventional'. * * @param phrase The @ref Phrase to delete */ void erase(Phrase *phrase); /** * Removes the @ref Phrase from the PhraseList but does not * delete it. * * Note that this leaves you with a pretty useless @ref Phrase. You * cannot use it in a @ref Part. Any @ref Part objects that were * using the @ref Phrase will reset their @ref Phrase reference. * * The only way to make the @ref Phrase useful again is to insert * it back into a PhraseList. * * Once you have removed a @ref Phrase from the PhraseList it is * no longer owned by the PhraseList, and it is your responsibility * to delete it. * * If the specified @ref Phrase is not in the @ref PhraseList then * no error is raised. * * @param phrase The @ref Phrase to remove * @see insert * @internal */ void remove(Phrase *phrase); /** * Inserts an unparented @ref Phrase back into the PhraseList. * * Throws @ref PhraseNameExists if there is already a @ref Phrase * with that name in the PhraseList. * * You cannot insert a Phrase with no title - the same exception * will be thrown. * * This causes the Phrase to be 'owned' by the PhraseList, it will * be deleted when the PhraseList is deleted. * * @param phrase The @ref Phrase to insert * @throws PhraseListError */ void insert(Phrase *phrase); /** * Returns a @ref Phrase name based on the given base string that is * guaranteed to not be used by any @ref Phrase in this PhraseList. * * If the base name already exists in the PhraseList, a unique * variant of it will be returned (by appending a number). * * @param baseName The base name string * @return A new unused Phrase name string * @see newPhraseString * @see importedString * @see mergedPhraseString * @see explodedPhraseString */ std::string newPhraseTitle (const std::string &baseName = newPhraseString); /** * @reimplemented */ virtual void Phrase_TitleAltered(Phrase *); /** * @reimplemented */ virtual void Notifier_Deleted(Phrase *); /** * @reimplemented */ virtual void save(std::ostream &o, int i) const; /** * @reimplemented * * NOTE: The PhraseList actually loads the @ref Phrase object * chunks. */ virtual void load(std::istream &i, SerializableLoadInfo &info); friend class Phrase; private: PhraseList &operator=(const PhraseList &); PhraseList(const PhraseList &); /** * Private internal part of insert, that adds the Phrase to the * @p list vector, but doesn't send any notifications. */ void insertInList(Phrase *phrase); /** * This is the only private method that the @ref Phrase * friend class calls. * * It informs the PhraseList that a @ref Phrase has changed its * name. * * @param p @ref Phrase that has changed its name */ void phraseTitleChanged(Phrase *p); /** * Used by load to load a Phrase from the Events block and * to insert it into the PhraseList */ void loadPhraseEvents(std::istream &i, int filePPQN, std::string &title); std::vector list; }; } #endif tse3-0.3.1/src/tse3/KeySigTrack.cpp0000755000175700001440000001505410302613324013650 00000000000000/* * @(#)KeySigTrack.cpp 3.00 30 May 2000 * * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "tse3/KeySigTrack.h" #include "tse3/FileBlockParser.h" #include using namespace TSE3; /****************************************************************************** * KeySigTrackIterator class *****************************************************************************/ namespace TSE3 { /** * The @ref PlayableIterator for the @ref KeySigTrack class. * * @short KeySigTrack PlayableIterator. * @author Pete Goodliffe * @version 3.00 * @see PlayableIterator * @see KeySigTrack */ class KeySigTrackIterator : public PlayableIterator, public Listener { public: KeySigTrackIterator(KeySigTrack *t, Clock m); virtual ~KeySigTrackIterator(); virtual void moveTo(Clock m); virtual void EventTrack_EventAltered(EventTrack *); virtual void EventTrack_EventInserted(EventTrack *); virtual void EventTrack_EventErased(EventTrack *); virtual void Notifier_Deleted(EventTrack *); protected: virtual void getNextEvent(); size_t _pos; KeySigTrack *_kstrack; private: KeySigTrackIterator &operator=(const KeySigTrackIterator &); KeySigTrackIterator(const KeySigTrackIterator &); }; } KeySigTrackIterator::KeySigTrackIterator(KeySigTrack *t, Clock c) : _pos(0), _kstrack(t) { moveTo(c); attachTo(_kstrack); } KeySigTrackIterator::~KeySigTrackIterator() { } void KeySigTrackIterator::moveTo(Clock c) { if (_kstrack) _pos = _kstrack->index(c); if (!_kstrack || _pos == _kstrack->size() || !_kstrack->status()) { _more = false; _next = MidiEvent(); } else { _more = true; _next = MidiEvent(MidiCommand(MidiCommand_TSE_Meta, 0, 0, MidiCommand_TSE_Meta_KeySig, ((*_kstrack)[_pos].data.incidentals << 4) | (*_kstrack)[_pos].data.type), (*_kstrack)[_pos].time); } } void KeySigTrackIterator::getNextEvent() { ++_pos; if (_pos == _kstrack->size()) { _more = false; _next = MidiEvent(); } else { _more = true; _next = MidiEvent(MidiCommand(MidiCommand_TSE_Meta, 0, 0, MidiCommand_TSE_Meta_KeySig, ((*_kstrack)[_pos].data.incidentals << 4) | (*_kstrack)[_pos].data.type), (*_kstrack)[_pos].time); } } void KeySigTrackIterator::EventTrack_EventAltered(EventTrack *) { moveTo(_next.time); } void KeySigTrackIterator::EventTrack_EventInserted(EventTrack *) { moveTo(_next.time); } void KeySigTrackIterator::EventTrack_EventErased(EventTrack *) { moveTo(_next.time); } void KeySigTrackIterator::Notifier_Deleted(EventTrack *) { _kstrack = 0; _more = false; _next = MidiEvent(); } /****************************************************************************** * KeySigTrack class *****************************************************************************/ KeySigTrack::KeySigTrack() : _status(true) { insert(Event(KeySig(), 0)); } KeySigTrack::~KeySigTrack() { } PlayableIterator *KeySigTrack::iterator(Clock index) { return new KeySigTrackIterator(this, index); } Clock KeySigTrack::lastClock() const { return (!data.empty()) ? data[size()-1].time : Clock(0); } /****************************************************************************** * KeySigTrack Serializable interface *****************************************************************************/ void KeySigTrack::save(std::ostream &o, int i) const { o << indent(i) << "{\n"; o << indent(i+1) << "Status:"; if (_status) o << "On\n"; else o << "Off\n"; o << indent(i+1) << "Events\n"; o << indent(i+1) << "{\n"; for (size_t n = 0; n < size(); ++n) { o << indent(i+2) << data[n].time << ":" << data[n].data.incidentals << "/" << data[n].data.type << "\n"; } o << indent(i+1) << "}\n"; o << indent(i) << "}\n"; } namespace { /** * A catch-all FileItemParser to handle data items in the KeySigTrack * Events sub-block. */ class FileItemParser_Events : public FileItemParser { public: FileItemParser_Events(KeySigTrack *kst, int PPQN) : kst(kst), PPQN(PPQN) {} virtual void parse(const std::string &line) { int time, incidentals, type; std::istringstream si(line); si >> time; si.ignore(1); // skip colon si >> incidentals; si.ignore(1); // skip slash si >> type; time = Clock::convert(time, PPQN); kst->insert(Event(KeySig(incidentals, type), time)); } private: KeySigTrack *kst; int PPQN; }; /** * A simple Serializable class that creates a simple FileBlockParser * to load the Events sub-block of the KeySigTrack block. */ class Events : public Serializable { public: Events(KeySigTrack *kst) : kst(kst) {} virtual void load(std::istream &in, SerializableLoadInfo &info) { FileItemParser_Events events(kst, info.PPQN); FileBlockParser parser; parser.add(&events); parser.parse(in, info); } private: KeySigTrack *kst; }; } void KeySigTrack::load(std::istream &in, SerializableLoadInfo &info) { FileItemParser_OnOff status(this, &KeySigTrack::setStatus); Events events(this); FileBlockParser parser; parser.add("Status", &status); parser.add("Events", &events); parser.parse(in, info); } tse3-0.3.1/src/tse3/file/0000777000175700017570000000000010310240002011756 500000000000000tse3-0.3.1/src/tse3/file/KeySigTrack.cpp0000644000175700001440000000112310302613313014552 00000000000000 #include "tse3/file/Write.h" #include "tse3/file/XML.h" #include "tse3/KeySigTrack.h" #include void TSE3::File::write(XmlFileWriter &writer, TSE3::KeySigTrack &kst) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "KeySigTrack"); writer.element("Status", kst.status()); TSE3::File::XmlFileWriter::AutoElement ae2(writer, "Events"); for (size_t n = 0; n < kst.size(); ++n) { std::ostringstream ev; ev << kst[n].time << ":" << kst[n].data.incidentals << "/" << kst[n].data.type; writer.element("Event", ev.str()); } } tse3-0.3.1/src/tse3/file/Part.cpp0000644000175700001440000000114010302613370013302 00000000000000 #include "tse3/file/Write.h" #include "tse3/file/XML.h" #include "tse3/Part.h" #include "tse3/Phrase.h" void TSE3::File::write(XmlFileWriter &writer, TSE3::Part &p) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "Part"); write(writer, *p.filter()); write(writer, *p.params()); write(writer, *p.displayParams()); if (p.phrase()) { writer.element("Phrase", p.phrase()->title()); } else { writer.element("Phrase", ""); } writer.element("Start", p.start()); writer.element("End", p.end()); writer.element("Repeat", p.repeat()); } tse3-0.3.1/src/tse3/file/XML.h0000644000175700001440000003161010302614241012504 00000000000000/* * @(#)file/XML.h 3.00 10 Aug 2001 * * Copyright (c) 2001 Pete Goodliffe (pete@cthree.org) * * This file is part of TSE3 - the Trax Sequencer Engine version 3.00. * * This library is modifiable/redistributable under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef TSE3_FILE_XML_H #define TSE3_FILE_XML_H #include #include #include #include #include #include #include "tse3/Midi.h" namespace TSE3 { class Song; class Progress; namespace File { /** * Data structure used by the @ref Serializable class during loading. * It contains information that has been gained about the file, mostly * from the "Header" chunk. Most @ref Serializable classes will not need * to write to this struct, but will almost certainly need to read it * (at least to convert local file PPQN resolution to TSE3 system PPQN). */ struct XmlLoadInfo { /** * The PPQN resolution of timestamps in this file. You can use * this to convert timestamps to the correct values in use in the * TSE3 library. See @ref Clock's convert() method. * This information is read from the file's "Header" chunk. */ int PPQN; /** * The current Song. This is set once by the @ref TSE3MDL class. * You may not write over this value afterwards or you will * create undefined behaviour. */ Song *song; /** * The files's najor version number, read from it's "Header" chunk. * This should be informational since the TSE3MDL file format is * forwards and backwards compatible. * * The (invalid) value -1 means that no major version has been read. */ int major; /** * The file's minor version number, read from it's "Header" chunk. * This should be informational since the TSE3MDL file format is * forwards and backwards compatible. * * The (invalid) value -1 means that no minor version has been read. */ int minor; /** * A boolean flag which reports whether the loading encountered * any unknown chunks (which will have been skipped over). * * If you are not using the @ref FileBlockParser class to perform * parsing, you must set this flag to true if you come across any * unrecognised chunks. The @ref FileBlockParser class does this * automatically. */ bool unknownChunks; /** * A boolean flag which reports whether the loading encountered * any unknown data lines (which will have been ignored). * * If you are not using the @ref FileBlockParser class to perform * parsing, you must set this flag to true if you come across any * unrecognised data lines. The @ref FileBlockParser class does this * automatically. */ bool unknownData; /** * A counter which reports how many chunks (and sub-chunks) were * in the file. * * If you are not using the @ref FileBlockParser class to perform * parsing, you must increment this counter if you come across a new * chunk. The @ref FileBlockParser class does this automatically. */ size_t noChunks; /** * If the operation that triggered this serializable operation * provided a @ref Progress callback object, this points to it. * * This information is used by the @ref FileBlockParser utility. * You do not need to handle this in client code. */ Progress *progress; /** * Sets up some default values for the struct values. * * These are: * @li PPQN - @ref Clock::PPQN * @li song - 0 * @li major - -1 * @li minor - -1 * @li unknownChunks - false * @li unknownData - false * @li progress - 0 */ XmlLoadInfo(); }; /********************************************************************** * Writing XML files *********************************************************************/ /** * A utility class to make writing XML files easier. */ class XmlFileWriter { public: XmlFileWriter(std::ostream &out); ~XmlFileWriter(); void openElement(const std::string &name); void closeElement(); void element(const std::string &name, const std::string &value); void element(const std::string &name, const char *value); void element(const std::string &name, int value); void element(const std::string &name, unsigned int value); void element(const std::string &name, bool value); void comment(const std::string &comment); class AutoElement { public: AutoElement(TSE3::File::XmlFileWriter &writer, const std::string &name) : _writer(writer) { _writer.openElement(name); } ~AutoElement() { _writer.closeElement(); } private: TSE3::File::XmlFileWriter &_writer; }; private: void indent(std::ostream &out); std::ostream &out; int indentLevel; class XmlFileWriterImpl *pimpl; }; /** * A utility class to make reading TSE3MDL files easier. */ class XmlFileReader { public: XmlFileReader(std::istream &in); ~XmlFileReader(); TSE3::Song *load(); private: std::istream ∈ }; /********************************************************************** * Reading XML files *********************************************************************/ class XmlElementParser; class XmlBlockParser { public: typedef void (block_handler_t)(); XmlBlockParser(); void add(const std::string &tag, XmlBlockParser &handler); void add(const std::string &tag, XmlElementParser &handler); void add(XmlElementParser &handler); void parse(std::istream &in, const std::string &tag, XmlLoadInfo &info); private: void skipBlock(std::istream &in); std::map elements; std::map blocks; XmlElementParser *catchAll; }; class XmlElementParser { public: XmlElementParser() {} virtual ~XmlElementParser() = 0; /** * This method is called by the @ref XmlBlockParser when it * finds a data line that is handled by this XmlElementParser. * * @param data The data from the "value" attribute to be * handled. */ virtual void parse(const std::string &data) = 0; private: XmlElementParser &operator=(const XmlElementParser &); XmlElementParser(const XmlElementParser &); }; /** * A TSE3 utility class. * * A utility class implementing a specific type of @ref XmlElementParser. * This class will call a member function with signature * void setXXX(reason r, bool) with the boolean value of the data string. * * @short Internal utility for parsing boolean values with reason codes * @short Internal utility for parsing numeric data lines * @author Pete Goodliffe * @version 1.00 */ template class XmlElementParser_ReasonOnOff : public XmlElementParser { public: typedef void (T::*fn_t)(reason, bool); XmlElementParser_ReasonOnOff(T *obj, fn_t mfun, reason r) : obj(obj), r(r) , mfun(mfun){} /** * @reimplemented */ void parse(const std::string &data) { (obj->*mfun)(r, (data == "On" || data == "Yes")); } private: T *obj; reason r; fn_t mfun; }; /** * A TSE3 utility class. * * A utility class implementing a specific type of @ref XmlElementParser. * This class will call a member function with signature void setXXX(int) * with the numeric value of the data string in a similar manner to * XmlElementParser_OnOff. * * @short Internal utility for parsing numeric data lines * @author Pete Goodliffe * @version 1.00 */ template class XmlElementParser_Number : public XmlElementParser { public: typedef void (T::*fn_t)(int); XmlElementParser_Number(T *obj, fn_t mfun) : obj(obj), mfun(mfun) {} /** * @reimplemented */ void parse(const std::string &data) { int i; std::istringstream si(data); si >> i; (obj->*mfun)(i); } private: T *obj; fn_t mfun; }; /** * A TSE3 utility class. * * A utility class implementing a specific type of @ref XmlElementParser. * This class will call a member function with signature * void setXXX(Clock) with the numeric value of the data string in * a similar manner to XmlElementParser_OnOff. * * This XmlElementParser looks partically identical to the _Number version. * * @short Internal utility for parsing @ref Clock data lines * @author Pete Goodliffe * @version 1.00 */ template class XmlElementParser_Clock : public XmlElementParser { public: typedef void (T::*fn_t)(Clock); XmlElementParser_Clock(T *obj, fn_t mfun) : obj(obj), mfun(mfun) {} /** * @reimplemented */ void parse(const std::string &data) { int i; std::istringstream si(data); si >> i; (obj->*mfun)(i); } private: T *obj; fn_t mfun; }; /** * A TSE3 utility class. * * A utility class implementing a specific type of @ref XmlElementParser. * This class will call a member function with signature * void setXXX(const string &) with the string in the data string. * * @short Internal utility for parsing string data lines * @author Pete Goodliffe * @version 1.00 */ template class XmlElementParser_String : public XmlElementParser { public: typedef void (T::*fn_t)(const std::string &); XmlElementParser_String(T *obj, fn_t mfun) : obj(obj), mfun(mfun) {} /** * @reimplemented */ void parse(const std::string &data) { (obj->*mfun)(data); } private: T *obj; fn_t mfun; }; } } #endif tse3-0.3.1/src/tse3/file/TempoTrack.cpp0000644000175700001440000000110610302614455014454 00000000000000 #include "tse3/file/Write.h" #include "tse3/file/XML.h" #include "tse3/TempoTrack.h" #include void TSE3::File::write(XmlFileWriter &writer, TSE3::TempoTrack &tt) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "TempoTrack"); writer.element("Status", tt.status()); TSE3::File::XmlFileWriter::AutoElement ae2(writer, "Events"); for (size_t n = 0; n < tt.size(); ++n) { // This will be a stringstream std::ostringstream ev; ev << tt[n].time << ":" << tt[n].data.tempo; writer.element("Event", ev.str()); } } tse3-0.3.1/src/tse3/file/PhraseList.cpp0000644000175700001440000000253210302616405014462 00000000000000 #include "tse3/file/Write.h" #include "tse3/file/XML.h" #include "tse3/PhraseList.h" #include "tse3/Phrase.h" #include void TSE3::File::write(XmlFileWriter &writer, TSE3::PhraseList &pl) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "PhraseList"); for (size_t n = 0; n < pl.size(); ++n) { write(writer, *pl[n]); } } void TSE3::File::write(XmlFileWriter &writer, TSE3::Phrase &p) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "Phrase"); writer.element("Title", p.title()); write(writer, *p.displayParams()); TSE3::File::XmlFileWriter::AutoElement ae2(writer, "Events"); for (size_t n = 0; n < p.size(); ++n) { // This will be a stringstream std::ostringstream ev; ev << p[n].time << ":" << p[n].data.status << "/" << p[n].data.data1 << "/" << p[n].data.data2 << "/" << p[n].data.channel << "/" << p[n].data.port; if (p[n].data.status == MidiCommand_NoteOn) { ev << "-" << p[n].offTime << ":" << p[n].offData.status << "/" << p[n].offData.data1 << "/" << p[n].offData.data2 << "/" << p[n].offData.channel << "/" << p[n].offData.port; } writer.element("Event", ev.str()); } } tse3-0.3.1/src/tse3/file/FlagTrack.cpp0000644000175700001440000000103110302614322014227 00000000000000 #include "tse3/file/Write.h" #include "tse3/file/XML.h" #include "tse3/FlagTrack.h" #include void TSE3::File::write(XmlFileWriter &writer, TSE3::FlagTrack &ft) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "FlagTrack"); TSE3::File::XmlFileWriter::AutoElement ae2(writer, "Events"); for (size_t n = 0; n < ft.size(); ++n) { // This will be a stringstream std::ostringstream ev; ev << ft[n].time << ":" << ft[n].data.title(); writer.element("Event", ev.str()); } } tse3-0.3.1/src/tse3/file/Write.h0000644000175700001440000000250710271145601013145 00000000000000 #ifndef TSE3_FILE_SONG_H #define TSE3_FILE_SONG_H namespace TSE3 { class Song; class TempoTrack; class TimeSigTrack; class KeySigTrack; class FlagTrack; class PhraseList; class Phrase; class DisplayParams; class Track; class MidiFilter; class MidiParams; class Part; namespace File { class XmlFileWriter; void writeSong(XmlFileWriter &writer, TSE3::Song &song); void write(XmlFileWriter &writer, TSE3::Song &song); void write(XmlFileWriter &writer, TSE3::TempoTrack &tempoTrack); void write(XmlFileWriter &writer, TSE3::TimeSigTrack &timeSigTrack); void write(XmlFileWriter &writer, TSE3::KeySigTrack &keySigTrack); void write(XmlFileWriter &writer, TSE3::FlagTrack &flagTrack); void write(XmlFileWriter &writer, TSE3::PhraseList &phraseList); void write(XmlFileWriter &writer, TSE3::Phrase &phrase); void write(XmlFileWriter &writer, TSE3::DisplayParams &displayParams); void write(XmlFileWriter &writer, TSE3::Track &track); void write(XmlFileWriter &writer, TSE3::MidiFilter &midiFilter); void write(XmlFileWriter &writer, TSE3::MidiParams &midiParams); void write(XmlFileWriter &writer, TSE3::Part &part); } } #endif tse3-0.3.1/src/tse3/file/DisplayParams.cpp0000644000175700001440000000130110302614302015140 00000000000000 #include "tse3/file/Write.h" #include "tse3/file/XML.h" #include "tse3/DisplayParams.h" #include void TSE3::File::write(XmlFileWriter &writer, TSE3::DisplayParams &dp) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "DisplayParams"); writer.element("Style", dp.style()); { // This will be a stringstream std::ostringstream ev; int r, g, b; dp.colour(r, g, b); ev << r << "," << g << "," << b; writer.element("Colour", ev.str()); } if (dp.style() == TSE3::DisplayParams::PresetColour) { writer.element("Preset", TSE3::DisplayParams::presetColourString(dp.presetColour())); } } tse3-0.3.1/src/tse3/file/Makefile.am0000644000175700001440000000060010271145601013726 00000000000000tse3fileh_HEADERS = XML.h Write.h tse3filehdir = $(pkgincludedir)/file noinst_LTLIBRARIES = libtse3file.la libtse3file_la_SOURCES = DisplayParams.cpp FlagTrack.cpp KeySigTrack.cpp MidiFilter.cpp MidiParams.cpp Part.cpp PhraseList.cpp Song.cpp TempoTrack.cpp TimeSigTrack.cpp Track.cpp Write.cpp XML.cpp DISTCLEANFILES = ./.deps/* ./.deps/.P INCLUDES = -I$(top_srcdir)/src tse3-0.3.1/src/tse3/file/Makefile.in0000644000175700017570000004122110302622112013746 00000000000000# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ SOURCES = $(libtse3file_la_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/tse3/file DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(tse3fileh_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libtse3file_la_LIBADD = am_libtse3file_la_OBJECTS = DisplayParams.lo FlagTrack.lo \ KeySigTrack.lo MidiFilter.lo MidiParams.lo Part.lo \ PhraseList.lo Song.lo TempoTrack.lo TimeSigTrack.lo Track.lo \ Write.lo XML.lo libtse3file_la_OBJECTS = $(am_libtse3file_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libtse3file_la_SOURCES) DIST_SOURCES = $(libtse3file_la_SOURCES) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(tse3filehdir)" tse3filehHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(tse3fileh_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPP_MM = @CPP_MM@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ HAVE_ALSA_FALSE = @HAVE_ALSA_FALSE@ HAVE_ALSA_TRUE = @HAVE_ALSA_TRUE@ HAVE_ARTS_FALSE = @HAVE_ARTS_FALSE@ HAVE_ARTS_TRUE = @HAVE_ARTS_TRUE@ HAVE_OSS_FALSE = @HAVE_OSS_FALSE@ HAVE_OSS_TRUE = @HAVE_OSS_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTALL_TSE3_DOC_FALSE = @INSTALL_TSE3_DOC_FALSE@ INSTALL_TSE3_DOC_TRUE = @INSTALL_TSE3_DOC_TRUE@ LDFLAGS = @LDFLAGS@ LIBARTS = @LIBARTS@ LIBASOUND = @LIBASOUND@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TSE3_ALSA_PREFIX = @TSE3_ALSA_PREFIX@ TSE3_ALSA_VERSION = @TSE3_ALSA_VERSION@ TSE3_ARTS_PREFIX = @TSE3_ARTS_PREFIX@ TSE3_WITH_ALSA = @TSE3_WITH_ALSA@ TSE3_WITH_ALSA_0_5_X = @TSE3_WITH_ALSA_0_5_X@ TSE3_WITH_ALSA_0_5_X_FALSE = @TSE3_WITH_ALSA_0_5_X_FALSE@ TSE3_WITH_ALSA_0_5_X_TRUE = @TSE3_WITH_ALSA_0_5_X_TRUE@ TSE3_WITH_ALSA_0_9_X = @TSE3_WITH_ALSA_0_9_X@ TSE3_WITH_ALSA_0_9_X_FALSE = @TSE3_WITH_ALSA_0_9_X_FALSE@ TSE3_WITH_ALSA_0_9_X_TRUE = @TSE3_WITH_ALSA_0_9_X_TRUE@ TSE3_WITH_ALSA_FALSE = @TSE3_WITH_ALSA_FALSE@ TSE3_WITH_ALSA_TRUE = @TSE3_WITH_ALSA_TRUE@ TSE3_WITH_ARTS = @TSE3_WITH_ARTS@ TSE3_WITH_ARTS_FALSE = @TSE3_WITH_ARTS_FALSE@ TSE3_WITH_ARTS_TRUE = @TSE3_WITH_ARTS_TRUE@ TSE3_WITH_OSS = @TSE3_WITH_OSS@ TSE3_WITH_OSS_FALSE = @TSE3_WITH_OSS_FALSE@ TSE3_WITH_OSS_TRUE = @TSE3_WITH_OSS_TRUE@ TSE3_WITH_WIN32 = @TSE3_WITH_WIN32@ TSE3_WITH_WIN32_FALSE = @TSE3_WITH_WIN32_FALSE@ TSE3_WITH_WIN32_TRUE = @TSE3_WITH_WIN32_TRUE@ VERSION = @VERSION@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ prefix = @prefix@ program_transform_name = @program_transform_name@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ tse3fileh_HEADERS = XML.h Write.h tse3filehdir = $(pkgincludedir)/file noinst_LTLIBRARIES = libtse3file.la libtse3file_la_SOURCES = DisplayParams.cpp FlagTrack.cpp KeySigTrack.cpp MidiFilter.cpp MidiParams.cpp Part.cpp PhraseList.cpp Song.cpp TempoTrack.cpp TimeSigTrack.cpp Track.cpp Write.cpp XML.cpp DISTCLEANFILES = ./.deps/* ./.deps/.P INCLUDES = -I$(top_srcdir)/src all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tse3/file/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/tse3/file/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libtse3file.la: $(libtse3file_la_OBJECTS) $(libtse3file_la_DEPENDENCIES) $(CXXLINK) $(libtse3file_la_LDFLAGS) $(libtse3file_la_OBJECTS) $(libtse3file_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DisplayParams.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FlagTrack.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KeySigTrack.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MidiFilter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MidiParams.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Part.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PhraseList.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Song.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TempoTrack.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSigTrack.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Track.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Write.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XML.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: install-tse3filehHEADERS: $(tse3fileh_HEADERS) @$(NORMAL_INSTALL) test -z "$(tse3filehdir)" || $(mkdir_p) "$(DESTDIR)$(tse3filehdir)" @list='$(tse3fileh_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(tse3filehHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(tse3filehdir)/$$f'"; \ $(tse3filehHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(tse3filehdir)/$$f"; \ done uninstall-tse3filehHEADERS: @$(NORMAL_UNINSTALL) @list='$(tse3fileh_HEADERS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(tse3filehdir)/$$f'"; \ rm -f "$(DESTDIR)$(tse3filehdir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(tse3filehdir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-tse3filehHEADERS install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am uninstall-tse3filehHEADERS .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip install-tse3filehHEADERS installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-info-am \ uninstall-tse3filehHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: tse3-0.3.1/src/tse3/file/Track.cpp0000644000175700001440000000074410271145601013453 00000000000000 #include "tse3/file/Write.h" #include "tse3/file/XML.h" #include "tse3/Track.h" void TSE3::File::write(XmlFileWriter &writer, TSE3::Track &t) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "Track"); writer.element("Title", t.title()); write(writer, *t.filter()); write(writer, *t.params()); write(writer, *t.displayParams()); writer.element("NoParts", t.size()); for (size_t n = 0; n < t.size(); ++n) { write(writer, *t[n]); } } tse3-0.3.1/src/tse3/file/TimeSigTrack.cpp0000644000175700001440000000116710302614474014741 00000000000000 #include "tse3/file/Write.h" #include "tse3/file/XML.h" #include "tse3/TimeSigTrack.h" #include void TSE3::File::write(XmlFileWriter &writer, TSE3::TimeSigTrack &tst) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "TimeSigTrack"); writer.element("Status", tst.status()); TSE3::File::XmlFileWriter::AutoElement ae2(writer, "Events"); for (size_t n = 0; n < tst.size(); ++n) { // This will be a stringstream std::ostringstream ev; ev << tst[n].time << ":" << tst[n].data.top << "/" << tst[n].data.bottom; writer.element("Event", ev.str()); } } tse3-0.3.1/src/tse3/file/Write.cpp0000644000175700001440000000105310271145601013473 00000000000000#include "tse3/file/Write.h" #include "tse3/file/XML.h" #include "tse3/Midi.h" const int MajorVersion = 200; const int MinorVersion = 0; static const char *originator = "TSE3"; void TSE3::File::writeSong(XmlFileWriter &writer, TSE3::Song &song) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "TSE3"); writer.element("Version-Major", MajorVersion); writer.element("Version-Minor", MinorVersion); writer.element("Originator", originator); writer.element("PPQN", Clock::PPQN); TSE3::File::write(writer, song); } tse3-0.3.1/src/tse3/file/Song.cpp0000644000175700001440000000216510271145601013314 00000000000000 #include "tse3/file/Write.h" #include "tse3/file/XML.h" #include "tse3/Song.h" void TSE3::File::write(XmlFileWriter &writer, TSE3::Song &song) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "Song"); writer.comment("General information"); writer.element("Title", song.title()); writer.element("Author", song.author()); writer.element("Copyright", song.copyright()); writer.element("Date", song.date()); writer.element("NoTracks", song.size()); writer.comment("Master tracks"); write(writer, *song.tempoTrack()); write(writer, *song.timeSigTrack()); write(writer, *song.keySigTrack()); write(writer, *song.flagTrack()); writer.comment("Playback information"); writer.element("SoloTrack", song.soloTrack()); writer.element("Repeat", song.repeat()); writer.element("From", song.from()); writer.element("To", song.to()); writer.comment("Phrase information"); write(writer, *song.phraseList()); writer.comment("Track information"); for (size_t n = 0; n < song.size(); ++n) { write(writer, *song[n]); } } tse3-0.3.1/src/tse3/file/MidiFilter.cpp0000644000175700001440000000171410302613537014440 00000000000000 #include "tse3/file/Write.h" #include "tse3/file/XML.h" #include "tse3/MidiFilter.h" void TSE3::File::write(XmlFileWriter &writer, TSE3::MidiFilter &mf) { TSE3::File::XmlFileWriter::AutoElement ae(writer, "MidiFilter"); writer.element("Status", mf.status()); unsigned int c_filter = 0, p_filter = 0; for (int n = 0; n < 16; n++) if (mf.channelFilter(n)) c_filter |= (1< // Loading Songs #include #include "tse3/Song.h" /****************************************************************************** * XmlLoadInfo *****************************************************************************/ TSE3::File::XmlLoadInfo::XmlLoadInfo() : PPQN(TSE3::Clock::PPQN), song(0), // major(-1), minor(-1), gcc 3.0 doesn't like this XXX unknownChunks(false), unknownData(false), noChunks(0), progress(0) { major = -1; minor = -1; } /****************************************************************************** * XmlFileWriter *****************************************************************************/ class TSE3::File::XmlFileWriterImpl { public: std::stack elements; }; TSE3::File::XmlFileWriter::XmlFileWriter(std::ostream &o) : out(o), indentLevel(0), pimpl(new TSE3::File::XmlFileWriterImpl) { //out << "\n"; //TSE3MDL isn't real XML (yet) so we don't write this } TSE3::File::XmlFileWriter::~XmlFileWriter() { delete pimpl; } void TSE3::File::XmlFileWriter::indent(std::ostream &out) { for (int n = 0; n < indentLevel; n++) out << " "; } void TSE3::File::XmlFileWriter::openElement(const std::string &name) { indent(out); out << "<" << name << ">\n"; pimpl->elements.push(name); indentLevel++; } void TSE3::File::XmlFileWriter::closeElement() { indentLevel--; indent(out); out << "elements.top() << ">\n"; pimpl->elements.pop(); } void TSE3::File::XmlFileWriter::element(const std::string &name, const std::string &value) { indent(out); out << "<" << name << " value=\"" << value << "\"/>\n"; } void TSE3::File::XmlFileWriter::element(const std::string &name, const char *value) { indent(out); out << "<" << name << " value=\"" << value << "\"/>\n"; } void TSE3::File::XmlFileWriter::element(const std::string &name, int value) { indent(out); out << "<" << name << " value=\"" << value << "\"/>\n"; } void TSE3::File::XmlFileWriter::element(const std::string &name, unsigned int value) { indent(out); out << "<" << name << " value=\"" << value << "\"/>\n"; } void TSE3::File::XmlFileWriter::element(const std::string &name, bool value) { indent(out); out << "<" << name << " value=\"" << (value ? "true" : "false") << "\"/>\n"; } void TSE3::File::XmlFileWriter::comment(const std::string &comment) { indent(out); out << "\n"; } /****************************************************************************** * XmlFileReader *****************************************************************************/ TSE3::File::XmlFileReader::XmlFileReader(std::istream &in) : in(in) { } TSE3::File::XmlFileReader::~XmlFileReader() { } namespace { class SimpleNumberParser : public TSE3::File::XmlElementParser { public: SimpleNumberParser(int &number) : number(number) {} /** * @reimplemented */ void parse(const std::string &data) { int i; std::istringstream si(data); si >> i; number = i; } private: int &number; }; } TSE3::Song *TSE3::File::XmlFileReader::load() { XmlBlockParser parser; XmlLoadInfo info; XmlBlockParser tse3parser; SimpleNumberParser versionMajor(info.major); SimpleNumberParser versionMinor(info.minor); SimpleNumberParser ppqn(info.PPQN); std::auto_ptr song(new TSE3::Song(0)); info.song = song.get(); info.progress = 0;//progress; parser.add("TSE3", tse3parser); tse3parser.add("Version-Major", versionMajor); tse3parser.add("Version-Minor", versionMinor); tse3parser.add("PPQN", ppqn); parser.parse(in, "", info); return song.release(); } /****************************************************************************** * XmlBlockParser *****************************************************************************/ TSE3::File::XmlBlockParser::XmlBlockParser() : catchAll(0) { } void TSE3::File::XmlBlockParser::add(const std::string &name, XmlBlockParser &block) { blocks[name] = █ } void TSE3::File::XmlBlockParser::add(const std::string &name, XmlElementParser &item) { elements[name] = &item; } void TSE3::File::XmlBlockParser::add(XmlElementParser &item) { catchAll = &item; } void TSE3::File::XmlBlockParser::parse(std::istream &in, const std::string &tag, XmlLoadInfo &info) { // Check that the chunk opens correctly std::cout << "XBP: start of tag given as \""<progress(in.tellg()); } bool more = true; std::string line; while (more && getline(ws(in), line)) { std::cout << "XBP: line[ " << line << " ]"; if (line == "") { std::cout << " is matching end tag\n"; more = false; } else if (!line.size() || line.find("