Exemple #1
0
// Generate a single midi data list for TSE3 from all current track
// tabulature.
TSE3::PhraseEdit *TabTrack::midiTrack(bool tracking, int tracknum)
{
	TSE3::PhraseEdit *midi = new TSE3::PhraseEdit();

	long timer = 0;				// midi timestamp for each note
	int midilen = 0;			// midi ticks until start of next note
	int duration;				// note duration (dead note: less than midilen)
	uchar pitch;				// note pitch
	const int velocity = 0x60;	// note velocity

	// Ugly MIDI shift between real start of notes and things like
	// patch/bank changes, etc. Required for stupid MIDI devices that
	// can't handle patch/bank change and note on event on the same tick.
	int midiShift = tracking ? 5 : 0;

	cursortimer = -1;

	for (uint x = 0; x < c.size(); x++) {

		// Calculate real duration (including all the linked beats)
		// for the non-ringing notes, which determines midilen
		// note: need to keep x unchanged, because pitch and effects are stored
		// in the first column of a set linked beats
		// remember x of the last linked beat, though

		int xl;					// x last linked note
		xl = x;
		midilen = c[xl].fullDuration();
		while ((xl + 1 < c.size()) && (c[xl + 1].flags & FLAG_ARC)) {
			xl++;
			midilen += c[xl].fullDuration();
		}

		if (x == this->x || (cursortimer == -1 && x > this->x))
			cursortimer = timer;

		// Note on/off events
		for (int i = 0; i < string; i++) {
			if (c[x].a[i] == -1)  continue;

			if (c[x].a[i] == DEAD_NOTE) {
				pitch = tune[i];
				duration = 5;
			} else {
				pitch = c[x].a[i] + tune[i];
				duration = midilen;
			}

			if (c[x].flags & FLAG_PM)
				duration = duration / 2;

			// ringing overrides the duration
			if (c[x].e[i] == EFFECT_LETRING) {
				// LVIFIX: add support for notes linked to ringing note
				// LVIFIX: the linked note should be able to be ringing itself
				duration = noteDuration(x, i);
			}

			if (c[x].e[i] == EFFECT_ARTHARM)
				pitch += 12;
			if (c[x].e[i] == EFFECT_HARMONIC) {
				switch (c[x].a[i]) {
				case 3:  pitch += 28; break;
				case 4:  pitch += 24; break;
				case 5:  pitch += 19; break;
				case 7:  pitch += 12; break;
				case 9:  pitch += 19; break;
				case 12: pitch += 0;  break;
				case 16: pitch += 12; break;    // same as 9th fret
				case 19: pitch += 0;  break;	// same as 7th fret
				case 24: pitch += 0;  break;    // same as 5th fret
				}
			}

// 			midi->insert(
// 				TSE3::MidiEvent(TSE3::MidiCommand(TSE3::MidiCommand_NoteOn,
// 				                                  channel - 1, Settings::midiPort(),
// 				                                  pitch, velocity),
// 				                timer + midiShift, velocity, timer + duration));

			midi->insert(
				TSE3::MidiEvent(TSE3::MidiCommand(TSE3::MidiCommand_NoteOn,
				                                  channel - 1, Settings::midiPort(),
				                                  pitch, velocity),
				                timer + midiShift));
			midi->insert(
				TSE3::MidiEvent(TSE3::MidiCommand(TSE3::MidiCommand_NoteOff,
				                                  channel - 1, Settings::midiPort(),
				                                  pitch, velocity),
				                timer + midiShift + duration - 1));

//			cout << "Inserted note pitch " << (int) pitch
//				 << ", start " << timer << ", duration " << duration << "\n";

		} // for (int i = 0; i < string ...

		if (tracking)
			midi->insert(TSE3::MidiEvent(encodeTimeTracking(tracknum, x), timer));

		timer += midilen;
		x = xl;					// step over linked notes

	} // for (uint x = 0; x < c.size() ...

	if (tracking) {
		// GREYFIX: Workaround for TSE3 bug (?) - last event not playing
		midi->insert(
			TSE3::MidiEvent(TSE3::MidiCommand(TSE3::MidiCommand_NoteOff,
											  0, Settings::midiPort(),
											  0, 0), timer + 120)
			);
	}

	// Initial setup, patches, midi volumes, choruses, etc.
	midi->insert(TSE3::MidiEvent(TSE3::MidiCommand(
										TSE3::MidiCommand_ProgramChange,
										channel - 1, Settings::midiPort(), patch),
								 tracking ? cursortimer : 0)
				 );

	return midi;
}
Exemple #2
0
int main()
{
    /**************************************************************************
     * 1. Create a Song containing a scale
     *************************************************************************/

    // First, we create a scale in a PhraseEdit

    TSE3::PhraseEdit phraseEdit;
    int              note = rootNote;
    TSE3::Clock      time = 0;
    for (int n = 0; n < 8; n++)
    {
        const int delta[]  = {2, 2, 1, 2, 2, 2, 1, 0};
        const int velocity = 0x60;
        const int channel  = 0;
        const int port     = 0;

        phraseEdit.insert
            (TSE3::MidiEvent(TSE3::MidiCommand(TSE3::MidiCommand_NoteOn,
                                               channel, port, note, velocity),
             time, velocity, time+duration));

        note += delta[n];
        time += duration;
    }

    // Now assemble the Song
    TSE3::Song    song(1);
    TSE3::Phrase *phrase = phraseEdit.createPhrase(song.phraseList());
    TSE3::Part   *part   = new TSE3::Part(0, phraseEdit.lastClock());
    part->setPhrase(phrase);
    song[0]->insert(part);

    /**************************************************************************
     * 2. Play the Song
     *************************************************************************/

    // Create transport objects
    // (You really want to create a MidiScheduler for your platform, perhaps
    // you'll use the UnixMidiSchedulerFactory)
    TSE3::Metronome                 metronome;
    TSE3::Util::StreamMidiScheduler scheduler;
    TSE3::Transport                 transport(&metronome, &scheduler);

    // Play and wait for the end
    transport.play(&song, 0);
    while (transport.status() != TSE3::Transport::Resting)
    {
        transport.poll();
        // perhaps sleep here to prevent slaughtering the CPU
    }

    /**************************************************************************
     * 3. Save the Song as a standard MIDI file
     *************************************************************************/

    TSE3::MidiFileExport mfe;
    mfe.save("export.midi", &song);

    /**************************************************************************
     * All done - note that there is no memory leak - when the Song is deleted
     * (it is on the stack, so this will happen automatically) all the other
     * components will be deleted by the Song's destructor.
     *************************************************************************/

    return 0;
}