示例#1
0
bool MidiFile::writeTrack(const MidiTrack &t)
      {
      write("MTrk", 4);
      qint64 lenpos = fp->pos();
      writeLong(0);                 // dummy len

      status   = -1;
      int tick = 0;
      for (auto i : t.events()) {
            int ntick = i.first;
            putvl(ntick - tick);    // write tick delta
            //
            // if track channel != -1, then use this
            //    channel for all events in this track
            //
            if (t.outChannel() != -1)
                  writeEvent(i.second);
            tick = ntick;
            }

      //---------------------------------------------------
      //    write "End Of Track" Meta
      //    write Track Len
      //

      putvl(1);
      put(0xff);        // Meta
      put(0x2f);        // EOT
      putvl(0);         // len 0
      qint64 endpos = fp->pos();
      fp->seek(lenpos);
      writeLong(endpos-lenpos-4);   // tracklen
      fp->seek(endpos);
      return false;
      }
示例#2
0
文件: pyapi.cpp 项目: OpenGanesh/oom
PyObject* getMidiControllerValue(PyObject*, PyObject* args)
{
	const char* trackname;
	int ctrltype;

	if (!PyArg_ParseTuple(args, "si", &trackname, &ctrltype))
	{
		return NULL;
	}

	Track* t = song->findTrack(QString(trackname));
	if (t == NULL)
		return NULL;

	if (t->isMidiTrack() == false)
	{
		Py_INCREF(Py_None);
		return Py_None;
	}

	MidiTrack* track = (MidiTrack*) t;
	int channel = track->outChannel();
	int outport = track->outPort();
	MidiPort* mp = &midiPorts[outport];
	if (mp == NULL)
		return Py_BuildValue("i", -1);

	int value = mp->hwCtrlState(channel, ctrltype);
	return Py_BuildValue("i", value);
}
示例#3
0
MidiTrack* MidiTrack::createTempoTrack() {

	MidiTrack* T = new MidiTrack();

	T->insertEvent(new TimeSignature());
	T->insertEvent(new Tempo());

	return T;
}
示例#4
0
void TrackListView::updatePartSelection(Part* part)/*{{{*/
{
    if(part)
    {
        MidiTrack* track = part->track();
        Part* curPart = m_editor->curCanvasPart();
        if (curPart)
        {
            song->setRecordFlag(curPart->track(), false);
        }
        m_editor->setCurCanvasPart(part);
        Song::movePlaybackToPart(part);
        // and turn it on for the new parts track
        song->setRecordFlag(track, true);
        song->deselectTracks();
        song->deselectAllParts();
        track->setSelected(true);
        part->setSelected(true);
        song->update(SC_SELECTION);

        int psn = part->sn();
        for(int i = 0; i < m_model->rowCount(); ++i)
        {
            QStandardItem* item = m_model->item(i, 0);
            if(item)
            {
                int type = item->data(TrackRole).toInt();
                if(type == 1)
                {//TrackMode
                    continue;
                }
                else
                {//PartMode
                    int sn = item->data(PartRole).toInt();
                    if(psn == sn)
                    {
                        m_selectedIndex = item->row();

                        m_tempColor = item->foreground();

                        m_model->blockSignals(true);
                        item->setForeground(QColor(99, 36, 36));
                        m_model->blockSignals(false);
                        update();
                        m_table->selectRow(m_selectedIndex);
                        m_table->scrollTo(m_model->index(m_selectedIndex, 0));

                        m_colorRows.append(m_selectedIndex);

                        QTimer::singleShot(350, this, SLOT(updateColor()));
                        break;
                    }
                }
            }
        }
    }
}/*}}}*/
示例#5
0
文件: part.cpp 项目: ViktorNova/los
void addPortCtrlEvents(Event& event, Part* part, bool doClones)/*{{{*/
{
    // Traverse and process the clone chain ring until we arrive at the same part again.
    // The loop is a safety net.
    // Update: Due to the varying calls, and order of, incARefcount, (msg)ChangePart, replaceClone, and remove/addPortCtrlEvents,
    //  we can not rely on the reference count as a safety net in these routines. We will just have to trust the clone chain.
    Part* p = part;
    //int j = doClones ? p->cevents()->arefCount() : 1;
    //if(j > 0)
    {
        //for(int i = 0; i < j; ++i)
        while (1)
        {
            // Added by Tim. p3.3.6
            //printf("addPortCtrlEvents i:%d %s %p events %p refs:%d arefs:%d\n", i, p->name().toLatin1().constData(), p, part->cevents(), part->cevents()->refCount(), j);

            Track* t = p->track();
            if (t)
            {
                MidiTrack* mt = (MidiTrack*) t;
                int port = mt->outPort();
                //const EventList* el = p->cevents();
                unsigned len = p->lenTick();
                //for(ciEvent ie = el->begin(); ie != el->end(); ++ie)
                //{
                //const Event& ev = ie->second;
                // Added by Tim. p3.3.6
                //printf("addPortCtrlEvents %s len:%d end:%d etick:%d\n", p->name().toLatin1().constData(), p->lenTick(), p->endTick(), event.tick());

                // Do not add events which are past the end of the part.
                if (event.tick() >= len)
                    break;

                if (event.type() == Controller)
                {
                    int ch = mt->outChannel();
                    int tck = event.tick() + p->tick();
                    int cntrl = event.dataA();
                    int val = event.dataB();
                    MidiPort* mp = &midiPorts[port];

                    mp->setControllerVal(ch, tck, cntrl, val, p);
                }
                //}
            }

            if (!doClones)
                break;
            // Get the next clone in the chain ring.
            p = p->nextClone();
            // Same as original part? Finished.
            if (p == part)
                break;
        }
    }
}/*}}}*/
示例#6
0
文件: part.cpp 项目: ViktorNova/los
void removePortCtrlEvents(Part* part, bool doClones)/*{{{*/
{
    // Traverse and process the clone chain ring until we arrive at the same part again.
    // The loop is a safety net.
    // Update: Due to the varying calls, and order of, incARefcount, (msg)ChangePart, replaceClone, and remove/addPortCtrlEvents,
    //  we can not rely on the reference count as a safety net in these routines. We will just have to trust the clone chain.
    Part* p = part;
    //int j = doClones ? p->cevents()->arefCount() : 1;
    //if(j > 0)
    {
        //for(int i = 0; i < j; ++i)
        while (1)
        {
            MidiTrack* t = p->track();
            if (t)
            {
                MidiTrack* mt = (MidiTrack*) t;
                int port = mt->outPort();
                const EventList* el = p->cevents();
                //unsigned len = p->lenTick();
                for (ciEvent ie = el->begin(); ie != el->end(); ++ie)
                {
                    const Event& ev = ie->second;
                    // Added by T356. Do not remove events which are past the end of the part.
                    // No, actually, do remove ALL of them belonging to the part.
                    // Just in case there are stray values left after the part end.
                    //if(ev.tick() >= len)
                    //  break;

                    if (ev.type() == Controller)
                    {
                        int ch = mt->outChannel();
                        int tck = ev.tick() + p->tick();
                        int cntrl = ev.dataA();
                        MidiPort* mp = &midiPorts[port];

                        mp->deleteController(ch, tck, cntrl, p);
                    }
                }
            }

            if (!doClones)
                break;
            // Get the next clone in the chain ring.
            p = p->nextClone();
            // Same as original part? Finished.
            if (p == part)
                break;
        }
    }
}/*}}}*/
示例#7
0
文件: part.cpp 项目: ViktorNova/los
void chainCloneInternal(Part* p)/*{{{*/
{
    Track* t = p->track();
    Part* p1 = 0;

    // Look for a part with the same event list, that we can chain to.
    // It's faster if track type is known...

    {
        MidiTrack* mt = 0;
        MidiTrackList* mtl = song->midis();
        for (ciMidiTrack imt = mtl->begin(); imt != mtl->end(); ++imt)
        {
            mt = *imt;
            const PartList* pl = mt->cparts();
            for (ciPart ip = pl->begin(); ip != pl->end(); ++ip)
            {
                // Added by Tim. p3.3.6
                //printf("chainCloneInternal track %p %s part %p %s evlist %p\n", (*imt), (*imt)->name().toLatin1().constData(), ip->second, ip->second->name().toLatin1().constData(), ip->second->cevents());

                if (ip->second != p && ip->second->cevents() == p->cevents())
                {
                    p1 = ip->second;
                    break;
                }
            }
            // If a suitable part was found on a different track, we're done. We will chain to it.
            // Otherwise keep looking for parts on another track. If no others found, then we
            //  chain to any suitable part which was found on the same given track t.
            if (p1 && mt != t)
                break;
        }
    }

    // No part found with same event list? Done.
    if (!p1)
        return;

    // Make sure the part to be chained is unchained first.
    p->prevClone()->setNextClone(p->nextClone());
    p->nextClone()->setPrevClone(p->prevClone());

    // Link the part to be chained.
    p->setPrevClone(p1);
    p->setNextClone(p1->nextClone());

    // Re-link the existing part.
    p1->nextClone()->setPrevClone(p);
    p1->setNextClone(p);
}/*}}}*/
示例#8
0
void AbstractMidiEditor::writePartList(int level, Xml& xml) const/*{{{*/
{
    for (ciPart p = _pl->begin(); p != _pl->end(); ++p)
    {
        Part* part = p->second;
        MidiTrack* track = part->track();
        int trkIdx = song->artracks()->index(track);
        int partIdx = track->parts()->index(part);

        if ((trkIdx == -1) || (partIdx == -1))
            printf("AbstractMidiEditor::writePartList error: trkIdx:%d partIdx:%d\n", trkIdx, partIdx);

        xml.put(level, "<part>%d:%d</part>", trkIdx, partIdx);
    }
}/*}}}*/
示例#9
0
void LOS::importPart()
{
    unsigned curPos = song->cpos();
    MidiTrackList* tracks = song->tracks();
    MidiTrack* track = 0;
    // Get first selected track:
    for (iMidiTrack i = tracks->begin(); i != tracks->end(); i++)
    {
        MidiTrack* t = *i;
        if (t->selected())
        {
            // Changed by T356. Support mixed .mpt files.
            {
                track = t;
                break;
            }
        }
    }

    if (track)
    {
        bool loadAll;
        QString filename = getOpenFileName(QString(""), part_file_pattern, this, tr("LOS: load part"), &loadAll);
        if (!filename.isEmpty())
        {
            // Make a backup of the current clone list, to retain any 'copy' items,
            //  so that pasting works properly after.
            CloneList copyCloneList = cloneList;
            // Clear the clone list to prevent any dangerous associations with
            //  current non-original parts.
            cloneList.clear();

            importPartToTrack(filename, curPos, track);

            // Restore backup of the clone list, to retain any 'copy' items,
            //  so that pasting works properly after.
            cloneList.clear();
            cloneList = copyCloneList;
        }
    }
    else
    {
        QMessageBox::warning(this, QString("LOS"), tr("No track selected for import"));
    }
}
示例#10
0
void EventCanvas::populateMultiSelect(CItem* baseItem)/*{{{*/
{
    if(editor->isGlobalEdit() && baseItem)
    {
        PartList* pl = editor->parts();
        int curTranspose = ((MidiTrack*)baseItem->part()->track())->getTransposition();
        Event curEvent = baseItem->event();
        int curPitch = curEvent.pitch();
        int curRawPitch = curPitch - curTranspose;
        //int curLen = curEvent.lenTick();
        m_multiSelect.clear();
        for(iPart p = pl->begin(); p != pl->end(); ++p)
        {
            if(p->second == _curPart)
                continue;
            CItemList pitems = getItemlistForPart(p->second);
            for (iCItem i = pitems.begin(); i != pitems.end(); ++i)
            {
                MidiTrack* mtrack = (MidiTrack*)i->second->part()->track();
                int transp = mtrack->getTransposition();
                Event e = i->second->event();
                if(e.empty())
                    continue;
                int pitch = e.pitch();
                int rpitch = pitch - transp;
                //int len = e.lenTick();
                //printf("Current pitch: %d, rawpitch: %d - note pitch: %d, raw: %d\n", curPitch, curRawPitch, pitch, rpitch);
                if(e.tick() == curEvent.tick() && rpitch == curRawPitch/*, len == curLen*/)
                {
                    m_multiSelect.add(i->second);
                        break;
                }
            }
        }
        //printf("MultiSelect list size: %d \n", (int)m_multiSelect.size());
    }
}/*}}}*/
示例#11
0
void TrackListView::selectionChanged(const QModelIndex current, const QModelIndex)/*{{{*/
{
    if(!current.isValid())
        return;
    int row = current.row();
    m_selectedIndex = row;
    QStandardItem* item = m_model->item(row);
    if(item)
    {
        int type = item->data(TrackRole).toInt();
        qint64 tid = item->data(TrackIdRole).toLongLong();
        bool checked = (item->checkState() == Qt::Checked);
        //QString trackName = item->data(TrackNameRole).toString();
        MidiTrack* track = song->findTrackById(tid);
        if(!track || !m_editor || type == 1 || !checked)
            return;

        PartList* list = track->parts();
        int sn = item->data(PartRole).toInt();
        unsigned tick = item->data(TickRole).toInt();
        Part* part = list->find(tick, sn);
        updatePartSelection(part);
    }
}/*}}}*/
示例#12
0
文件: menulist.cpp 项目: faesong/oom
QWidget* MenuList::createWidget(QWidget* parent)
{
	if(!_track)
		return 0;
	//if(!_track->isMidiTrack() || _track->type() != Track::AUDIO_SOFTSYNTH)
	//	return 0;
	MidiTrack* track = (MidiTrack*) _track;

	MidiDevice* md = 0;
	int port = -1;
	if (track->type() == Track::AUDIO_SOFTSYNTH)
	{
		md = dynamic_cast<MidiDevice*> (track);
		if (md)
			port = md->midiPort();
	}
	else
		port = track->outPort();
	list = new QListWidget(parent);
	list->setSelectionMode(QAbstractItemView::SingleSelection);
	list->setAlternatingRowColors(true);
	list->setEditTriggers(QAbstractItemView::NoEditTriggers);
	list->setFixedHeight(300);
	for (int i = 0; i < MIDI_PORTS; ++i)
	{
		QString name;
		name.sprintf("%d:%s", i + 1, midiPorts[i].portname().toLatin1().constData());
		list->insertItem(i, name);
		if (i == port)
			list->setCurrentRow(i);
	}
	connect(list, SIGNAL(itemPressed(QListWidgetItem*)), this, SLOT(updateData(QListWidgetItem*)));
	//connect(list, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(updateData(QListWidgetItem*)));
	//connect(list, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(updateData(QListWidgetItem*)));
	return list;
}
示例#13
0
std::multimap<ReducedFraction, std::string>
extractLyricsFromTrack(const MidiTrack &lyricsTrack, int division)
      {
      std::multimap<ReducedFraction, std::string> lyrics;

      for (const auto &i: lyricsTrack.events()) {
            const auto& e = i.second;
            if (isLyricEvent(e)) {
                  const uchar* data = (uchar*)e.edata();
                  std::string text = MidiCharset::fromUchar(data);
                  if (isLyricText(text)) {
                        const auto tick = toMuseScoreTicks(i.first, division);
                                    // no charset handling here
                        lyrics.insert({tick, text});
                        }
                  }
            }
      return lyrics;
      }
bool isLyricsTrack(const MidiTrack &lyricsTrack)
      {
      bool lyricsFlag = false;

      for (const auto &i: lyricsTrack.events()) {
            const auto& e = i.second;
            if (isLyricEvent(e)) {
                  const uchar* data = (uchar*)e.edata();
                              // no charset handling here
                  std::string text = MidiCharset::fromUchar(data);
                  if (isLyricText(text)) {
                        if (!lyricsFlag)
                              lyricsFlag = true;
                        }
                  }
            else if (e.type() == ME_NOTE)
                  return false;
            }

      return lyricsFlag;
      }
示例#15
0
MidiTrack MidiTrack::ReadFromStream(std::istream &stream)
{
   // Verify the track header
   const static string MidiTrackHeader = "MTrk";

   // I could use (MidiTrackHeader.length() + 1), but then this has to be
   // dynamically allocated.  More hassle than it's worth.  MIDI is well
   // defined and will always have a 4-byte header.  We use 5 so we get
   // free null termination.
   char header_id[5] = { 0, 0, 0, 0, 0 };
   unsigned long track_length;

   stream.read(header_id, static_cast<streamsize>(MidiTrackHeader.length()));
   stream.read(reinterpret_cast<char*>(&track_length), sizeof(unsigned long));

   if (stream.fail()) throw MidiError(MidiError_TrackHeaderTooShort);

   string header(header_id);
   if (header != MidiTrackHeader) throw MidiError_BadTrackHeaderType;

   // Pull the full track out of the file all at once -- there is an
   // End-Of-Track event, but this allows us handle malformed MIDI a
   // little more gracefully.
   track_length = BigToSystem32(track_length);
   char *buffer = new char[track_length + 1];
   buffer[track_length] = 0;

   stream.read(buffer, track_length);
   if (stream.fail())
   {
      delete[] buffer;
      throw MidiError(MidiError_TrackTooShort);
   }

   // We have to jump through a couple hoops because istringstream
   // can't handle binary data unless constructed through an std::string. 
   string buffer_string(buffer, track_length);
   istringstream event_stream(buffer_string, ios::binary);
   delete[] buffer;

   MidiTrack t;

   // Read events until we run out of track
   char last_status = 0;
   unsigned long current_pulse_count = 0;
   while (event_stream.peek() != char_traits<char>::eof())
   {
      MidiEvent ev = MidiEvent::ReadFromStream(event_stream, last_status); 
      last_status = ev.StatusCode();
      
      t.m_events.push_back(ev);

      current_pulse_count += ev.GetDeltaPulses();
      t.m_event_pulses.push_back(current_pulse_count);
   }

   t.BuildNoteSet();
   t.DiscoverInstrument();

   return t;
}
示例#16
0
void EventCanvas::viewMousePressEvent(QMouseEvent* event)/*{{{*/
{
    ///keyState = event->state();
    _keyState = ((QInputEvent*) event)->modifiers();
    _button = event->button();

    //printf("viewMousePressEvent buttons:%x mods:%x button:%x\n", (int)event->buttons(), (int)keyState, event->button());

    // special events if right button is clicked while operations
    // like moving or drawing lasso is performed.
    if (event->buttons() & Qt::RightButton & ~(event->button()))
    {
        //printf("viewMousePressEvent special buttons:%x mods:%x button:%x\n", (int)event->buttons(), (int)keyState, event->button());
        switch (_drag)
        {
        case DRAG_LASSO:
            _drag = DRAG_OFF;
            redraw();
            return;
        case DRAG_MOVE:
            _drag = DRAG_OFF;
            endMoveItems(_start, MOVE_MOVE, 0);
            return;
        default:
            break;
        }
    }

    // ignore event if (another) button is already active:
    if (event->buttons() & (Qt::LeftButton | Qt::RightButton | Qt::MidButton) & ~(event->button()))
    {
        //printf("viewMousePressEvent ignoring buttons:%x mods:%x button:%x\n", (int)event->buttons(), (int)keyState, event->button());
        return;
    }
    bool shift = _keyState & Qt::ShiftModifier;
    bool alt = _keyState & Qt::AltModifier;
    bool ctrl = _keyState & Qt::ControlModifier;
    _start = event->pos();

    //---------------------------------------------------
    //    set curItem to item mouse is pointing
    //    (if any)
    //---------------------------------------------------

    CItemList list = _items;
    if(multiPartSelectionAction && !multiPartSelectionAction->isChecked())
        list = getItemlistForCurrentPart();
    if (virt())
    {
        _curItem = list.find(_start);//_items.find(_start);
    }
    else
    {
        _curItem = 0; //selectAtTick(_start.x());
        iCItem ius;
        bool usfound = false;
        for (iCItem i = list.begin(); i != list.end(); ++i)
        {
            MidiTrack* mtrack = (MidiTrack*)i->second->part()->track();
            int sy = _start.y();
            int p = y2pitch(sy);
            if(editor->isGlobalEdit())
                p += mtrack->getTransposition();
            int p2 = pitch2y(p);
            QPoint lpos(_start.x(), p2);
            QRect box = i->second->bbox();
            int x = rmapxDev(box.x());
            int y = rmapyDev(box.y());
            int w = rmapxDev(box.width());
            int h = rmapyDev(box.height());
            QRect r(x, y, w, h);
            r.translate(i->second->pos().x(), i->second->pos().y());
            if(r.contains(lpos))
            {
                if (i->second->isSelected())
                {
                    _curItem = i->second;
                    break;
                }
                else if (!usfound)
                {
                    ius = i;
                    usfound = true;
                }
            }
        }
        if (!_curItem && usfound)
            _curItem = ius->second;

    }

    if(editor->isGlobalEdit() && _curItem)
    {
        populateMultiSelect(_curItem);
    }

    if (_curItem && (event->button() == Qt::MidButton))
    {
        if (!_curItem->isSelected())
        {
            selectItem(_curItem, true);
            updateSelection();
            redraw();
        }
        startDrag(_curItem, shift);
    }
    else if (event->button() == Qt::RightButton)
    {
        if (_curItem)
        {
            if (shift)
            {
                _drag = DRAG_RESIZE;
                setCursor();
                int dx = _start.x() - _curItem->x();
                _curItem->setWidth(dx);
                _start.setX(_curItem->x());
                deselectAll();
                selectItem(_curItem, true);
                updateSelection();
                redraw();
            }
            else
            {
                _itemPopupMenu = genItemPopup(_curItem);
                if (_itemPopupMenu)
                {
                    QAction *act = _itemPopupMenu->exec(QCursor::pos());
                    if (act)
                        itemPopup(_curItem, act->data().toInt(), _start);
                    delete _itemPopupMenu;
                }
            }
        }
        else
        {
            _canvasPopupMenu = genCanvasPopup(true);
            if (_canvasPopupMenu)
            {
                QAction *act = _canvasPopupMenu->exec(QCursor::pos(), 0);
                if (act)
                {
                    int actnum = act->data().toInt();
                    canvasPopup(actnum);
                    if(actnum >= 20) //Nome of the tools have a higher number than 9
                    {
                        editor->updateCanvas();
                        los->arranger->updateCanvas();
                    }
                }
                delete _canvasPopupMenu;
            }
        }
    }
    else if (event->button() == Qt::LeftButton)
    {
        switch (_tool)
        {
        case PointerTool:
            if (_curItem)
            {
                /*if (_curItem->part() != _curPart)
                {
                    _curPart = _curItem->part();
                    _curPartId = _curPart->sn();
                    curPartChanged();
                }*/
                itemPressed(_curItem);
                if (shift)
                    _drag = DRAG_COPY_START;
                else if (alt)
                {
                    _drag = DRAG_CLONE_START;
                }
                else if (ctrl)
                { //Select all on the same pitch (e.g. same y-value)
                    deselectAll();
                    //printf("Yes, ctrl and press\n");
                    for (iCItem i = _items.begin(); i != _items.end(); ++i)
                    {
                        if (i->second->y() == _curItem->y())
                            selectItem(i->second, true);
                    }
                    updateSelection();
                    redraw();
                }
                else
                    _drag = DRAG_MOVE_START;
            }
            else
                _drag = DRAG_LASSO_START;
            setCursor();
            break;

            case RubberTool:
            deleteItem(_start);
            _drag = DRAG_DELETE;
            setCursor();
            break;

            case PencilTool:
            if (_curItem)
            {
                _drag = DRAG_RESIZE;
                setCursor();
                int dx = _start.x() - _curItem->x();
                _curItem->setWidth(dx);
                _start.setX(_curItem->x());
            }
            else
            {
                _drag = DRAG_NEW;
                setCursor();
                _curItem = newItem(_start, event->modifiers());
                if (_curItem)
                    _items.add(_curItem);
                else
                {
                    _drag = DRAG_OFF;
                    setCursor();
                }
            }
            deselectAll();
            if (_curItem)
            {
                selectItem(_curItem, true);
                // Play the note
                itemPressed(_curItem);
            }
            updateSelection();
            redraw();
            break;

            default:
            break;
        }
    }
    mousePress(event);
}/*}}}*/
示例#17
0
文件: midi.cpp 项目: faesong/oom
void Audio::processMidi()
{
	midiBusy = true;
	//
	// TODO: syntis should directly write into recordEventList
	//
	for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
	{
		MidiDevice* md = *id;

		MPEventList* playEvents = md->playEvents();
		//
		// erase already played events:
		//
		iMPEvent nextPlayEvent = md->nextPlayEvent();
		playEvents->erase(playEvents->begin(), nextPlayEvent);

		// klumsy hack for synti devices:
		if (md->isSynti())
		{
			SynthI* s = (SynthI*) md;
			while (s->eventsPending())
			{
				MidiRecordEvent ev = s->receiveEvent();
				md->recordEvent(ev);
			}
		}

		// Is it a Jack midi device?
		//MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
		//if(mjd)
		//  mjd->collectMidiEvents();
		md->collectMidiEvents();

		// Take snapshots of the current sizes of the recording fifos,
		//  because they may change while here in process, asynchronously.
		md->beforeProcess();
	}

	MPEventList* playEvents = metronome->playEvents();
	iMPEvent nextPlayEvent = metronome->nextPlayEvent();
	playEvents->erase(playEvents->begin(), nextPlayEvent);

	// p3.3.25
	bool extsync = extSyncFlag.value();

	for (iMidiTrack t = song->midis()->begin(); t != song->midis()->end(); ++t)
	{
		MidiTrack* track = *t;
		int port = track->outPort();
		MidiDevice* md = midiPorts[port].device();

		// Changed by Tim. p3.3.8
		//if(md == 0)
		//  continue;
		//MPEventList* playEvents = md->playEvents();
		//if (playEvents == 0)
		//    continue;
		//if (!track->isMute())
		MPEventList* playEvents = 0;
		if (md)
		{
			playEvents = md->playEvents();

			// only add track events if the track is unmuted
			if (!track->isMute())
			{
				if (isPlaying() && (curTickPos < nextTickPos))
					collectEvents(track, curTickPos, nextTickPos);
			}
		}

		//
		//----------midi recording
		//
		if (track->recordFlag())
		{
			//int portMask    = track->inPortMask();
			// p3.3.38 Removed
			//unsigned int portMask = track->inPortMask();
			//int channelMask = track->inChannelMask();

			MPEventList* rl = track->mpevents();
			MidiPort* tport = &midiPorts[port];

			// p3.3.38
			//for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
			//{
			RouteList* irl = track->inRoutes();
			for (ciRoute r = irl->begin(); r != irl->end(); ++r)
			{
				//if(!r->isValid() || (r->type != Route::ALSA_MIDI_ROUTE && r->type != Route::JACK_MIDI_ROUTE))
				//if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE))
				if (!r->isValid() || (r->type != Route::MIDI_PORT_ROUTE)) // p3.3.49
					continue;

				int devport = r->midiPort; // p3.3.49
				if (devport == -1)
					continue;

				//MidiDevice* dev = *id;
				//MidiDevice* dev = r->device;
				MidiDevice* dev = midiPorts[devport].device(); // p3.3.49
				if (!dev)
					continue;


				// p3.3.50 Removed
				//int channel = r->channel;
				// NOTE: TODO: Special for input device sysex 'channel' marked as -1, ** IF we end up going with that method **.
				// This would mean having a separate 'System' channel listed in the routing popups.
				// The other alternative is to accept sysex from a device as long as ANY regular channel is routed from it,
				//  this does not require a 'System' channel listed in the routing popups.
				// But that requires more code below... Done.
				//if(channel == -1)
				//channel = MIDI_CHANNELS; // Special channel '17'
				//  continue;

				//int devport = dev->midiPort();

				// record only from ports marked in portMask:
				//if (devport == -1 || !(portMask & (1 << devport)))
				//if (devport == -1)
				//      continue;

				//MREventList* el = dev->recordEvents();
				//MidiFifo& rf = dev->recordEvents();


				int channelMask = r->channel; // p3.3.50
				if (channelMask == -1 || channelMask == 0)
					continue;
				for (int channel = 0; channel < MIDI_CHANNELS; ++channel) // p3.3.50
				{
					if (!(channelMask & (1 << channel)))
						continue;

					if (!dev->sysexFIFOProcessed())
					{
						// Set to the sysex fifo at first.
						MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS);
						// Get the frozen snapshot of the size.
						int count = dev->tmpRecordCount(MIDI_CHANNELS);

						for (int i = 0; i < count; ++i)
						{
							MidiPlayEvent event(rf.peek(i));

							//unsigned time = event.time() + segmentSize*(segmentCount-1);
							//unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1));
							//unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1));
							//event.setTime(time);
							//if(!extsync)
							//  event.setTime(event.time() + segmentSize*(segmentCount-1));

							event.setPort(port);

							// dont't echo controller changes back to software
							// synthesizer:
							if (!dev->isSynti() && md && track->recEcho())
								playEvents->add(event);

							// If syncing externally the event time is already in units of ticks, set above.
							if (!extsync)
							{
								//time = tempomap.frame2tick(event.time());
								//event.setTime(time);  // set tick time
								event.setTime(tempomap.frame2tick(event.time())); // set tick time
							}

							if (recording)
								rl->add(event);
						}

						dev->setSysexFIFOProcessed(true);
					}

					// Set to the sysex fifo at first.
					///MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS);
					// Get the frozen snapshot of the size.
					///int count = dev->tmpRecordCount(MIDI_CHANNELS);

					// Iterate once for sysex fifo (if needed), once for channel fifos.
					///for(int sei = 0; sei < 2; ++sei)
					{
						// If on first pass, do sysex fifo.
						/*
						if(sei == 0)
						{
						  // Ignore any further channel routes on this device if already done here.
						  if(dev->sysexFIFOProcessed())
							continue;
						  // Go ahead and set this now.
						  dev->setSysexFIFOProcessed(true);
						  // Allow it to fall through with the sysex fifo and count...
						}
						else
						{
						  // We're on the second pass, do channel fifos.
						  rf = dev->recordEvents(channel);
						  // Get the frozen snapshot of the size.
						  count = dev->tmpRecordCount(channel);
						}
						 */

						MidiFifo& rf = dev->recordEvents(channel);
						int count = dev->tmpRecordCount(channel);

						//for (iMREvent ie = el->begin(); ie != el->end(); ++ie)
						for (int i = 0; i < count; ++i)
						{
							MidiPlayEvent event(rf.peek(i));

							//int channel = ie->channel();
							///int channel = event.channel();

							int defaultPort = devport;
							///if (!(channelMask & (1 << channel)))
							///{
							///      continue;
							///}

							//MidiPlayEvent event(*ie);
							int drumRecPitch = 0; //prevent compiler warning: variable used without initialization
							MidiController *mc = 0;
							int ctl = 0;

							//Hmmm, hehhh...
							// TODO: Clean up a bit around here when it comes to separate events for rec & for playback.
							// But not before 0.7 (ml)

							int prePitch = 0, preVelo = 0;

							event.setChannel(track->outChannel());

							if (event.isNote() || event.isNoteOff())
							{
								//
								// apply track values
								//

								//Apply drum inkey:
								if (track->type() == Track::DRUM)
								{
									int pitch = event.dataA();
									//Map note that is played according to drumInmap
									drumRecPitch = drumMap[(unsigned int) drumInmap[pitch]].enote;
									devport = drumMap[(unsigned int) drumInmap[pitch]].port;
									event.setPort(devport);
									channel = drumMap[(unsigned int) drumInmap[pitch]].channel;
									event.setA(drumMap[(unsigned int) drumInmap[pitch]].anote);
									event.setChannel(channel);
								}
								else
								{ //Track transpose if non-drum
									prePitch = event.dataA();
									int pitch = prePitch + track->transposition;
									if (pitch > 127)
										pitch = 127;
									if (pitch < 0)
										pitch = 0;
									event.setA(pitch);
								}

								if (!event.isNoteOff())
								{
									preVelo = event.dataB();
									int velo = preVelo + track->velocity;
									velo = (velo * track->compression) / 100;
									if (velo > 127)
										velo = 127;
									if (velo < 1)
										velo = 1;
									event.setB(velo);
								}
							}
								// Added by T356.
							else if (event.type() == ME_CONTROLLER)
							{
								//printf("11111111111111111111111111111111111111111111111111111\n");
								if (track->type() == Track::DRUM)
								{
									//printf("2222222222222222222222222222222222222222222222222222222222\n");
									ctl = event.dataA();
									// Regardless of what port the event came from, is it a drum controller event
									//  according to the track port's instrument?
									mc = tport->drumController(ctl);
									if (mc)
									{

										//printf("333333333333333333333333333333333333333333333333\n");
										int pitch = ctl & 0x7f;
										ctl &= ~0xff;
										int dmindex = drumInmap[pitch] & 0x7f;
										//Map note that is played according to drumInmap
										drumRecPitch = drumMap[dmindex].enote;
										devport = drumMap[dmindex].port;
										event.setPort(devport);
										channel = drumMap[dmindex].channel;
										event.setA(ctl | drumMap[dmindex].anote);
										event.setChannel(channel);
									}
								}
							}

							// p3.3.25
							// OOMidi uses a fixed clocks per quarternote of 24.
							// At standard 384 ticks per quarternote for example,
							// 384/24=16 for a division of 16 sub-frames (16 OOMidi 'ticks').
							// That is what we'll use if syncing externally.
							//unsigned time = event.time() + segmentSize*(segmentCount-1);
							//unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1));
							// p3.3.34
							// Oops, use the current tick.
							//unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1));
							//event.setTime(time);
							// p3.3.35
							// If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent().
							// TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice.
							// p3.3.36
							//if(!extsync)
							//  event.setTime(event.time() + segmentSize*(segmentCount-1));

							// dont't echo controller changes back to software
							// synthesizer:

							if (!dev->isSynti())
							{
								//printf("444444444444444444444444444444444444444444444444444444\n");
								//Check if we're outputting to another port than default:
								if (devport == defaultPort)
								{

									//printf("5555555555555555555555555555555555555555555\n");
									event.setPort(port);
									if (md && track->recEcho())
										playEvents->add(event);
								}
								else
								{
									//printf("66666666666666666666666666666666666666\n");
									// Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent??
									MidiDevice* mdAlt = midiPorts[devport].device();
									if (mdAlt && track->recEcho())
										mdAlt->playEvents()->add(event);
								}
								// Shall we activate meters even while rec echo is off? Sure, why not...
								if (event.isNote() && event.dataB() > track->activity())
									track->setActivity(event.dataB());
							}

							// p3.3.25
							// If syncing externally the event time is already in units of ticks, set above.
							if (!extsync)
							{
								//printf("7777777777777777777777777777777777777777777\n");
								// p3.3.35
								//time = tempomap.frame2tick(event.time());
								//event.setTime(time);  // set tick time
								event.setTime(tempomap.frame2tick(event.time())); // set tick time
							}

							// Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml)
							if (recording)
							{
								//printf("888888888888888888888888888888888888888888888888\n");
								// In these next steps, it is essential to set the recorded event's port
								//  to the track port so buildMidiEventList will accept it. Even though
								//  the port may have no device "<none>".
								//
								if (track->type() == Track::DRUM)
								{
									//printf("99999999999999999999999999999999999999999999999999\n");
									// Is it a drum controller event?
									if (mc)
									{
										//printf("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
										MidiPlayEvent drumRecEvent = event;
										drumRecEvent.setA(ctl | drumRecPitch);
										// In this case, preVelo is simply the controller value.
										drumRecEvent.setB(preVelo);
										drumRecEvent.setPort(port); //rec-event to current port
										drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
										rl->add(drumRecEvent);
									}
									else
									{
										//printf("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n");

										MidiPlayEvent drumRecEvent = event;
										drumRecEvent.setA(drumRecPitch);
										drumRecEvent.setB(preVelo);
										// Changed by T356.
										// Tested: Events were not being recorded for a drum map entry pointing to a
										//  different port. This must have been wrong - buildMidiEventList would ignore this.
										//drumRecEvent.setPort(devport);
										drumRecEvent.setPort(port); //rec-event to current port

										drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
										rl->add(drumRecEvent);
									}
								}
								else
								{
									//printf("ccccccccccccccccccccccccccccccccccccccccccccc\n");
									// Restore record-pitch to non-transposed value since we don't want the note transposed twice next
									MidiPlayEvent recEvent = event;
									if (prePitch)
										recEvent.setA(prePitch);
									if (preVelo)
										recEvent.setB(preVelo);
									recEvent.setPort(port);
									recEvent.setChannel(track->outChannel());

									rl->add(recEvent);
								}
							}
						}
					}
				}
			}
		}
		// Added by Tim. p3.3.8
		if (md)
		{
			//printf("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\n");

			md->setNextPlayEvent(playEvents->begin());
		}
	}

	//
	// clear all recorded events in midiDevices
	// process stuck notes
	//
	for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
	{
		//printf("--------------------------aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
		MidiDevice* md = *id;

		///md->recordEvents()->clear();
		// By T356. Done processing this rec buffer, now flip to the other one.
		///md->flipRecBuffer();
		// We are done with the 'frozen' recording fifos, remove the events.
		md->afterProcess();

		MPEventList* stuckNotes = md->stuckNotes();
		MPEventList* playEvents = md->playEvents();

		iMPEvent k;
		for (k = stuckNotes->begin(); k != stuckNotes->end(); ++k)
		{
			if (k->time() >= nextTickPos)
				break;
			MidiPlayEvent ev(*k);

			// p3.3.25
			//int frame = tempomap.tick2frame(k->time()) + frameOffset;
			if (extsync)
			{
				ev.setTime(k->time());
			}
			else
			{
				int frame = tempomap.tick2frame(k->time()) + frameOffset;
				ev.setTime(frame);
			}

			// p3.3.25
			//ev.setTime(frame);

			playEvents->add(ev);
		}
		stuckNotes->erase(stuckNotes->begin(), k);
		md->setNextPlayEvent(playEvents->begin());
	}

	//---------------------------------------------------
	//    insert metronome clicks
	//---------------------------------------------------

	MidiDevice* md = 0;
	if (midiClickFlag)
		md = midiPorts[clickPort].device();
	if (song->click() && (isPlaying() || state == PRECOUNT))
	{
		MPEventList* playEvents = 0;
		MPEventList* stuckNotes = 0;
		if (md)
		{
			playEvents = md->playEvents();
			stuckNotes = md->stuckNotes();
		}
		int bar, beat;
		unsigned tick;
		bool isMeasure = false;
		while (midiClick < nextTickPos)
		{
			if (isPlaying())
			{
				///sigmap.tickValues(midiClick, &bar, &beat, &tick);
				AL::sigmap.tickValues(midiClick, &bar, &beat, &tick);
				isMeasure = beat == 0;
			}
			else if (state == PRECOUNT)
			{
				isMeasure = (clickno % clicksMeasure) == 0;
			}
			// p3.3.25
			//int frame = tempomap.tick2frame(midiClick) + frameOffset;
			int evtime = extsync ? midiClick : tempomap.tick2frame(midiClick) + frameOffset;

			// p3.3.25
			//MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON,
			MidiPlayEvent ev(evtime, clickPort, clickChan, ME_NOTEON,
					beatClickNote, beatClickVelo);

			if (md)
			{
				// p3.3.25
				//MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON,
				MidiPlayEvent ev(evtime, clickPort, clickChan, ME_NOTEON,
						beatClickNote, beatClickVelo);

				if (isMeasure)
				{
					ev.setA(measureClickNote);
					ev.setB(measureClickVelo);
				}
				playEvents->add(ev);
			}
			if (audioClickFlag)
			{
				// p3.3.25
				//MidiPlayEvent ev1(frame, 0, 0, ME_NOTEON, 0, 0);
				MidiPlayEvent ev1(evtime, 0, 0, ME_NOTEON, 0, 0);

				ev1.setA(isMeasure ? 0 : 1);
				metronome->playEvents()->add(ev1);
			}
			if (md)
			{
				ev.setB(0);
				// p3.3.25
				// Removed. Why was this here?
				//frame = tempomap.tick2frame(midiClick+20) + frameOffset;
				//
				// Does it mean this should be changed too?
				// No, stuck notes are in units of ticks, not frames like (normal, non-external) play events...
				ev.setTime(midiClick + 10);

				if (md)
					stuckNotes->add(ev);
			}

			if (isPlaying())
				///midiClick = sigmap.bar2tick(bar, beat+1, 0);
				midiClick = AL::sigmap.bar2tick(bar, beat + 1, 0);
			else if (state == PRECOUNT)
			{
				midiClick += ticksBeat;
				if (clickno)
					--clickno;
				else
					state = START_PLAY;
			}
		}
		if (md)
			md->setNextPlayEvent(playEvents->begin());
		if (audioClickFlag)
			metronome->setNextPlayEvent(metronome->playEvents()->begin());
	}

	if (state == STOP)
	{
		//---------------------------------------------------
		//    end all notes
		//---------------------------------------------------

		for (iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
		{
			MidiDevice* md = *imd;
			MPEventList* playEvents = md->playEvents();
			MPEventList* stuckNotes = md->stuckNotes();
			for (iMPEvent k = stuckNotes->begin(); k != stuckNotes->end(); ++k)
			{
				MidiPlayEvent ev(*k);
				ev.setTime(0); // play now
				playEvents->add(ev);
			}
			stuckNotes->clear();
		}
	}


	// p3.3.36
	//int tickpos = audio->tickPos();
	//bool extsync = extSyncFlag.value();
	//
	// Special for Jack midi devices: Play all Jack midi events up to curFrame.
	//
	for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
	{
		(*id)->processMidi();

		/*
		int port = md->midiPort();
		MidiPort* mp = port != -1 ? &midiPorts[port] : 0;
		MPEventList* el = md->playEvents();
		if (el->empty())
			  continue;
		iMPEvent i = md->nextPlayEvent();
		for(; i != el->end(); ++i)
		{
		  // 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(i->time() > curFrame)
		  if(i->time() > (extsync ? tickpos : curFrame))
		  {
			//printf("  curT %d  frame %d\n", i->time(), curFrame);
			break; // skip this event
		  }

		  if(mp)
		  {
			if(mp->sendEvent(*i))
			  break;
		  }
		  else
		  {
			if(md->putEvent(*i))
			  break;
		  }
		}
		md->setNextPlayEvent(i);
		 */
	}

	midiBusy = false;
}
示例#18
0
bool QSoundSeq::PostLoad()
{
	if (readMode != READMODE_CONVERT_TO_MIDI)
		return true;

	// We need to add pitch bend events for vibrato, which is controlled by a software LFO
	//  This is actually a bit tricky because the LFO is running independent of the sequence
	//  tempo.  It gets updated (251/4) times a second, always.  We will have to convert 
	//  ticks in our sequence into absolute elapsed time, which means we also need to keep
	//  track of any tempo events that change the absolute time per tick.
	vector<MidiEvent*> tempoEvents;
	vector<MidiTrack*>& miditracks = midi->aTracks;

	// First get all tempo events, we assume they occur on track 1
	for (unsigned int i = 0; i < miditracks[0]->aEvents.size(); i++)
	{
		MidiEvent* event = miditracks[0]->aEvents[i];
		if (event->GetEventType() == MIDIEVENT_TEMPO)
			tempoEvents.push_back(event);
	}

	// Now for each track, gather all vibrato events, lfo events, pitch bend events and track end events
	for (unsigned int i = 0; i < miditracks.size(); i++)
	{
		vector<MidiEvent*> events(tempoEvents);
		MidiTrack* track = miditracks[i];
		int channel = this->aTracks[i]->channel;

		for (unsigned int j = 0; j < track->aEvents.size(); j++)
		{
			MidiEvent* event = miditracks[i]->aEvents[j];
			MidiEventType type = event->GetEventType();
			if (type == MIDIEVENT_MARKER || type == MIDIEVENT_PITCHBEND || type == MIDIEVENT_ENDOFTRACK)
				events.push_back(event);
		}
		// We need to sort by priority so that vibrato events get ordered correctly.  Since they cause the
		//  pitch bend range to be set, they need to occur before pitchbend events.
		stable_sort(events.begin(), events.end(), PriorityCmp());	//Sort all the events by priority
		stable_sort(events.begin(), events.end(), AbsTimeCmp());	//Sort all the events by absolute time, so that delta times can be recorded correctly
		

		// And now we actually add vibrato and pitch bend events
		const uint32_t ppqn = GetPPQN();					// pulses (ticks) per quarter note
		const uint32_t mpLFOt = (uint32_t)((1/(251/4.0)) * 1000000);	// microseconds per LFO tick
		uint32_t mpqn = 500000;							// microseconds per quarter note - 120 bpm default
		uint32_t mpt = mpqn / ppqn;						// microseconds per MIDI tick
		short pitchbend = 0;							// pitch bend in cents
		int pitchbendRange = 200;						// pitch bend range in cents default 2 semitones
		double vibrato = 0;								// vibrato depth in cents
		uint16_t tremelo = 0;								// tremelo depth.  we divide this value by 0x10000 to get percent amplitude attenuation
		uint16_t lfoRate = 0;								// value added to lfo env every lfo tick
		uint32_t lfoVal = 0;									// LFO envelope value. 0 - 0xFFFFFF .  Effective envelope range is -0x1000000 to +0x1000000
		int lfoStage = 0;								// 0 = rising from mid, 1 = falling from peak, 2 = falling from mid 3 = rising from bottom
		short lfoCents = 0;								// cents adjustment from most recent LFO val excluding pitchbend.
		long effectiveLfoVal = 0;
		//bool bLfoRising = true;;						// is LFO rising or falling?
		
		uint32_t startAbsTicks = 0;							// The MIDI tick time to start from for a given vibrato segment

		size_t numEvents = events.size();
		for (size_t j = 0; j < numEvents; j++)
		{
			MidiEvent* event = events[j];
			uint32_t curTicks = event->AbsTime;			//current absolute ticks
			
			if (curTicks > 0 /*&& (vibrato > 0 || tremelo > 0)*/ && startAbsTicks < curTicks)
			{
				// if we're starting a fresh vibrato segment, let's start the LFO env at 0 and set it to rise
				/*if (prevVibrato == 0 && prevTremelo == 0)
				{
					lfoVal = 0;
					lfoStage = 0;
				}*/
				
				long segmentDurTicks = curTicks - startAbsTicks;
				double segmentDur = segmentDurTicks * mpt;	// duration of this segment in micros
				double lfoTicks = segmentDur / (double)mpLFOt;
				double numLfoPhases = (lfoTicks * (double)lfoRate) / (double)0x20000;
				//double midiTicksPerPhase = (curTicks-startAbsTicks) / numLfoPhases;
				//double centsPerMidiTick = vibrato / midiTicksPerPhase;
				double lfoRatePerMidiTick = (numLfoPhases * 0x20000) / (double)segmentDurTicks;

				const uint8_t tickRes = 16;
				uint32_t lfoRatePerLoop = (uint32_t)((tickRes * lfoRatePerMidiTick) * 256);

				for (int t = 0; t < segmentDurTicks; t += tickRes)
				{
					lfoVal += lfoRatePerLoop;
					if (lfoVal > 0xFFFFFF)
					{
						lfoVal -= 0x1000000;
						lfoStage = (lfoStage+1) % 4;
					}
					effectiveLfoVal = lfoVal;
					if (lfoStage == 1)
						effectiveLfoVal = 0x1000000 - lfoVal;
					else if (lfoStage == 2)
						effectiveLfoVal = -((long)lfoVal);
					else if (lfoStage == 3)
						effectiveLfoVal = -0x1000000 + lfoVal;

					double lfoPercent = (effectiveLfoVal / (double)0x1000000);

					if (vibrato > 0)
					{
						lfoCents = (short)(lfoPercent * vibrato);
						track->InsertPitchBend(channel, (short)(((lfoCents + pitchbend) / (double)pitchbendRange) * 8192), startAbsTicks + t);
					}

					if (tremelo > 0)
					{
						uint8_t expression = ConvertPercentAmpToStdMidiVal((0x10000 - (tremelo*abs(lfoPercent))) / (double)0x10000);
						track->InsertExpression(channel, expression, startAbsTicks + t);
					}
				}
				// TODO add adjustment for segmentDurTicks % tickRes						
			}


			switch(event->GetEventType())
			{
			case MIDIEVENT_TEMPO:
				{
					TempoEvent* tempoevent = (TempoEvent*)event;
					mpqn = tempoevent->microSecs;
					mpt = mpqn / ppqn;
				}
				break;
			case MIDIEVENT_ENDOFTRACK:

				break;
			case MIDIEVENT_MARKER:
				{
					MarkerEvent* marker = (MarkerEvent*)event;
					if (marker->name == "vibrato")
					{
						vibrato = vibrato_depth_table[marker->databyte1] * (100/256.0);
						//pitchbendRange = max(200, (vibrato + 50));		//50 cents to allow for pitchbend values, which range -50/+50
						pitchbendRange = (int)max(200, ceil((vibrato+50)/100.0)*100);	//+50 cents to allow for pitchbend values, which range -50/+50
						track->InsertPitchBendRange(channel, pitchbendRange/100, pitchbendRange%100, curTicks);
						
						lfoCents = (short)((effectiveLfoVal / (double)0x1000000) * vibrato);
						
						if (curTicks > 0)
							track->InsertPitchBend(channel, (short)(((lfoCents + pitchbend) / (double)pitchbendRange) * 8192), curTicks);
					}
					else if (marker->name == "tremelo")
					{
						tremelo = tremelo_depth_table[marker->databyte1];
						if (tremelo == 0)
							track->InsertExpression(channel, 127, curTicks);
					}
					else if (marker->name == "lfo")
					{
						lfoRate = lfo_rate_table[marker->databyte1];
					}
					else if (marker->name == "resetlfo")
					{
						if (marker->databyte1 != 1)
							break;
						lfoVal = 0;
						effectiveLfoVal = 0;
						lfoStage = 0;
						lfoCents = 0;
						if (vibrato > 0)
							track->InsertPitchBend(channel, (short)(((0 + pitchbend) / (double)pitchbendRange) * 8192), curTicks);
						if (tremelo > 0)
							track->InsertExpression(channel, 127, curTicks);
					}
					else if (marker->name == "pitchbend")
					{
						pitchbend = (short)(((char)marker->databyte1 / 256.0) * 100);
						//stringstream stream;
						//stream << "cents: " << cents << "  finalval: " <<  (cents / (double)pitchbendRange) * 8192 << "\n";
						//ATLTRACE(stream.str().c_str());
						track->InsertPitchBend(channel, (short)(((lfoCents + pitchbend) / (double)pitchbendRange) * 8192), curTicks);
					}
				}
				break;
			}
			startAbsTicks = curTicks;

		}
	}

	

	return VGMSeq::PostLoad();
}
示例#19
0
bool LOS::importMidi(const QString name, bool merge)/*{{{*/
{
    bool popenFlag;
    FILE* fp = fileOpen(this, name, QString(".mid"), "r", popenFlag);
    if (fp == 0)
        return true;
    MidiFile mf(fp);
    bool rv = mf.read();
    popenFlag ? pclose(fp) : fclose(fp);
    if (rv)
    {
        QString s(tr("reading midifile\n  "));
        s += name;
        s += tr("\nfailed: ");
        s += mf.error();
        QMessageBox::critical(this, QString("LOS"), s);
        return rv;
    }
    //
    //  evaluate song Type (GM, XG, GS, unknown)
    //
    MType t = song->midiType();
    if (!merge)
    {
        t = mf.mtype();
        song->setMType(t);
    }
    MidiInstrument* instr = 0;
    for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i)
    {
        MidiInstrument* mi = *i;
        if ((mi->iname() == "GM" && ((t == MT_UNKNOWN) || (t == MIDI_TYPE_GM)))
                || ((mi->iname() == "GS") && (t == MT_GS))
                || ((mi->iname() == "XG") && (t == MT_XG)))
        {
            instr = mi;
            break;
        }
    }
    if (instr == 0)
    {
        // the standard instrument files (GM, GS, XG) must be present
        printf("no instrument, type %d\n", t);
        return true;
        //abort();
    }

    MidiFileTrackList* etl = mf.trackList();
    int division = mf.division();

    //
    // create MidiTrack and copy events to ->events()
    //    - combine note on/off events
    //    - calculate tick value for internal resolution
    //
    for (iMidiFileTrack t = etl->begin(); t != etl->end(); ++t)
    {
        MPEventList* el = &((*t)->events);
        if (el->empty())
            continue;
        //
        // if we split the track, SYSEX and META events go into
        // the first target track

        bool first = true;
        // somewhat silly and slooow:
        for (int port = 0; port < kMaxMidiPorts; ++port)
        {
            for (int channel = 0; channel < kMaxMidiChannels; ++channel)
            {
                //
                // check if there are any events for port/channel in track:
                //
                iMPEvent i;
                for (i = el->begin(); i != el->end(); ++i)
                {
                    MidiPlayEvent ev = *i;
                    if (ev.type() != ME_SYSEX && ev.type() != ME_META
                            && ev.channel() == channel && ev.port() == port)
                        break;
                }
                if (i == el->end())
                    continue;
                MidiTrack* track = new MidiTrack();
                if ((*t)->isDrumTrack)
                {
                    track->setType(Track::DRUM);
                }

                track->setOutChannel(channel);
                track->setOutPort(port);

                MidiPort* mport = &midiPorts[track->outPort()];
                // this overwrites any instrument set for this port:
                mport->setInstrument(instr);

                EventList* mel = track->events();
                //buildMidiEventList(mel, el, track, division, first);
                // Don't do loops.
                buildMidiEventList(mel, el, track, division, first, false);
                first = false;

                // Hmm. buildMidiEventList already takes care of this.
                // But it seems to work. How? Must test.
                if (channel == 9 && song->midiType() != MT_UNKNOWN)
                {
                    track->setType(Track::DRUM);
                    //
                    // remap drum pitch with drumInmap
                    //
                    EventList* tevents = track->events();
                    for (iEvent i = tevents->begin(); i != tevents->end(); ++i)
                    {
                        Event ev = i->second;
                        if (ev.isNote())
                        {
                            int pitch = drumInmap[ev.pitch()];
                            ev.setPitch(pitch);
                        }
                        else
                            if (ev.type() == Controller)
                        {
                            int ctl = ev.dataA();
                            MidiController *mc = mport->drumController(ctl);
                            if (mc)
                                ev.setA((ctl & ~0xff) | drumInmap[ctl & 0x7f]);
                        }
                    }
                }

                processTrack(track);

                song->insertTrack(track, -1);
            }
        }
        if (first)
        {
            //
            // track does only contain non-channel messages
            // (SYSEX or META)
            //
            MidiTrack* track = new MidiTrack();
            track->setOutChannel(0);
            track->setOutPort(0);
            EventList* mel = track->events();
            //buildMidiEventList(mel, el, track, division, true);
            // Do SysexMeta. Don't do loops.
            buildMidiEventList(mel, el, track, division, true, false);
            processTrack(track);
            song->insertTrack(track, -1);
        }
    }

    if (!merge)
    {
        TrackList* tl = song->tracks();
        if (!tl->empty())
        {
            Track* track = tl->front();
            track->setSelected(true);
        }
        song->initLen();

        int z, n;
        ///sigmap.timesig(0, z, n);
        sigmap.timesig(0, z, n);

        int tempo = tempomap.tempo(0);
        transport->setTimesig(z, n);
        transport->setTempo(tempo);

        bool masterF = !tempomap.empty();
        song->setMasterFlag(masterF);
        transport->setMasterFlag(masterF);

        song->updatePos();

        composer->reset();
        ///composer->setMode(int(song->midiType())); // p4.0.7 Tim
    }
    else
    {
        song->initLen();
    }

    return false;
}/*}}}*/
示例#20
0
bool LOS::importMidi(const QString name, bool merge)/*{{{*/
{
    bool popenFlag;
    FILE* fp = fileOpen(this, name, QString(".mid"), "r", popenFlag);
    if (fp == 0)
        return true;
    MidiFile mf(fp);
    bool rv = mf.read();
    popenFlag ? pclose(fp) : fclose(fp);
    if (rv)
    {
        QString s(tr("reading midifile\n  "));
        s += name;
        s += tr("\nfailed: ");
        s += mf.error();
        QMessageBox::critical(this, QString("LOS"), s);
        return rv;
    }
    //
    //  evaluate song Type (GM, XG, GS, unknown)
    //
    MidiType t = song->midiType();
    if (!merge)
    {
        t = mf.midiType();
        song->setMidiType(t);
    }
    MidiInstrument* instr = 0;
    for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i)
    {
        MidiInstrument* mi = *i;
        if ((mi->iname() == "GM" && ((t == MIDI_TYPE_NULL) || (t == MIDI_TYPE_GM))) ||
            (mi->iname() == "GS" &&   t == MIDI_TYPE_GS) ||
            (mi->iname() == "XG" &&   t == MIDI_TYPE_XG))
        {
            instr = mi;
            break;
        }
    }
    if (instr == 0)
    {
        // the standard instrument files (GM, GS, XG) must be present
        printf("no instrument, type %d\n", t);
        return true;
        //abort();
    }

    MidiFileTrackList* etl = mf.trackList();
    int division = mf.division();

    //
    // create MidiTrack and copy events to ->events()
    //    - combine note on/off events
    //    - calculate tick value for internal resolution
    //
    int mPort = getFreeMidiPort();
    for (iMidiFileTrack t = etl->begin(); t != etl->end(); ++t)
    {
        MPEventList* el = &((*t)->events);
        if (el->empty())
            continue;
        //
        // if we split the track, SYSEX and META events go into
        // the first target track

        bool first = true;
        QList<QPair<int, int> > portChannelList;
        iMPEvent i;
        for(i = el->begin(); i != el->end(); i++)
        {
            if (i->type() != ME_SYSEX && i->type() != ME_META)
            {
                int chan = i->channel();
                int port = i->port();
                if(portChannelList.isEmpty() || !portChannelList.contains(qMakePair(chan, port)))
                {
                    portChannelList.append(qMakePair(chan, port));

                    MidiTrack* track = new MidiTrack();
                    track->setDefaultName();
                    track->setMasterFlag(true);

                    if(config.partColorNames[lastTrackPartColorIndex].contains("menu:", Qt::CaseSensitive))
                        lastTrackPartColorIndex ++;

                    track->setDefaultPartColor(lastTrackPartColorIndex);
                    lastTrackPartColorIndex ++;

                    if(lastTrackPartColorIndex == NUM_PARTCOLORS)
                        lastTrackPartColorIndex = 1;

                    //Set track channel so buildMidiEventList can match the event to a channel
                    track->setOutChannel(chan);
                    track->setOutPort(mPort);

                    MidiPort* mport = &midiPorts[track->outPort()];
                    // this overwrites any instrument set for this port:
                    mport->setInstrument(instr);

                    EventList* mel = track->events();
                    buildMidiEventList(mel, el, track, division, first, false, false);

                    first = false;

                    processTrack(track);

                    //Update track to channel 1
                    //99% of all midi we import will be alien to our setup anyway,
                    //so I'm making it easy for the user to just set the Instrument and go
                    track->setOutChannel(0);

                    song->insertTrack(track, -1);
                    mPort++;
                    //FIXME: Provice a non-iterative way to do this using the new losMidiPorts hash
                    //Or maintain a list of configured or inuse ports
                    while((&midiPorts[mPort])->device() && mPort < kMaxMidiPorts)
                        mPort++;//Just incase we have a configured port after an empty one
                }
            }
        }
        if (first)
        {
            //
            // track does only contain non-channel messages
            // (SYSEX or META)
            //
            MidiTrack* track = new MidiTrack();
            track->setDefaultName();
            track->setMasterFlag(true);
            track->setOutChannel(0);
            track->setOutPort(mPort);

            if(config.partColorNames[lastTrackPartColorIndex].contains("menu:", Qt::CaseSensitive))
                lastTrackPartColorIndex ++;

            track->setDefaultPartColor(lastTrackPartColorIndex);
            lastTrackPartColorIndex ++;

            if(lastTrackPartColorIndex == NUM_PARTCOLORS)
                lastTrackPartColorIndex = 1;

            EventList* mel = track->events();
            // Do SysexMeta. Don't do loops.
            // TODO: Properly support sysex dumps
            buildMidiEventList(mel, el, track, division, true, false, false);
            processTrack(track);
            song->insertTrack(track, -1);
            mPort++;
            while((&midiPorts[mPort])->device() && mPort < kMaxMidiPorts)
                mPort++;
        }
    }

    if (!merge)
    {
        MidiTrackList* tl = song->tracks();
        if (!tl->empty())
        {
            MidiTrack* track = tl->front();
            track->setSelected(true);
        }
        song->initLen();

        int z, n;
        sigmap.timesig(0, z, n);

        int tempo = tempomap.tempo(0);
        transport->setTimesig(z, n);
        transport->setTempo(tempo);

        bool masterF = !tempomap.empty();
        song->setMasterFlag(masterF);
        transport->setMasterFlag(masterF);

        song->updatePos();

        composer->reset();
    }
    else
    {
        song->initLen();
    }

    return false;
}/*}}}*/
示例#21
0
bool LOS::importMidi(const QString name, bool merge)/*{{{*/
{
    bool popenFlag;
    FILE* fp = fileOpen(this, name, QString(".mid"), "r", popenFlag);
    if (fp == 0)
        return true;
    MidiFile mf(fp);
    bool rv = mf.read();
    popenFlag ? pclose(fp) : fclose(fp);
    if (rv)
    {
        QString s(tr("reading midifile\n  "));
        s += name;
        s += tr("\nfailed: ");
        s += mf.error();
        QMessageBox::critical(this, QString("LOS"), s);
        return rv;
    }
    //
    //  evaluate song Type (GM, XG, GS, unknown)
    //
    MType t = song->midiType();
    if (!merge)
    {
        t = mf.mtype();
        song->setMType(t);
    }
    MidiInstrument* instr = 0;
    for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i)
    {
        MidiInstrument* mi = *i;
        if ((mi->iname() == "GM" && ((t == MT_UNKNOWN) || (t == MIDI_TYPE_GM)))
                || ((mi->iname() == "GS") && (t == MT_GS))
                || ((mi->iname() == "XG") && (t == MT_XG)))
        {
            instr = mi;
            break;
        }
    }
    if (instr == 0)
    {
        // the standard instrument files (GM, GS, XG) must be present
        printf("no instrument, type %d\n", t);
        return true;
        //abort();
    }

    MidiFileTrackList* etl = mf.trackList();
    int division = mf.division();

    //
    // create MidiTrack and copy events to ->events()
    //    - combine note on/off events
    //    - calculate tick value for internal resolution
    //
    int mPort = getFreeMidiPort();
    for (iMidiFileTrack t = etl->begin(); t != etl->end(); ++t)
    {
        MPEventList* el = &((*t)->events);
        if (el->empty())
            continue;
        //
        // if we split the track, SYSEX and META events go into
        // the first target track

        bool first = true;
        // somewhat silly and slooow:
        QList<QPair<int, int> > eventChannelList;
        if(mPort >= 0 && mPort < kMaxMidiPorts)
        {
            for (int channel = 0; channel < kMaxMidiChannels; ++channel)
            {
                //
                // check if there are any events for port/channel in track:
                //
                iMPEvent i;
                for (i = el->begin(); i != el->end(); ++i)
                {
                    MidiPlayEvent ev = *i;
                    if (ev.type() != ME_SYSEX && ev.type() != ME_META && ev.channel() == channel)
                        break;
                }
                if (i == el->end())
                    continue;
                MidiTrack* track = new MidiTrack();
                track->setDefaultName();
                track->setMasterFlag(true);

                track->setOutChannel(channel);
                track->setOutPort(mPort);

                MidiPort* mport = &midiPorts[track->outPort()];
                // this overwrites any instrument set for this port:
                mport->setInstrument(instr);

                EventList* mel = track->events();
                buildMidiEventList(mel, el, track, division, first, false, false);

                first = false;

                processTrack(track);

                song->insertTrack(track, -1);
                //Create the Audio input side of the track
                Track* input = song->addTrackByName(QString("i").append(track->name()), Track::AUDIO_INPUT, -1, false, false);
                if(input)
                {
                    input->setMasterFlag(false);
                    input->setChainMaster(track->id());
                    track->addManagedTrack(input->id());
                }
            }
        }
        if (first)
        {
            //
            // track does only contain non-channel messages
            // (SYSEX or META)
            //
            MidiTrack* track = new MidiTrack();
            track->setDefaultName();
            track->setMasterFlag(true);
            track->setOutChannel(0);
            track->setOutPort(mPort);
            EventList* mel = track->events();
            //buildMidiEventList(mel, el, track, division, true);
            // Do SysexMeta. Don't do loops.
            buildMidiEventList(mel, el, track, division, true, false, false);
            processTrack(track);
            song->insertTrack(track, -1);
            //Create the Audio input side of the track
            Track* input = song->addTrackByName(QString("i").append(track->name()), Track::AUDIO_INPUT, -1, false, false);
            if(input)
            {
                input->setMasterFlag(false);
                input->setChainMaster(track->id());
                track->addManagedTrack(input->id());
            }
        }
        mPort++;
        //FIXME: Provice a non-iterative way to do this using the new losMidiPorts hash
        //Or maintain a list of configured or inuse ports
        while((&midiPorts[mPort])->device() && mPort < kMaxMidiPorts)
            mPort++;//Just incase we have a configured port after an empty one
    }

    if (!merge)
    {
        TrackList* tl = song->tracks();
        if (!tl->empty())
        {
            Track* track = tl->front();
            track->setSelected(true);
        }
        song->initLen();

        int z, n;
        sigmap.timesig(0, z, n);

        int tempo = tempomap.tempo(0);
        transport->setTimesig(z, n);
        transport->setTempo(tempo);

        bool masterF = !tempomap.empty();
        song->setMasterFlag(masterF);
        transport->setMasterFlag(masterF);

        song->updatePos();

        composer->reset();
    }
    else
    {
        song->initLen();
    }

    return false;
}/*}}}*/
示例#22
0
文件: midi.cpp 项目: faesong/oom
void Audio::initDevices()
{
	//
	// mark all used ports
	//
	bool activePorts[MIDI_PORTS];
	for (int i = 0; i < MIDI_PORTS; ++i)
		activePorts[i] = false;

	MidiTrackList* tracks = song->midis();
	for (iMidiTrack it = tracks->begin(); it != tracks->end(); ++it)
	{
		MidiTrack* track = *it;
		activePorts[track->outPort()] = true;
	}
	if (song->click())
		activePorts[clickPort] = true;

	//
	// test for explicit instrument initialization
	//

	for (int i = 0; i < MIDI_PORTS; ++i)
	{
		if (!activePorts[i])
			continue;

		MidiPort* port = &midiPorts[i];
		MidiInstrument* instr = port->instrument();
		MidiDevice* md = port->device();

		if (instr && md)
		{
			EventList* events = instr->midiInit();
			if (events->empty())
				continue;
			for (iEvent ie = events->begin(); ie != events->end(); ++ie)
			{
				MidiPlayEvent ev(0, i, 0, ie->second);
				md->putEvent(ev);
			}
			activePorts[i] = false; // no standard initialization
		}
	}
	//
	// damit Midi-Devices, die mehrere Ports besitzen, wie z.B.
	// das Korg NS5R, nicht mehrmals zwischen GM und XG/GS hin und
	// hergeschaltet werden, wird zun�hst auf allen Ports GM
	// initialisiert, und dann erst XG/GS
	//

	// Standard initialization...
	for (int i = 0; i < MIDI_PORTS; ++i)
	{
		if (!activePorts[i])
			continue;
		MidiPort* port = &midiPorts[i];
		switch (song->mtype())
		{
			case MT_GS:
			case MT_UNKNOWN:
				break;
			case MT_GM:
			case MT_XG:
				port->sendGmOn();
				break;
		}
	}
	for (int i = 0; i < MIDI_PORTS; ++i)
	{
		if (!activePorts[i])
			continue;
		MidiPort* port = &midiPorts[i];
		switch (song->mtype())
		{
			case MT_UNKNOWN:
				break;
			case MT_GM:
				port->sendGmInitValues();
				break;
			case MT_GS:
				port->sendGsOn();
				port->sendGsInitValues();
				break;
			case MT_XG:
				port->sendXgOn();
				port->sendXgInitValues();
				break;
		}
	}
}
示例#23
0
文件: midi.cpp 项目: faesong/oom
void Audio::preloadControllers()/*{{{*/
{
	midiBusy = true;

	MidiTrackList* tracks = song->midis();
	for (iMidiTrack it = tracks->begin(); it != tracks->end(); ++it)
	{
		MidiTrack* track = *it;
		//activePorts[track->outPort()] = true;
		QList<ProcessList*> pcevents;

		int port = track->outPort();
		int channel = track->outChannel();
		int defaultPort = port;

		MidiDevice* md = midiPorts[port].device();
		if (!md)
		{
			continue;
		}
		MPEventList* playEvents = md->playEvents();
		playEvents->erase(playEvents->begin(), playEvents->end());

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

			unsigned offset = delay + partTick;

			for (iEvent ie = events->begin(); ie != events->end(); ++ie)
			{
				Event ev = ie->second;
				port = defaultPort;
				unsigned tick = ev.tick() + offset;
				//unsigned frame = tempomap.tick2frame(tick) + frameOffset;
				switch (ev.dataA())
				{
					case CTRL_PROGRAM:
					{
						ProcessList *pl = new ProcessList;
						pl->port = port;
						pl->channel = channel;
						pl->dataB = ev.dataB();
						bool addEvent = true;
						for(int i = 0; i < pcevents.size(); ++i)
						{
							ProcessList* ipl = pcevents.at(i);
							if(ipl->port == pl->port && ipl->channel == pl->channel && ipl->dataB == pl->dataB)
							{
								addEvent = false;
								break;
							}
						}
						if(addEvent)
						{
							printf("Audio::preloadControllers() Loading event @ tick: %d - on channel: %d - on port: %d - dataA: %d - dataB: %d\n",
								tick, channel, port, ev.dataA(), ev.dataB());
							pcevents.append(pl);
							playEvents->add(MidiPlayEvent(tick, port, channel, ev));
						}
					}
						break;
					default:
						break;
				}
			}
		}
		md->setNextPlayEvent(playEvents->begin());
	}
	midiBusy = false;
}/*}}}*/
示例#24
0
int main(int argc, char* argv[])
      {
      int c;
      while ((c = getopt(argc, argv, "vdD:r")) != EOF) {
            switch (c) {
                  case 'v':
                        printVersion();
                        return 0;
                  case 'd':
                        debugMode = true;
                        break;
                  default:
                        usage();
                        return -1;
                  }
            }
      QIODevice* in = 0;
      QIODevice* out = 0;

      switch (argc - optind) {
            case 2:
                  out = new QFile(argv[1 + optind]);
                  if (!out->open(QIODevice::WriteOnly)) {
                        printf("cannot open output file <%s>: %s\n", argv[optind+1], strerror(errno));
                        return -3;
                        }
            case 1:
                  in = new QFile(argv[optind]);
                  if (!in->open(QIODevice::ReadOnly)) {
                        printf("cannot open input file <%s>: %s\n", argv[optind], strerror(errno));
                        return -4;
                        }
                  break;
            case 0:
                  break;
            default:
                  usage();
                  return -2;
                  break;
            }
      if (in == 0) {
            in = new QFile;
            ((QFile*)in)->open(stdin, QIODevice::ReadOnly);
            }
      if (out == 0) {
            out = new QFile;
            ((QFile*)out)->open(stdout, QIODevice::WriteOnly);
            }

      MidiFile mf;
      mf.setFormat(1);

      XmlReader e(in);
      while (e.readNextStartElement()) {
            const QStringRef& tag(e.name());
            if (tag == "SMF") {
                  while (e.readNextStartElement()) {
                        const QStringRef& tag(e.name());
                        if (tag == "Track") {
                              MidiTrack* track = new MidiTrack(&mf);
                              while (e.readNextStartElement()) {
                                    const QStringRef& tag(e.name());
                                    if (tag == "NoteOff") {
                                          MidiEventType t = MidiEventType::NOTEOFF;
                                          int tick        = e.intAttribute("tick");
                                          uchar c         = e.intAttribute("c");
                                          uchar a         = e.intAttribute("a", 0, 16);
                                          uchar b         = e.intAttribute("b", 0, 16);
                                          track->events().insert(std::pair<int,MidiEvent>(tick, MidiEvent(t, c, a, b)));
                                          e.skipCurrentElement();
                                          }
                                    else if (tag == "NoteOn") {
                                          MidiEventType t = MidiEventType::NOTEON;
                                          int tick        = e.intAttribute("tick");
                                          uchar c         = e.intAttribute("c");
                                          uchar a         = e.intAttribute("a", 0, 16);
                                          uchar b         = e.intAttribute("b", 0, 16);
                                          track->events().insert(std::pair<int,MidiEvent>(tick, MidiEvent(t, c, a, b)));
                                          e.skipCurrentElement();
                                          }
                                    else if (tag == "Ctrl") {
                                          MidiEventType t = MidiEventType::CONTROLLER;
                                          int tick        = e.intAttribute("tick");
                                          uchar c         = e.intAttribute("c");
                                          uchar a         = e.intAttribute("a", 0, 16);
                                          uchar b         = e.intAttribute("b", 0, 16);
                                          track->events().insert(std::pair<int,MidiEvent>(tick, MidiEvent(t, c, a, b)));
                                          e.skipCurrentElement();
                                          }
                                    else if (tag == "Program") {
                                          MidiEventType t = MidiEventType::PROGRAM;
                                          int tick        = e.intAttribute("tick");
                                          uchar c         = e.intAttribute("c");
                                          uchar a         = e.intAttribute("a", 0, 16);
                                          track->events().insert(std::pair<int,MidiEvent>(tick, MidiEvent(t, c, a, 0)));
                                          e.skipCurrentElement();
                                          }
                                    else if (tag == "Event") {
                                          uchar t         = e.intAttribute("t");
                                          int tick        = e.intAttribute("tick");
                                          uchar c         = e.intAttribute("c");
                                          uchar a         = e.intAttribute("a", 0, 16);
                                          uchar b         = e.intAttribute("b", 0, 16);
                                          track->events().insert(std::pair<int,MidiEvent>(tick,
                                             MidiEvent(MidiEventType(t), c, a, b)));
                                          e.skipCurrentElement();
                                          }
                                    else
                                          e.unknown();
                                    }
                              mf.tracks().push_back(track);
                              }
                        else if (tag == "division")
                              mf.setDivision(e.readInt());
                        else if (tag == "format")
                              mf.setFormat(e.readInt());
                        else
                              e.unknown();
                        }
                  }
            else
                  e.unknown();
            }

      mf.write(out);

      delete out;
      delete in;
      return 0;
      }
示例#25
0
文件: part.cpp 项目: faesong/oom
void addPortCtrlEvents(Part* part, bool doClones)
{
	// Traverse and process the clone chain ring until we arrive at the same part again.
	// The loop is a safety net.
	// Update: Due to the varying calls, and order of, incARefcount, (msg)ChangePart, replaceClone, and remove/addPortCtrlEvents,
	//  we can not rely on the reference count as a safety net in these routines. We will just have to trust the clone chain.
	Part* p = part;
	//int j = doClones ? p->cevents()->arefCount() : 1;
	//if(j > 0)
	{
		//for(int i = 0; i < j; ++i)
		while (1)
		{
			// Added by Tim. p3.3.6
			//printf("addPortCtrlEvents i:%d %s %p events %p refs:%d arefs:%d\n", i, p->name().toLatin1().constData(), p, part->cevents(), part->cevents()->refCount(), j);

			Track* t = p->track();
			if (t && t->isMidiTrack())
			{
				MidiTrack* mt = (MidiTrack*) t;
				int port = mt->outPort();
				const EventList* el = p->cevents();
				unsigned len = p->lenTick();
				for (ciEvent ie = el->begin(); ie != el->end(); ++ie)
				{
					const Event& ev = ie->second;
					// Added by T356. Do not add events which are past the end of the part.
					if (ev.tick() >= len)
						break;

					if (ev.type() == Controller)
					{
						int ch = mt->outChannel();
						int tck = ev.tick() + p->tick();
						int cntrl = ev.dataA();
						int val = ev.dataB();
						MidiPort* mp = &midiPorts[port];

						// Is it a drum controller event, according to the track port's instrument?
						if (mt->type() == Track::DRUM)
						{
							MidiController* mc = mp->drumController(cntrl);
							if (mc)
							{
								int note = cntrl & 0x7f;
								cntrl &= ~0xff;
								ch = drumMap[note].channel;
								mp = &midiPorts[drumMap[note].port];
								cntrl |= drumMap[note].anote;
							}
						}

						mp->setControllerVal(ch, tck, cntrl, val, p);
					}
				}
			}
			if (!doClones)
				break;
			// Get the next clone in the chain ring.
			p = p->nextClone();
			// Same as original part? Finished.
			if (p == part)
				break;
		}
	}
}
示例#26
0
void TrackListView::contextPopupMenu(QPoint pos)/*{{{*/
{
    QModelIndex mindex = m_table->indexAt(pos);
    if(!mindex.isValid())
        return;
    //int row = mindex.row();
    QStandardItem* item = m_model->itemFromIndex(mindex);
    if(item)
    {
        m_selectedIndex = item->row();
        //Make it works even if you rightclick on the checkbox
        QString trackName = item->data(TrackNameRole).toString();
        int type = item->data(TrackRole).toInt();
        MidiTrack* track = song->findTrack(trackName);
        if(!track || !m_editor)
            return;
        QMenu* p = new QMenu(this);
        QString title(tr("Part Color"));
        int index = track->getDefaultPartColor();
        Part* npart = 0;
        if(type == 1)
            title = QString(tr("Default Part Color"));
        else
        {
            PartList* list = track->parts();
            int sn = item->data(PartRole).toInt();
            unsigned tick = item->data(TickRole).toInt();
            npart = list->find(tick, sn);
            if(npart)
                index = npart->colorIndex();
        }
        QMenu* colorPopup = p->addMenu(title);

        QMenu* colorSub;
        for (int i = 0; i < NUM_PARTCOLORS; ++i)
        {
            QString colorname(config.partColorNames[i]);
            if(colorname.contains("menu:", Qt::CaseSensitive))
            {
                colorSub = colorPopup->addMenu(colorname.replace("menu:", ""));
            }
            else
            {
                if(index == i)
                {
                    colorname = QString(config.partColorNames[i]);
                    colorPopup->setIcon(partColorIconsSelected.at(i));
                    colorPopup->setTitle(colorSub->title()+": "+colorname);

                    colorname = QString("* "+config.partColorNames[i]);
                    QAction *act_color = colorSub->addAction(partColorIconsSelected.at(i), colorname);
                    act_color->setData(20 + i);
                }
                else
                {
                    colorname = QString("     "+config.partColorNames[i]);
                    QAction *act_color = colorSub->addAction(partColorIcons.at(i), colorname);
                    act_color->setData(20 + i);
                }
            }
        }
        p->addAction(tr("Add Part"))->setData(1);
        p->addAction(tr("Add Part and Select"))->setData(2);
        if(type == 2)
            p->addAction(tr("Delete Part"))->setData(3);

        QAction* act = p->exec(QCursor::pos());
        if (act)
        {
            int selection = act->data().toInt();
            switch(selection)
            {
                case 1:
                {
                    CItem *citem = los->composer->addCanvasPart(track);
                    if(citem)
                    {
                        Part* mp = citem->part();
                        populateTable();//update check state
                        //Select and scroll to the added part
                        if(mp)
                        {
                            int psn = mp->sn();
                            for(int i = 0; i < m_model->rowCount(); ++i)
                            {
                                QStandardItem* item = m_model->item(i, 0);
                                if(item)
                                {
                                    int type = item->data(TrackRole).toInt();
                                    if(type == 1)
                                    {//TrackMode
                                        continue;
                                    }
                                    else
                                    {//PartMode
                                        int sn = item->data(PartRole).toInt();
                                        if(psn == sn)
                                        {
                                            //m_tempColor = item->foreground();
                                            m_model->blockSignals(true);
                                            item->setForeground(QColor(99, 36, 36));
                                            m_model->blockSignals(false);
                                            update();
                                            m_selectedIndex = item->row();
                                            m_table->selectRow(m_selectedIndex);
                                            m_table->scrollTo(m_model->index(m_selectedIndex, 0));
                                            m_colorRows.append(m_selectedIndex);
                                            QTimer::singleShot(350, this, SLOT(updateColor()));
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                break;
                case 2:
                {
                    CItem* citem = los->composer->addCanvasPart(track);
                    if(citem)
                    {
                        Part* mp = citem->part();
                        if(mp)
                        {
                            m_editor->addPart(mp);
                            populateTable();//update check state
                            updatePartSelection(mp);
                        }
                    }
                    break;
                }
                case 3:
                {
                    if(npart)
                    {
                        audio->msgRemovePart(npart);
                        populateTable();//update check state
                        scrollPos = pos;
                        /*if(row < m_model->rowCount())
                        {
                            QModelIndex rowIndex = m_table->indexAt(pos);
                            m_table->scrollTo(rowIndex, QAbstractItemView::PositionAtTop);
                        }*/
                    }
                    break;
                }
                case 20 ... NUM_PARTCOLORS + 20:
                {
                    int curColorIndex = selection - 20;
                    if(npart)
                    {
                        npart->setColorIndex(curColorIndex);
                        song->update(SC_PART_COLOR_MODIFIED);
                    }
                    else
                    {
                        track->setDefaultPartColor(curColorIndex);
                    }
                    populateTable();//update check state
                    break;
                }
            }
        }
        delete p;
    }
}/*}}}*/
示例#27
0
文件: route.cpp 项目: 87maxi/oom
Route name2route(const QString& rn, bool /*dst*/, int rtype)/*{{{*/
{
	// printf("name2route %s\n", rn.toLatin1().constData());
	int channel = -1;
	QString s(rn);
	// Support old route style in oom files. Obsolete.
	if (rn.size() >= 2 && rn[0].isNumber() && rn[1] == ':')
	{
		channel = rn[0].toAscii() - int('1');
		s = rn.mid(2);
	}

	if (rtype == -1)
	{
		if (checkAudioDevice())
		{
			void* p = audioDevice->findPort(s.toLatin1().constData());
			if (p)
				return Route(p, channel);
		}

		TrackList* tl = song->tracks();
		for (iTrack i = tl->begin(); i != tl->end(); ++i)
		{
			if ((*i)->isMidiTrack())
			{
				MidiTrack* track = (MidiTrack*) * i;
				if (track->name() == s)
					return Route(track, channel);
			}
			else
			{
				AudioTrack* track = (AudioTrack*) * i;
				if (track->name() == s)
					return Route(track, channel);
			}
		}

		for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)
		{
			if ((*i)->name() == s)
				return Route(*i, channel);
		}

		// p3.3.49
		if (s.left(ROUTE_MIDIPORT_NAME_PREFIX.length()) == ROUTE_MIDIPORT_NAME_PREFIX)
		{
			bool ok = false;
			int port = s.mid(ROUTE_MIDIPORT_NAME_PREFIX.length()).toInt(&ok);
			if (ok)
				return Route(port, channel);
		}
	}
	else
	{
		if (rtype == Route::TRACK_ROUTE)
		{
			TrackList* tl = song->tracks();
			for (iTrack i = tl->begin(); i != tl->end(); ++i)
			{
				if ((*i)->isMidiTrack())
				{
					MidiTrack* track = (MidiTrack*) * i;
					if (track->name() == s)
						return Route(track, channel);
				}
				else
				{
					AudioTrack* track = (AudioTrack*) * i;
					if (track->name() == s)
						return Route(track, channel);
				}
			}
		}// TODO Distinguish the device types
		else if (rtype == Route::MIDI_DEVICE_ROUTE)
		{
			for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)
			{
				if ((*i)->name() == s)
					return Route(*i, channel);
			}
		}
		else if (rtype == Route::JACK_ROUTE)
		{
			if (checkAudioDevice())
			{
				void* p = audioDevice->findPort(s.toLatin1().constData());
				if (p)
					return Route(p, channel);
			}
		}
		else if (rtype == Route::MIDI_PORT_ROUTE) // p3.3.49
		{
			if (s.left(ROUTE_MIDIPORT_NAME_PREFIX.length()) == ROUTE_MIDIPORT_NAME_PREFIX)
			{
				bool ok = false;
				int port = s.mid(ROUTE_MIDIPORT_NAME_PREFIX.length()).toInt(&ok);
				if (ok)
					return Route(port, channel);
			}
		}
	}

	printf("  name2route: <%s> not found\n", rn.toLatin1().constData());
	return Route((Track*) 0, channel);
}/*}}}*/
示例#28
0
void TrackListView::populateTable()/*{{{*/
{
    if(debugMsg)
        printf("TrackListView::populateTable\n");
    QScrollBar *bar = m_table->verticalScrollBar();
    int barPos = 0;
    if(bar)
        barPos = bar->sliderPosition();

    m_model->clear();
    for(iMidiTrack i = song->artracks()->begin(); i != song->artracks()->end(); ++i)
    {
        MidiTrack* track = (MidiTrack*)(*i);
        PartList* pl = track->parts();
        if(m_displayRole == PartRole && pl->empty())
        {
            continue;
        }

        QStandardItem* trackName = new QStandardItem();
        trackName->setForeground(QBrush(QColor(205,209,205)));
        trackName->setBackground(QBrush(QColor(20,20,20)));
        trackName->setFont(QFont("fixed-width", 10, QFont::Bold));
        trackName->setText(track->name());
        trackName->setCheckable(true);
        trackName->setCheckState(m_selectedTracks.contains(track->id()) ? Qt::Checked : Qt::Unchecked);

        trackName->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
        trackName->setData(1, TrackRole);
        trackName->setData(track->name(), TrackNameRole);
        trackName->setData(track->id(), TrackIdRole);
        trackName->setEditable(true);
        m_model->appendRow(trackName);

        for(iPart ip = pl->begin(); ip != pl->end(); ++ip)
        {
            Part* part = ip->second;
            QStandardItem* partName = new QStandardItem();
            partName->setFont(QFont("fixed-width", 9, QFont::Bold));
            partName->setText(part->name());
            partName->setData(part->sn(), PartRole);
            partName->setData(2, TrackRole);
            partName->setData(track->name(), TrackNameRole);
            partName->setData(part->name(), PartNameRole);
            partName->setData(part->tick(), TickRole);
            partName->setData(track->id(), TrackIdRole);
            partName->setEditable(true);
            partName->setCheckable(true);
            partName->setCheckState(m_editor->hasPart(part->sn()) ? Qt::Checked : Qt::Unchecked);

            if(!partColorIcons.isEmpty() && part->colorIndex() < partColorIcons.size())
                partName->setIcon(partColorIcons.at(part->colorIndex()));

            m_model->appendRow(partName);
        }
    }
    m_model->setHorizontalHeaderLabels(m_headers);
    if(m_selectedIndex < m_model->rowCount())
    {
        m_table->selectRow(m_selectedIndex);
        m_table->scrollTo(m_model->index(m_selectedIndex, 0));
    }
    if(bar)
        bar->setSliderPosition(barPos);
}/*}}}*/
示例#29
0
文件: conf.cpp 项目: Adamiko/los
static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo)/*{{{*/
{
    xml.tag(level++, "sequencer");

    if (writePortInfo)
    {
        //
        // write information about all midi ports, their assigned
        // instruments and all managed midi controllers
        //
        for (int i = 0; i < MIDI_PORTS; ++i)
        {
            bool used = false;
            MidiPort* mport = &midiPorts[i];

            // Route check by Tim. Port can now be used for routing even if no device.
            // Also, check for other non-defaults and save port, to preserve settings even if no device.
            // Dont write the config for the global inputs list they will be auto created with each startup
            if (mport->defaultInChannels() || mport->defaultOutChannels() ||
                    (mport->instrument() && !mport->instrument()->iname().isEmpty() && mport->instrument()->iname() != "GM") /*|| !mport->syncInfo().isDefault()*/ )
            {
                used = true;
            }
            else
            {//Put the ID of this track into a list
                MidiTrackList* tl = song->midis();
                for (iMidiTrack it = tl->begin(); it != tl->end(); ++it)
                {
                    MidiTrack* t = *it;
                    if (t->outPort() == i)
                    {
                        used = true;
                        break;
                    }
                }
            }

            MidiDevice* dev = mport->device();
            if (!used && !dev)
                continue;
            bool isGlobal = gInputListPorts.contains(mport->portno());
            xml.tag(level++, "midiport portId=\"%lld\" isGlobalInput=\"%d\"", mport->id(), isGlobal);

            if (mport->defaultInChannels())
                xml.intTag(level, "defaultInChans", mport->defaultInChannels());
            if (mport->defaultOutChannels())
                xml.intTag(level, "defaultOutChans", mport->defaultOutChannels());

            if (mport->instrument() && !mport->instrument()->iname().isEmpty() &&
                    (mport->instrument()->iname() != "GM")) // FIXME: TODO: Make this user configurable.
            {
                xml.strTag(level, "instrument", mport->instrument()->iname());
            }

            if (dev)
            {
                xml.strTag(level, "name", dev->name());
                xml.intTag(level, "cacheNRPN", (int)dev->cacheNRPN());

                if (dev->deviceType() != MidiDevice::ALSA_MIDI)
                    xml.intTag(level, "type", dev->deviceType());

                xml.intTag(level, "openFlags", dev->openFlags());
            }
            // write out registered controller for all channels
            MidiCtrlValListList* vll = mport->controller();
            for (int k = 0; k < MIDI_CHANNELS; ++k)
            {
                int min = k << 24;
                int max = min + 0x100000;
                xml.tag(level++, "channel idx=\"%d\"", k);
                iMidiCtrlValList s = vll->lower_bound(min);
                iMidiCtrlValList e = vll->lower_bound(max);
                if (s != e)
                {
                    for (iMidiCtrlValList i = s; i != e; ++i)
                    {
                        if(i->second->num() != 262145)
                        {
                            xml.tag(level++, "controller id=\"%d\"", i->second->num());
                            if (i->second->hwVal() != CTRL_VAL_UNKNOWN)
                                xml.intTag(level, "val", i->second->hwVal());
                            xml.etag(--level, "controller");
                        }
                    }
                }
                xml.etag(--level, "channel");
            }
            QList<PatchSequence*> *patchSequences = mport->patchSequences();
            if (patchSequences && !patchSequences->isEmpty())
            {
                for (int p = 0; p < patchSequences->size(); ++p)
                {
                    PatchSequence* ps = patchSequences->at(p);
                    QString pm = ps->name.replace('\n', " ");
                    xml.put(level, "<patchSequence id=\"%d\" name=\"%s\" checked=\"%d\" />", ps->id, pm.toLatin1().constData(), ps->selected);
                }
            }
            if(!mport->presets()->isEmpty())
            {
                QHashIterator<int, QString> iter(*mport->presets());
                while(iter.hasNext())
                {
                    iter.next();
                    xml.put(level, "<midiPreset id=\"%d\" sysex=\"%s\"/>", iter.key(), iter.value().toLatin1().constData());
                }
            }
            xml.etag(--level, "midiport");
        }
    }
    xml.tag(--level, "/sequencer");
}/*}}}*/
示例#30
0
void TrackListView::toggleTrackPart(QStandardItem* item)/*{{{*/
{
    if(!item)
        return;
    m_editing = true;
    int type = item->data(TrackRole).toInt();
    int column = item->column();
    bool checked = (item->checkState() == Qt::Checked);
    qint64 tid = item->data(TrackIdRole).toLongLong();
    QString trackName = item->data(TrackNameRole).toString();
    QString partName;
    m_selectedIndex = item->row();
    QString newName = item->text();
    if(type == 1)
    {
        if(trackName == newName)
            column = 0;
        else
            column = 1;
    }
    else
    {
        partName = item->data(PartNameRole).toString();
        if(partName == newName)
            column = 0;
        else
            column = 1;
    }

    MidiTrack* track = song->findTrackById(tid);
    if(!track || !m_editor)
    {
        m_editing = false;
        return;
    }

    PartList* list = track->parts();
    if(list->empty())
    {
        m_editing = false;
        updateCheck();
        return;
    }
    switch(type)
    {
        case 1: //Track
        {
            if(!column)
            {
                if(checked)
                {
                    m_editor->addParts(list);
                    m_selectedTracks.append(track->id());
                    if(!list->empty())
                    {
                        updatePartSelection(list->begin()->second);

                        updateCheck(list, checked);
                    }
                }
                else
                {
                    m_editor->removeParts(list);
                    m_editor->updateCanvas();
                    m_selectedTracks.removeAll(track->id());
                    updateCheck();
                    song->update(SC_SELECTION);
                }
            }
            else
            {
                bool valid = true;
                if(newName.isEmpty())
                {
                    valid = false;
                }
                if(valid)
                {
                    for (iMidiTrack i = song->tracks()->begin(); i != song->tracks()->end(); ++i)
                    {
                        if ((*i)->name() == newName)
                        {
                            valid = false;
                            break;
                        }
                    }
                }
                if(!valid)
                {
                    QMessageBox::critical(this, tr("LOS: bad trackname"),
                            tr("please choose a unique track name"),
                            QMessageBox::Ok, Qt::NoButton, Qt::NoButton);
                    m_model->blockSignals(true);
                    item->setText(item->data(TrackNameRole).toString());
                    m_model->blockSignals(false);
                    update();
                    m_editing = false;
                    return;
                }
                m_model->blockSignals(true);
                item->setData(newName, TrackNameRole);
                m_model->blockSignals(false);

                Track* newTrack = track->clone(false);
                newTrack->setName(newName);
                track->setName(newName);
                audio->msgChangeTrack((MidiTrack*)newTrack, track);
            }
        }
        break;
        case 2: //Part
        {
            int sn = item->data(PartRole).toInt();
            unsigned tick = item->data(TickRole).toInt();
            Part* part = list->find(tick, sn);
            if(part)
            {
                if(!column)
                {
                    if(checked)
                    {
                        m_editor->addPart(part);
                        updatePartSelection(part);
                    }
                    else
                    {
                        m_editor->removePart(sn);
                        m_editor->updateCanvas();
                        updateCheck();
                        song->update(SC_SELECTION);
                    }
                }
                else
                {
                    if(partName.isEmpty())
                    {
                        QMessageBox::critical(this, tr("LOS: Invalid part name"),
                                tr("Please choose a name with at least one charactor"),
                                QMessageBox::Ok, Qt::NoButton, Qt::NoButton);

                        m_model->blockSignals(true);
                        item->setText(item->data(PartNameRole).toString());
                        m_model->blockSignals(false);
                        update();
                        m_editing = false;
                        return;
                    }

                    m_model->blockSignals(true);
                    item->setData(newName, PartNameRole);
                    m_model->blockSignals(false);

                    Part* newPart = part->clone();
                    newPart->setName(newName);
                    // Indicate do undo, and do port controller values but not clone parts.
                    audio->msgChangePart(part, newPart, true, true, false);
                    song->update(SC_PART_MODIFIED);
                }
            }
        }
        break;
    }
    update();
    if(m_selectedIndex < m_model->rowCount())
    {
        m_table->selectRow(m_selectedIndex);
        m_table->scrollTo(m_model->index(m_selectedIndex, 0));
    }
    m_editing = false;
}/*}}}*/