Ejemplo n.º 1
0
void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len)/*{{{*/
{
        {
            startUndo();

            MidiPart* nPart = new MidiPart(*(MidiPart*) oPart);
            nPart->setLenTick(len);
            // Indicate no undo, and do port controller values but not clone parts.
            audio->msgChangePart(oPart, nPart, false, true, false);

            // cut Events in nPart
            // Changed by T356. Don't delete events if this is a clone part.
            // The other clones might be longer than this one and need these events.
            if (nPart->cevents()->arefCount() <= 1)
            {
                if (oPart->lenTick() > len)
                {
                    EventList* el = nPart->events();
                    iEvent ie = el->lower_bound(len);
                    for (; ie != el->end();)
                    {
                        iEvent i = ie;
                        ++ie;
                        // Indicate no undo, and do port controller values and clone parts.
                        audio->msgDeleteEvent(i->second, nPart, false, true, true);
                    }
                }
            }

            /*
            // cut Events in nPart
            // Changed by T356. Don't delete events if this is a clone part.
            // The other clones might be longer than this one and need these events.
            if(oPart->cevents()->arefCount() <= 1)
            {
              if (oPart->lenTick() > len) {
                    EventList* el = nPart->events();
                    iEvent ie = el->lower_bound(len);
                    for (; ie != el->end();) {
                          iEvent i = ie;
                          ++ie;
                          // Indicate no undo, and do not do port controller values and clone parts.
                          //audio->msgDeleteEvent(i->second, nPart, false);
                          audio->msgDeleteEvent(i->second, nPart, false, false, false);
                          }
                    }
            }
            // Indicate no undo, and do port controller values but not clone parts.
            //audio->msgChangePart(oPart, nPart, false);
            audio->msgChangePart(oPart, nPart, false, true, false);
             */

            endUndo(SC_PART_MODIFIED);
        }
}/*}}}*/
Ejemplo n.º 2
0
void LOS::processTrack(MidiTrack* track)
{
    EventList* tevents = track->events();
    if (tevents->empty())
        return;

    //---------------------------------------------------
    // Identify Parts
    // The MIDI tracks are broken up into parts
    // A new Part will be located based on track.
    // Events will be aligned on new track
    //---------------------------------------------------

    PartList* pl = track->parts();

    int lastTick = 0;
    for (iEvent i = tevents->begin(); i != tevents->end(); ++i)
    {
        Event event = i->second;
        int epos = event.tick() + event.lenTick();
        if (epos > lastTick)
            lastTick = epos;
    }

    QString partname = track->name();
    int len = song->roundUpBar(lastTick + 1);

    // p3.3.27
    if (config.importMidiSplitParts)
    {

        int bar2, beat;
        unsigned tick;
        sigmap.tickValues(len, &bar2, &beat, &tick);

        int lastOff = 0;
        int st = -1; // start tick current part
        int x1 = 0; // start tick current measure
        int x2 = 0; // end tick current measure

        for (int bar = 0; bar < bar2; ++bar, x1 = x2)
        {
            ///x2 = sigmap.bar2tick(bar+1, 0, 0);
            x2 = sigmap.bar2tick(bar + 1, 0, 0);
            if (lastOff > x2)
            {
                // this measure is busy!
                continue;
            }
            iEvent i1 = tevents->lower_bound(x1);
            iEvent i2 = tevents->lower_bound(x2);

            if (i1 == i2)
            { // empty?
                if (st != -1)
                {
                    MidiPart* part = new MidiPart(track);
                    part->setTick(st);
                    part->setLenTick(x1 - st);
                    // printf("new part %d len: %d\n", st, x1-st);
                    part->setName(partname);
                    pl->add(part);
                    st = -1;
                }
            }
            else
            {
                if (st == -1)
                    st = x1; // begin new  part
                //HACK:
                //lastOff:
                for (iEvent i = i1; i != i2; ++i)
                {
                    Event event = i->second;
                    if (event.type() == Note)
                    {
                        int off = event.tick() + event.lenTick();
                        if (off > lastOff)
                            lastOff = off;
                    }
                }
            }
        }
        if (st != -1)
        {
            MidiPart* part = new MidiPart(track);
            part->setTick(st);
            // printf("new part %d len: %d\n", st, x2-st);
            part->setLenTick(x2 - st);
            part->setName(partname);
            pl->add(part);
        }
    }
    else
    {
        // Just one long part...
        MidiPart* part = new MidiPart(track);
        //part->setTick(st);
        part->setTick(0);
        part->setLenTick(len);
        part->setName(partname);
        pl->add(part);
    }

    //-------------------------------------------------------------
    //    assign events to parts
    //-------------------------------------------------------------

    for (iPart p = pl->begin(); p != pl->end(); ++p)
    {
        MidiPart* part = (MidiPart*) (p->second);
        int stick = part->tick();
        int etick = part->tick() + part->lenTick();
        iEvent r1 = tevents->lower_bound(stick);
        iEvent r2 = tevents->lower_bound(etick);
        int startTick = part->tick();

        EventList* el = part->events();
        for (iEvent i = r1; i != r2; ++i)
        {
            Event ev = i->second;
            int ntick = ev.tick() - startTick;
            ev.setTick(ntick);
            el->add(ev);
        }
        tevents->erase(r1, r2);
    }

    if (tevents->size())
        printf("-----------events left: %zd\n", tevents->size());
    for (iEvent i = tevents->begin(); i != tevents->end(); ++i)
    {
        printf("%d===\n", i->first);
        i->second.dump();
    }
    // all events should be processed:
    assert(tevents->empty());
}
Ejemplo n.º 3
0
Archivo: midi.cpp Proyecto: faesong/oom
void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,
		int div, bool addSysexMeta, bool doLoops)
{
	int hbank = 0xff;
	int lbank = 0xff;
	int rpnh = -1;
	int rpnl = -1;
	int datah = 0;
	int datal = 0;
	int dataType = 0; // 0 : disabled, 0x20000 : rpn, 0x30000 : nrpn

	EventList mel;

	for (iMPEvent i = el->begin(); i != el->end(); ++i)
	{
		MidiPlayEvent ev = *i;
		if (!addSysexMeta && (ev.type() == ME_SYSEX || ev.type() == ME_META))
			continue;
		if (!(ev.type() == ME_SYSEX || ev.type() == ME_META
				|| ((ev.channel() == track->outChannel()) && (ev.port() == track->outPort()))))
			continue;
		unsigned tick = ev.time();
		// Added by Tim. p3.3.8

		// Added by T356.
		if (doLoops)
		{
			if (tick >= song->lPos().tick() && tick < song->rPos().tick())
			{
				int loopn = ev.loopNum();
				int loopc = audio->loopCount();
				int cmode = song->cycleMode(); // CYCLE_NORMAL, CYCLE_MIX, CYCLE_REPLACE
				// If we want REPLACE and the event was recorded in a previous loop,
				//  just ignore it. This will effectively ignore ALL previous loop events inside
				//  the left and right markers, regardless of where recording was started or stopped.
				// We want to keep any loop 0 note-offs from notes which crossed over the left marker.
				// To avoid more searching here, just keep ALL note-offs from loop 0, and let code below
				//  sort out and keep which ones had note-ons.
				if (!(ev.isNoteOff() && loopn == 0))
				{
					if (cmode == Song::CYCLE_REPLACE && loopn < loopc)
					{
						// Added by Tim. p3.3.8
						//printf("buildMidiEventList: CYCLE_REPLACE t:%d type:%d A:%d B:%d ln:%d lc:%d\n", tick, ev.type(), ev.dataA(), ev.dataB(), loopn, loopc);

						continue;
					}
					// If we want NORMAL, same as REPLACE except keep all events from the previous loop
					//  from rec stop position to right marker (and beyond).
					if (cmode == Song::CYCLE_NORMAL)
					{
						// Not sure of accuracy here. Adjust? Adjusted when used elsewhere?
						unsigned endRec = audio->getEndRecordPos().tick();
						if ((tick < endRec && loopn < loopc) || (tick >= endRec && loopn < (loopc - 1)))
						{
							// Added by Tim. p3.3.8
							//printf("buildMidiEventList: CYCLE_NORMAL t:%d type:%d A:%d B:%d ln:%d lc:%d\n", tick, ev.type(), ev.dataA(), ev.dataB(), loopn, loopc);

							continue;
						}
					}
				}
			}
		}

		Event e;
		switch (ev.type())
		{
			case ME_NOTEON:
				e.setType(Note);

				if (track->type() == Track::DRUM)
				{
					int instr = drumInmap[ev.dataA()];
					e.setPitch(instr);
				}
				else
				{
					e.setPitch(ev.dataA());
				}

				e.setVelo(ev.dataB());
				e.setLenTick(0);
				break;
			case ME_NOTEOFF:
				e.setType(Note);
				if (track->type() == Track::DRUM)
				{
					int instr = drumInmap[ev.dataA()];
					e.setPitch(instr);
				}
				else
					e.setPitch(ev.dataA());
				e.setVelo(0);
				e.setVeloOff(ev.dataB());
				e.setLenTick(0);
				break;
			case ME_POLYAFTER:
				e.setType(PAfter);
				e.setA(ev.dataA());
				e.setB(ev.dataB());
				break;
			case ME_CONTROLLER:
			{
				int val = ev.dataB();
				switch (ev.dataA())
				{
					case CTRL_HBANK:
						hbank = val;
						break;

					case CTRL_LBANK:
						lbank = val;
						break;

					case CTRL_HDATA:
						datah = val;
						// check if a CTRL_LDATA follows
						// e.g. wie have a 14 bit controller:
					{
						iMPEvent ii = i;
						++ii;
						bool found = false;
						for (; ii != el->end(); ++ii)
						{
							MidiPlayEvent ev = *ii;
							if (ev.type() == ME_CONTROLLER)
							{
								if (ev.dataA() == CTRL_LDATA)
								{
									// handle later
									found = true;
								}
								break;
							}
						}
						if (!found)
						{
							if (rpnh == -1 || rpnl == -1)
							{
								printf("parameter number not defined, data 0x%x\n", datah);
							}
							else
							{
								int ctrl = dataType | (rpnh << 8) | rpnl;
								e.setType(Controller);
								e.setA(ctrl);
								e.setB(datah);
							}
						}
					}
						break;

					case CTRL_LDATA:
						datal = val;

						if (rpnh == -1 || rpnl == -1)
						{
							printf("parameter number not defined, data 0x%x 0x%x, tick %d, channel %d\n",
									datah, datal, tick, track->outChannel());
							break;
						}
						// assume that the sequence is always
						//    CTRL_HDATA - CTRL_LDATA
						// eg. that LDATA is always send last

						e.setType(Controller);
						// 14 Bit RPN/NRPN
						e.setA((dataType + 0x30000) | (rpnh << 8) | rpnl);
						e.setB((datah << 7) | datal);
						break;

					case CTRL_HNRPN:
						rpnh = val;
						dataType = 0x30000;
						break;

					case CTRL_LNRPN:
						rpnl = val;
						dataType = 0x30000;
						break;

					case CTRL_HRPN:
						rpnh = val;
						dataType = 0x20000;
						break;

					case CTRL_LRPN:
						rpnl = val;
						dataType = 0x20000;
						break;

					default:
						e.setType(Controller);
						int ctl = ev.dataA();
						e.setA(ctl);

						if (track->type() == Track::DRUM)
						{
							// Is it a drum controller event, according to the track port's instrument?
							MidiController *mc = midiPorts[track->outPort()].drumController(ctl);
							if (mc)
								// Store an index into the drum map.
								e.setA((ctl & ~0xff) | drumInmap[ctl & 0x7f]);
						}

						e.setB(val);
						break;
				}
			}
				break;

			case ME_PROGRAM:
				e.setType(Controller);
				e.setA(CTRL_PROGRAM);
				e.setB((hbank << 16) | (lbank << 8) | ev.dataA());
				break;

			case ME_AFTERTOUCH:
				e.setType(CAfter);
				e.setA(ev.dataA());
				break;

			case ME_PITCHBEND:
				e.setType(Controller);
				e.setA(CTRL_PITCH);
				e.setB(ev.dataA());
				break;

			case ME_SYSEX:
				e.setType(Sysex);
				e.setData(ev.data(), ev.len());
				break;

			case ME_META:
			{
				const unsigned char* data = ev.data();
				switch (ev.dataA())
				{
					case 0x01: // Text
						if (track->comment().isEmpty())
							track->setComment(QString((const char*) data));
						else
							track->setComment(track->comment() + "\n" + QString((const char*) data));
						break;
					case 0x03: // Sequence-/TrackName
						track->setName(QString((char*) data));
						break;
					case 0x6: // Marker
					{
						unsigned ltick = CALC_TICK(tick); //(tick * config.division + div/2) / div;
						song->addMarker(QString((const char*) (data)), ltick, false);
					}
						break;
					case 0x5: // Lyrics
					case 0x8: // text
					case 0x9:
					case 0xa:
						break;

					case 0x0f: // Track Comment
						track->setComment(QString((char*) data));
						break;
					case 0x51: // Tempo
					{
						unsigned tempo = data[2] + (data[1] << 8) + (data[0] << 16);
						unsigned ltick = CALC_TICK(tick); // (unsigned(tick) * unsigned(config.division) + unsigned(div/2)) / unsigned(div);
						// After ca 10 mins 32 bits will not be enough... This expression has to be changed/factorized or so in some "sane" way...
						tempomap.addTempo(ltick, tempo);
					}
						break;
					case 0x58: // Time Signature
					{
						int timesig_z = data[0];
						int n = data[1];
						int timesig_n = 1;
						for (int i = 0; i < n; i++)
							timesig_n *= 2;
						int ltick = CALC_TICK(tick); //(tick * config.division + div/2) / div;
						///sigmap.add(ltick, timesig_z, timesig_n);
						AL::sigmap.add(ltick, AL::TimeSignature(timesig_z, timesig_n));
					}
						break;
					case 0x59: // Key Signature
						// track->scale.set(data[0]);
						// track->scale.setMajorMinor(data[1]);
						break;
					default:
						printf("unknown Meta 0x%x %d\n", ev.dataA(), ev.dataA());
				}
			}
				break;
		} // switch(ev.type()
		if (!e.empty())
		{
			e.setTick(tick);
			// Added by Tim. p3.3.8
			//printf("buildMidiEventList: mel adding t:%d type:%d A:%d B:%d C:%d\n", tick, e.type(), e.dataA(), e.dataB(), e.dataC());

			mel.add(e);
		}
	} // i != el->end()

	//---------------------------------------------------
	//    resolve NoteOff events
	//---------------------------------------------------

	//      for (iEvent i = mel.begin(); i != mel.end(); ++i) {
	//            Event event = i->second;
	//            if (event.isNote())
	//                  event.setLenTick(0);
	//            }

	// Added by Tim. p3.3.8

	// The loop is a safe way to delete while iterating.
	bool loop;
	do
	{
		loop = false;

		for (iEvent i = mel.begin(); i != mel.end(); ++i)
		{
			Event ev = i->second;
			if (ev.isNote())
			{
				if (ev.isNoteOff())
				{
					iEvent k;
					bool found = false;
					for (k = i; k != mel.end(); ++k)
					{
						Event event = k->second;
						if (event.tick() > ev.tick())
							break;
						if (event.isNoteOff(ev))
						{
							ev.setLenTick(1);
							ev.setVelo(event.velo());
							ev.setVeloOff(0);
							// Added by Tim. p3.3.8
							//printf("buildMidiEventList: found note off: event t:%d len:%d type:%d A:%d B:%d C:%d  ev t:%d len:%d type:%d A:%d B:%d C:%d\n", event.tick(), event.lenTick(), event.type(), event.dataA(), event.dataB(), event.dataC(), ev.tick(), ev.lenTick(), ev.type(), ev.dataA(), ev.dataB(), ev.dataC());

							found = true;
							break;
						}
					}
					if (!found)
					{
						printf("NOTE OFF without Note ON tick %d type %d  %d %d\n",
								ev.tick(), ev.type(), ev.pitch(), ev.velo());
					}
					else
					{
						mel.erase(k);

						// Changed by Tim. p3.3.8
						//continue;
						loop = true;
						break;

					}
				}
				// Added by Tim. p3.3.8

				// If the event length is not zero, it means the event and its
				//  note on/off have already been taken care of. So ignore it.
				if (ev.lenTick() != 0)
				{
					continue;
				}

				iEvent k;
				for (k = mel.lower_bound(ev.tick()); k != mel.end(); ++k)
				{
					Event event = k->second;
					if (ev.isNoteOff(event))
					{
						int t = k->first - i->first;
						if (t <= 0)
						{
							if (debugMsg)
							{
								printf("Note len is (%d-%d)=%d, set to 1\n",
										k->first, i->first, k->first - i->first);
								ev.dump();
								event.dump();
							}
							t = 1;
						}
						ev.setLenTick(t);
						ev.setVeloOff(event.veloOff());
						// Added by Tim. p3.3.8
						//printf("buildMidiEventList: set len and velOff: event t:%d len:%d type:%d A:%d B:%d C:%d  ev t:%d len:%d type:%d A:%d B:%d C:%d\n", event.tick(), event.lenTick(), event.type(), event.dataA(), event.dataB(), event.dataC(), ev.tick(), ev.lenTick(), ev.type(), ev.dataA(), ev.dataB(), ev.dataC());

						break;
					}
				}
				if (k == mel.end())
				{
					printf("-no note-off! %d pitch %d velo %d\n",
							ev.tick(), ev.pitch(), ev.velo());
					//
					// switch off at end of measure
					//
					int endTick = song->roundUpBar(ev.tick() + 1);
					ev.setLenTick(endTick - ev.tick());
				}
				else
				{
					mel.erase(k);
					// Added by Tim. p3.3.8
					loop = true;
					break;

				}
			}
		}
	} while (loop);

	// DEBUG: any note offs left?

	// Removed by Tim. p3.3.8
	//for (iEvent i = mel.begin(); i != mel.end(); ++i) {
	//      Event ev  = i->second;
	//      if (ev.isNoteOff()) {
	//            printf("+extra note-off! %d pitch %d velo %d\n",
	//                     i->first, ev.pitch(), ev.velo());
	//                  ev.dump();
	//            }
	//      }

	for (iEvent i = mel.begin(); i != mel.end(); ++i)
	{
		Event ev = i->second;
		if (ev.isNoteOff())
		{
			printf("+extra note-off! %d pitch %d velo %d\n",
					i->first, ev.pitch(), ev.velo());
			//                  ev.dump();
			continue;
		}
		int tick = CALC_TICK(ev.tick()); //(ev.tick() * config.division + div/2) / div;
		if (ev.isNote())
		{
			int lenTick = CALC_TICK(ev.lenTick()); //(ev.lenTick() * config.division + div/2) / div;
			ev.setLenTick(lenTick);
		}
		ev.setTick(tick);
		del->add(ev);
	}
}
Ejemplo n.º 4
0
Archivo: midi.cpp Proyecto: faesong/oom
void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts)
{
	int port = track->outPort();
	int channel = track->outChannel();
	int defaultPort = port;

	MidiDevice* md = midiPorts[port].device();
	MPEventList* playEvents = md->playEvents();
	MPEventList* stuckNotes = md->stuckNotes();

	PartList* pl = track->parts();
	for (iPart p = pl->begin(); p != pl->end(); ++p)
	{
		MidiPart* part = (MidiPart*) (p->second);
		// dont play muted parts
		if (part->mute())
			continue;
		EventList* events = part->events();
		unsigned partTick = part->tick();
		unsigned partLen = part->lenTick();
		int delay = track->delay;

		if (cts > nts)
		{
			printf("processMidi: FATAL: cur > next %d > %d\n",
					cts, nts);
			return;
		}
		unsigned offset = delay + partTick;
		if (offset > nts)
			continue;
		unsigned stick = (offset > cts) ? 0 : cts - offset;
		unsigned etick = nts - offset;
		// By T356. Do not play events which are past the end of this part.
		if (etick > partLen)
			continue;

		iEvent ie = events->lower_bound(stick);
		iEvent iend = events->lower_bound(etick);

		for (; ie != iend; ++ie)
		{
			Event ev = ie->second;
			port = defaultPort; //Reset each loop
			//
			//  dont play any meta events
			//
			if (ev.type() == Meta)
				continue;
			if (track->type() == Track::DRUM)
			{
				int instr = ev.pitch();
				// ignore muted drums
				if (ev.isNote() && drumMap[instr].mute)
					continue;
			}
			unsigned tick = ev.tick() + offset;
			unsigned frame = tempomap.tick2frame(tick) + frameOffset;
			switch (ev.type())
			{
				case Note:
				{
					int len = ev.lenTick();
					int pitch = ev.pitch();
					int velo = ev.velo();
					if (track->type() == Track::DRUM)
					{
						//
						// Map drum-notes to the drum-map values
						//
						int instr = ev.pitch();
						pitch = drumMap[instr].anote;
						port = drumMap[instr].port; //This changes to non-default port
						channel = drumMap[instr].channel;
						velo = int(double(velo) * (double(drumMap[instr].vol) / 100.0));
					}
					else
					{
						//
						// transpose non drum notes
						//
						pitch += (track->transposition + song->globalPitchShift());
					}

					if (pitch > 127)
						pitch = 127;
					if (pitch < 0)
						pitch = 0;
					velo += track->velocity;
					velo = (velo * track->compression) / 100;
					if (velo > 127)
						velo = 127;
					if (velo < 1) // no off event
						velo = 1;
					len = (len * track->len) / 100;
					if (len <= 0) // dont allow zero length
						len = 1;
					int veloOff = ev.veloOff();

					if (port == defaultPort)
					{
						//printf("Adding event normally: frame=%d port=%d channel=%d pitch=%d velo=%d\n",frame, port, channel, pitch, velo);

						// p3.3.25
						// If syncing to external midi sync, we cannot use the tempo map.
						// Therefore we cannot get sub-tick resolution. Just use ticks instead of frames.
						if (extSyncFlag.value())
							playEvents->add(MidiPlayEvent(tick, port, channel, 0x90, pitch, velo));
						else

							playEvents->add(MidiPlayEvent(frame, port, channel, 0x90, pitch, velo));

						stuckNotes->add(MidiPlayEvent(tick + len, port, channel,
								veloOff ? 0x80 : 0x90, pitch, veloOff));
					}
					else
					{ //Handle events to different port than standard.
						MidiDevice* mdAlt = midiPorts[port].device();
						if (mdAlt)
						{

							// p3.3.25
							if (extSyncFlag.value())
								mdAlt->playEvents()->add(MidiPlayEvent(tick, port, channel, 0x90, pitch, velo));
							else

								mdAlt->playEvents()->add(MidiPlayEvent(frame, port, channel, 0x90, pitch, velo));

							mdAlt->stuckNotes()->add(MidiPlayEvent(tick + len, port, channel,
									veloOff ? 0x80 : 0x90, pitch, veloOff));
						}
					}

					if (velo > track->activity())
						track->setActivity(velo);
				}
					break;

					// Added by T356.
				case Controller:
				{
					//int len   = ev.lenTick();
					//int pitch = ev.pitch();
					if (track->type() == Track::DRUM)
					{
						int ctl = ev.dataA();
						// Is it a drum controller event, according to the track port's instrument?
						MidiController *mc = midiPorts[defaultPort].drumController(ctl);
						if (mc)
						{
							int instr = ctl & 0x7f;
							ctl &= ~0xff;
							int pitch = drumMap[instr].anote & 0x7f;
							port = drumMap[instr].port; //This changes to non-default port
							channel = drumMap[instr].channel;
							MidiDevice* mdAlt = midiPorts[port].device();
							if (mdAlt)
							{
								// p3.3.25
								// If syncing to external midi sync, we cannot use the tempo map.
								// Therefore we cannot get sub-tick resolution. Just use ticks instead of frames.
								if (extSyncFlag.value())
									mdAlt->playEvents()->add(MidiPlayEvent(tick, port, channel,
										ME_CONTROLLER, ctl | pitch, ev.dataB()));
								else

									//playEvents->add(MidiPlayEvent(frame, port, channel, ev));
									mdAlt->playEvents()->add(MidiPlayEvent(frame, port, channel,
										ME_CONTROLLER, ctl | pitch, ev.dataB()));

							}
							break;
						}
					}
					// p3.3.25
					if (extSyncFlag.value())
						playEvents->add(MidiPlayEvent(tick, port, channel, ev));
					else

						playEvents->add(MidiPlayEvent(frame, port, channel, ev));
				}
					break;


				default:
					// p3.3.25
					if (extSyncFlag.value())
						playEvents->add(MidiPlayEvent(tick, port, channel, ev));
					else

						playEvents->add(MidiPlayEvent(frame, port, channel, ev));

					break;
			}
		}
	}
}
Ejemplo n.º 5
0
Archivo: part.cpp Proyecto: faesong/oom
void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len)
{
	switch (track->type())
	{
		case Track::WAVE:
		{
			WavePart* nPart = new WavePart(*(WavePart*) oPart);
			EventList* el = nPart->events();
			unsigned new_partlength = tempomap.deltaTick2frame(oPart->tick(), oPart->tick() + len);
			//printf("new partlength in frames: %d\n", new_partlength);

			// If new nr of frames is less than previous what can happen is:
			// -   0 or more events are beginning after the new final position. Those are removed from the part
			// -   The last event begins before new final position and ends after it. If so, it will be resized to end at new part length
			if (new_partlength < oPart->lenFrame())
			{
				startUndo();

				for (iEvent i = el->begin(); i != el->end(); i++)
				{
					Event e = i->second;
					unsigned event_startframe = e.frame();
					unsigned event_endframe = event_startframe + e.lenFrame();
					//printf("Event frame=%d, length=%d\n", event_startframe, event_length);
					if (event_endframe < new_partlength)
						continue;
					if (event_startframe > new_partlength)
					{ // If event start was after the new length, remove it from part
						// Indicate no undo, and do not do port controller values and clone parts.
						//audio->msgDeleteEvent(e, nPart, false);
						audio->msgDeleteEvent(e, nPart, false, false, false);
						continue;
					}
					if (event_endframe > new_partlength)
					{ // If this event starts before new length and ends after, shrink it
						Event newEvent = e.clone();
						newEvent.setLenFrame(new_partlength - event_startframe);
						// Indicate no undo, and do not do port controller values and clone parts.
						//audio->msgChangeEvent(e, newEvent, nPart, false);
						audio->msgChangeEvent(e, newEvent, nPart, false, false, false);
					}
				}
				nPart->setLenFrame(new_partlength);
				// Indicate no undo, and do not do port controller values and clone parts.
				//audio->msgChangePart(oPart, nPart, false);
				audio->msgChangePart(oPart, nPart, false, false, false);

				endUndo(SC_PART_MODIFIED);
			}
				// If the part is expanded there can be no additional events beginning after the previous final position
				// since those are removed if the part has been shrunk at some time (see above)
				// The only thing we need to check is the final event: If it has data after the previous final position,
				// we'll expand that event
			else
			{
				if (!el->empty())
				{
					iEvent i = el->end();
					i--;
					Event last = i->second;
					unsigned last_start = last.frame();
					SndFileR file = last.sndFile();
					if (file.isNull())
						return;

					unsigned clipframes = (file.samples() - last.spos()); // / file.channels();
					Event newEvent = last.clone();
					//printf("SndFileR samples=%d channels=%d event samplepos=%d clipframes=%d\n", file.samples(), file.channels(), last.spos(), clipframes);

					unsigned new_eventlength = new_partlength - last_start;
					if (new_eventlength > clipframes) // Shrink event length if new partlength exceeds last clip
						new_eventlength = clipframes;

					newEvent.setLenFrame(new_eventlength);
					startUndo();
					// Indicate no undo, and do not do port controller values and clone parts.
					//audio->msgChangeEvent(last, newEvent, nPart, false);
					audio->msgChangeEvent(last, newEvent, nPart, false, false, false);
				}
				else
				{
					startUndo();
				}

				nPart->setLenFrame(new_partlength);
				// Indicate no undo, and do not do port controller values and clone parts.
				//audio->msgChangePart(oPart, nPart, false);
				audio->msgChangePart(oPart, nPart, false, false, false);
				endUndo(SC_PART_MODIFIED);
			}
		}
			break;
		case Track::MIDI:
		case Track::DRUM:
		{
			startUndo();

			MidiPart* nPart = new MidiPart(*(MidiPart*) oPart);
			nPart->setLenTick(len);
			// Indicate no undo, and do port controller values but not clone parts.
			audio->msgChangePart(oPart, nPart, false, true, false);

			// cut Events in nPart
			// Changed by T356. Don't delete events if this is a clone part.
			// The other clones might be longer than this one and need these events.
			if (nPart->cevents()->arefCount() <= 1)
			{
				if (oPart->lenTick() > len)
				{
					EventList* el = nPart->events();
					iEvent ie = el->lower_bound(len);
					for (; ie != el->end();)
					{
						iEvent i = ie;
						++ie;
						// Indicate no undo, and do port controller values and clone parts.
						audio->msgDeleteEvent(i->second, nPart, false, true, true);
					}
				}
			}

			/*
			// cut Events in nPart
			// Changed by T356. Don't delete events if this is a clone part.
			// The other clones might be longer than this one and need these events.
			if(oPart->cevents()->arefCount() <= 1)
			{
			  if (oPart->lenTick() > len) {
					EventList* el = nPart->events();
					iEvent ie = el->lower_bound(len);
					for (; ie != el->end();) {
						  iEvent i = ie;
						  ++ie;
						  // Indicate no undo, and do not do port controller values and clone parts.
						  //audio->msgDeleteEvent(i->second, nPart, false);
						  audio->msgDeleteEvent(i->second, nPart, false, false, false);
						  }
					}
			}
			// Indicate no undo, and do port controller values but not clone parts.
			//audio->msgChangePart(oPart, nPart, false);
			audio->msgChangePart(oPart, nPart, false, true, false);
			 */

			endUndo(SC_PART_MODIFIED);
			break;
		}
		default:
			break;
	}
}