예제 #1
0
파일: PianoView.cpp 프로젝트: BaraMGB/lmms
/*! \brief Handle a mouse move event on the piano display view
 *
 *  This handles the user dragging the mouse across the keys.  It uses
 *  code from mousePressEvent() and mouseReleaseEvent(), also correcting
 *  for if the mouse movement has stayed within one key and if the mouse
 *  has moved outside the vertical area of the keyboard (which is still
 *  allowed but won't make the volume go up to 11).
 *
 *  \param _me the ContextMenuEvent to handle.
 *  \todo Paul Wayper thinks that this code should be refactored to
 *  reduce or remove the duplication between this, the mousePressEvent()
 *  and mouseReleaseEvent() methods.
 */
void PianoView::mouseMoveEvent( QMouseEvent * _me )
{
	if( m_piano == NULL )
	{
		return;
	}

	int key_num = getKeyFromMouse( _me->pos() );
	int y_diff = _me->pos().y() - PIANO_BASE;
	int velocity = (int)( (float) y_diff /
		( Piano::isWhiteKey( key_num ) ?
			PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) *
						(float) m_piano->instrumentTrack()->midiPort()->baseVelocity() );
	// maybe the user moved the mouse-cursor above or under the
	// piano-widget while holding left button so check that and
	// correct volume if necessary
	if( y_diff < 0 )
	{
		velocity = 0;
	}
	else if( y_diff >
		( Piano::isWhiteKey( key_num ) ?
				PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) )
	{
		velocity = m_piano->instrumentTrack()->midiPort()->baseVelocity();
	}

	// is the calculated key different from current key? (could be the
	// user just moved the cursor one pixel left but on the same key)
	if( key_num != m_lastKey )
	{
		if( m_lastKey != -1 )
		{
			m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOff, -1, m_lastKey, 0 ) );
			m_piano->setKeyState( m_lastKey, false );
			m_lastKey = -1;
		}
		if( _me->buttons() & Qt::LeftButton )
		{
			if( _me->pos().y() > PIANO_BASE )
			{
				m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOn, -1, key_num, velocity ) );
				m_piano->setKeyState( key_num, true );
				m_lastKey = key_num;
			}
			else
			{
				m_piano->instrumentTrack()->baseNoteModel()->setInitValue( (float) key_num );
			}
		}
		// and let the user see that he pressed a key... :)
		update();
	}
	else if( m_piano->isKeyPressed( key_num ) )
	{
		m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiKeyPressure, -1, key_num, velocity ) );
	}

}
void InstrumentTrack::updatePitchRange()
{
	const int r = m_pitchRangeModel.value();
	m_pitchModel.setRange( MinPitchDefault * r, MaxPitchDefault * r );

	processOutEvent( MidiEvent( MidiControlChange, midiPort()->realOutputChannel(),
								MidiControllerRegisteredParameterNumberLSB, MidiPitchBendSensitivityRPN & 0x7F ) );
	processOutEvent( MidiEvent( MidiControlChange, midiPort()->realOutputChannel(),
								MidiControllerRegisteredParameterNumberMSB, ( MidiPitchBendSensitivityRPN >> 8 ) & 0x7F ) );
	processOutEvent( MidiEvent( MidiControlChange, midiPort()->realOutputChannel(), MidiControllerDataEntry, midiPitchRange() ) );
}
void InstrumentTrack::processOutEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset )
{
	// do nothing if we do not have an instrument instance (e.g. when loading settings)
	if( m_instrument == NULL )
	{
		return;
	}

	const MidiEvent transposedEvent = applyMasterKey( event );
	const int key = transposedEvent.key();

	switch( event.type() )
	{
		case MidiNoteOn:
			m_midiNotesMutex.lock();
			m_piano.setKeyState( event.key(), true );	// event.key() = original key

			if( key >= 0 && key < NumKeys )
			{
				if( m_runningMidiNotes[key] > 0 )
				{
					m_instrument->handleMidiEvent( MidiEvent( MidiNoteOff, midiPort()->realOutputChannel(), key, 0 ), time, offset );
				}
				++m_runningMidiNotes[key];
				m_instrument->handleMidiEvent( MidiEvent( MidiNoteOn, midiPort()->realOutputChannel(), key, event.velocity() ), time, offset );

			}
			m_midiNotesMutex.unlock();
			emit newNote();
			break;

		case MidiNoteOff:
			m_midiNotesMutex.lock();
			m_piano.setKeyState( event.key(), false );	// event.key() = original key

			if( key >= 0 && key < NumKeys && --m_runningMidiNotes[key] <= 0 )
			{
				m_instrument->handleMidiEvent( MidiEvent( MidiNoteOff, midiPort()->realOutputChannel(), key, 0 ), time, offset );
			}
			m_midiNotesMutex.unlock();
			break;

		default:
			m_instrument->handleMidiEvent( transposedEvent, time, offset );
			break;
	}

	// if appropriate, midi-port does futher routing
	m_midiPort.processOutEvent( event, time );
}
예제 #4
0
void NotePlayHandle::noteOff( const f_cnt_t _s )
{
	if( m_released )
	{
		return;
	}

	// first note-off all sub-notes
	for( NotePlayHandleList::Iterator it = m_subNotes.begin(); it != m_subNotes.end(); ++it )
	{
		( *it )->noteOff( _s );
	}

	// then set some variables indicating release-state
	m_framesBeforeRelease = _s;
	m_releaseFramesToDo = qMax<f_cnt_t>( 0, actualReleaseFramesToDo() );

	if( hasParent() || ! m_instrumentTrack->isArpeggioEnabled() )
	{
		// send MidiNoteOff event
		m_instrumentTrack->processOutEvent(
				MidiEvent( MidiNoteOff, midiChannel(), midiKey(), 0 ),
				MidiTime::fromFrames( _s, engine::framesPerTick() ), 
				_s );
	}

	// inform attached components about MIDI finished (used for recording in Piano Roll)
	if( m_origin == OriginMidiInput )
	{
		setLength( MidiTime( static_cast<f_cnt_t>( totalFramesPlayed() / engine::framesPerTick() ) ) );
		m_instrumentTrack->midiNoteOff( *this );
	}

	m_released = true;
}
예제 #5
0
void sfxrInstrumentView::previewSound()
{
    sfxrInstrument* s = castModel<sfxrInstrument>();
    InstrumentTrack* it = s->instrumentTrack();
    it->silenceAllNotes();
    it->processInEvent( MidiEvent( MidiNoteOn, 0, it->baseNoteModel()->value(), MidiDefaultVelocity ) );
}
예제 #6
0
파일: PianoView.cpp 프로젝트: BaraMGB/lmms
/*! \brief Handle the focus leaving the piano display view
 *
 *  Turn off all notes if we lose focus.
 *
 *  \todo Is there supposed to be a parameter given here?
 */
void PianoView::focusOutEvent( QFocusEvent * )
{
	if( m_piano == NULL )
	{
		return;
	}

	// focus just switched to another control inside the instrument track
	// window we live in?
	if( parentWidget()->parentWidget()->focusWidget() != this &&
		parentWidget()->parentWidget()->focusWidget() != NULL &&
		!parentWidget()->parentWidget()->
				focusWidget()->inherits( "QLineEdit" ) )
	{
		// then reclaim keyboard focus!
		setFocus();
		return;
	}

	// if we loose focus, we HAVE to note off all running notes because
	// we don't receive key-release-events anymore and so the notes would
	// hang otherwise
	for( int i = 0; i < NumKeys; ++i )
	{
		m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOff, -1, i, 0 ) );
		m_piano->setKeyState( i, false );
	}
	update();
}
예제 #7
0
void NotePlayHandle::setVolume( volume_t _volume )
{
	note::setVolume( _volume );

	const int baseVelocity = m_instrumentTrack->midiPort()->baseVelocity();

	m_instrumentTrack->processOutEvent( MidiEvent( MidiKeyPressure, midiChannel(), midiKey(), midiVelocity( baseVelocity ) ) );
}
예제 #8
0
파일: Piano.cpp 프로젝트: DeRobyJ/lmms
/*! \brief Handle a note being released on our keyboard display
 *
 *  \param key the key being releassed
 */
void Piano::handleKeyRelease( int key )
{
	if( isValidKey( key ) )
	{
		m_midiEvProc->processInEvent( MidiEvent( MidiNoteOff, -1, key, 0 ) );
		m_pressedKeys[key] = false;
	}
}
예제 #9
0
void MidiWinMM::handleInputEvent( HMIDIIN hm, DWORD ev )
{
	const int cmd = ev & 0xff;
	if( cmd == MidiActiveSensing )
	{
		return;
	}
	const int par1 = ( ev >> 8 ) & 0xff;
	const int par2 = ev >> 16;
	const MidiEventTypes cmdtype = static_cast<MidiEventTypes>( cmd & 0xf0 );
	const int chan = cmd & 0x0f;

	const QString d = m_inputDevices.value( hm );
	if( d.isEmpty() || !m_inputSubs.contains( d ) )
	{
		return;
	}

	const MidiPortList & l = m_inputSubs[d];
	for( MidiPortList::ConstIterator it = l.begin(); it != l.end(); ++it )
	{
		switch( cmdtype )
		{
			case MidiNoteOn:
			case MidiNoteOff:
			case MidiKeyPressure:
				( *it )->processInEvent( MidiEvent( cmdtype, chan, par1 - KeysPerOctave, par2 & 0xff, &hm ) );
				break;

			case MidiControlChange:
			case MidiProgramChange:
			case MidiChannelPressure:
				( *it )->processInEvent( MidiEvent( cmdtype, chan, par1, par2 & 0xff, &hm ) );
				break;

			case MidiPitchBend:
				( *it )->processInEvent( MidiEvent( cmdtype, chan, par1 + par2*128, 0, &hm ) );
				break;

			default:
				qWarning( "MidiWinMM: unhandled input event %d\n", cmdtype );
				break;
		}
	}
}
예제 #10
0
파일: vestige.cpp 프로젝트: asmw/lmms
void VestigeInstrumentView::noteOffAll( void )
{
	m_vi->m_pluginMutex.lock();
	if( m_vi->m_plugin != NULL )
	{
		for( int key = 0; key <= MidiMaxKey; ++key )
		{
			m_vi->m_plugin->processMidiEvent( MidiEvent( MidiNoteOff, 0, key, 0 ), 0 );
		}
	}
	m_vi->m_pluginMutex.unlock();
}
예제 #11
0
파일: Piano.cpp 프로젝트: DeRobyJ/lmms
/*! \brief Handle a note being pressed on our keyboard display
 *
 *  \param key the key being pressed
 */
void Piano::handleKeyPress( int key, int midiVelocity )
{
	if( midiVelocity == -1 )
	{
		midiVelocity = m_instrumentTrack->midiPort()->baseVelocity();
	}
	if( isValidKey( key ) )
	{
		m_midiEvProc->processInEvent( MidiEvent( MidiNoteOn, -1, key, midiVelocity ) );
		m_pressedKeys[key] = true;
	}
}
예제 #12
0
파일: PianoView.cpp 프로젝트: BaraMGB/lmms
/*! \brief Handle a mouse click on this piano display view
 *
 *  We first determine the key number using the getKeyFromMouse() method.
 *
 *  If we're below the 'root key selection' area,
 *  we set the volume of the note to be proportional to the vertical
 *  position on the keyboard - lower down the key is louder, within the
 *  boundaries of the (white or black) key pressed.  We then tell the
 *  instrument to play that note, scaling for MIDI max loudness = 127.
 *
 *  If we're in the 'root key selection' area, of course, we set the
 *  root key to be that key.
 *
 *  We finally update ourselves to show the key press
 *
 *  \param _me the mouse click to handle.
 */
void PianoView::mousePressEvent( QMouseEvent * _me )
{
	if( _me->button() == Qt::LeftButton && m_piano != NULL )
	{
		// get pressed key
		int key_num = getKeyFromMouse( _me->pos() );
		if( _me->pos().y() > PIANO_BASE )
		{
			int y_diff = _me->pos().y() - PIANO_BASE;
			int velocity = (int)( ( float ) y_diff /
				( Piano::isWhiteKey( key_num )  ?
				PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) *
						(float) m_piano->instrumentTrack()->midiPort()->baseVelocity() );
			if( y_diff < 0 )
			{
				velocity = 0;
			}
			else if( y_diff >
				( Piano::isWhiteKey( key_num ) ?
				PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) )
			{
				velocity = m_piano->instrumentTrack()->midiPort()->baseVelocity();
			}
			// set note on
			m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOn, -1, key_num, velocity ) );
			m_piano->setKeyState( key_num, true );
			m_lastKey = key_num;

			emit keyPressed( key_num );
		}
		else
		{
			if( _me->modifiers() & Qt::ControlModifier )
			{
				new StringPairDrag( "automatable_model",
					QString::number( m_piano->instrumentTrack()->baseNoteModel()->id() ),
					QPixmap(), this );
				_me->accept();
			}
			else
			{
				m_piano->instrumentTrack()->baseNoteModel()->setInitValue( (float) key_num );

				emit baseNoteChanged();
			}
		}

		// and let the user see that he pressed a key... :)
		update();
	}
}
예제 #13
0
파일: PianoView.cpp 프로젝트: BaraMGB/lmms
/*! \brief Handle a mouse release event on the piano display view
 *
 *  If a key was pressed by the in the mousePressEvent() function, we
 *  turn the note off.
 *
 *  \param _me the mousePressEvent to handle.
 */
void PianoView::mouseReleaseEvent( QMouseEvent * )
{
	if( m_lastKey != -1 )
	{
		if( m_piano != NULL )
		{
			m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOff, -1, m_lastKey, 0 ) );
			m_piano->setKeyState( m_lastKey, false );
		}

		// and let the user see that he released a key... :)
		update();

		m_lastKey = -1;
	}
}
예제 #14
0
MidiEvent MidiBuffer::readEvent(int index, bool *ok) {
    if(!isValid()) {
        if(ok) {
            (*ok) = false;
        }
        return MidiEvent();
    }

    MidiEvent midiEvent;
    bool success = (jack_midi_event_get(
        &midiEvent,
        _jackBuffer,
        index) == 0);

    if(ok) {
        (*ok) = success;
    }

    return midiEvent;
}
예제 #15
0
파일: MidiPort.cpp 프로젝트: jasp00/lmms
void MidiPort::updateOutputProgram()
{
	processOutEvent( MidiEvent( MidiProgramChange, realOutputChannel(), outputProgram()-1 ) );
}
예제 #16
0
파일: MidiApple.cpp 프로젝트: DeRobyJ/lmms
void MidiApple::HandleReadCallback( const MIDIPacketList *pktlist, void *srcConnRefCon )
{
	const char * refName = (const char *) srcConnRefCon;

	MIDIEndpointRef endPointRef = m_inputDevices.value(refName);
	if( !m_inputSubs.contains( refName ) )
	{
//		qDebug("HandleReadCallback '%s' not subscribed",refName);
//		printQStringKeys("m_inputDevices", m_inputDevices);
		return;
	}
//	qDebug("HandleReadCallback '%s' subscribed",refName);
	bool continueSysEx = false;
	unsigned int nBytes;
	const MIDIPacket *packet = &pktlist->packet[0];
	unsigned char sysExMessage[SYSEX_LENGTH];
	unsigned int sysExLength = 0;
	
	for (uint32_t i=0; i<pktlist->numPackets; ++i)
	{
		nBytes = packet->length;
		// Check if this is the end of a continued SysEx message
		if (continueSysEx) {
			unsigned int lengthToCopy = qMin(nBytes, SYSEX_LENGTH - sysExLength);
			// Copy the message into our SysEx message buffer,
			// making sure not to overrun the buffer
			memcpy(sysExMessage + sysExLength, packet->data, lengthToCopy);
			sysExLength += lengthToCopy;
			// Check if the last byte is SysEx End.
			continueSysEx = (packet->data[nBytes - 1] == 0xF7);
			if (!continueSysEx || sysExLength == SYSEX_LENGTH) {
				// We would process the SysEx message here, as it is we're just ignoring it
				
				sysExLength = 0;
			}
		}
		else
		{
			UInt16 iByte, size;
			
			iByte = 0;
			while (iByte < nBytes)
			{
				size = 0;
				
				// First byte should be status
				unsigned char status = packet->data[iByte];
				if (status < 0xC0) {
					size = 3;
				}
				else if (status < 0xE0)
				{
					size = 2;
				}
				else if (status < 0xF0)
				{
					size = 3;
				}
				else if (status == 0xF0)
				{
					// MIDI SysEx then we copy the rest of the message into the SysEx message buffer
					unsigned int lengthLeftInMessage = nBytes - iByte;
					unsigned int lengthToCopy = qMin(lengthLeftInMessage, SYSEX_LENGTH);
					
					memcpy(sysExMessage + sysExLength, packet->data, lengthToCopy);
					sysExLength += lengthToCopy;
					
					size = 0;
					iByte = nBytes;
					
					// Check whether the message at the end is the end of the SysEx
					continueSysEx = (packet->data[nBytes - 1] != 0xF7);
				}
				else if (status < 0xF3)
				{
					size = 3;
				}
				else if (status == 0xF3)
				{
					size = 2;
				}
				else
				{
					size = 1;
				}
				
				unsigned char messageChannel = status & 0xF;
				const MidiEventTypes cmdtype = static_cast<MidiEventTypes>( status & 0xF0 );
				const int par1 = packet->data[iByte + 1];
				const int par2 = packet->data[iByte + 2];

				switch (cmdtype)
				{
					case MidiNoteOff: //0x80:
					case MidiNoteOn: //0x90:
					case MidiKeyPressure: //0xA0:
						notifyMidiPortList(m_inputSubs[refName],MidiEvent( cmdtype, messageChannel, par1 - KeysPerOctave, par2 & 0xff, &endPointRef ));
						break;
						
					case MidiControlChange: //0xB0:
					case MidiProgramChange: //0xC0:
					case MidiChannelPressure: //0xD0:
						notifyMidiPortList(m_inputSubs[refName],MidiEvent( cmdtype, messageChannel, par1, par2 & 0xff, &endPointRef ));
						break;
						
					case MidiPitchBend: //0xE0:
						notifyMidiPortList(m_inputSubs[refName],MidiEvent( cmdtype, messageChannel, par1 + par2 * 128, 0, &endPointRef ));
						break;
					case MidiActiveSensing: //0xF0
					case 0xF0:
						break;
					default:
						qDebug("endPointRef name='%s':Some other message %d", refName, cmdtype);
						break;
				}
				iByte += size;
			}
		}
		packet = MIDIPacketNext(packet);
	}
}
void InstrumentTrack::updatePitch()
{
	updateBaseNote();

	processOutEvent( MidiEvent( MidiPitchBend, midiPort()->realOutputChannel(), midiPitch() ) );
}
void InstrumentTrackView::activityIndicatorReleased()
{
	model()->processInEvent( MidiEvent( MidiNoteOff, 0, DefaultKey, 0 ) );
}
void InstrumentTrackView::activityIndicatorPressed()
{
	model()->processInEvent( MidiEvent( MidiNoteOn, 0, DefaultKey, MidiDefaultVelocity ) );
}
예제 #20
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;
      }
예제 #21
0
NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack,
								const f_cnt_t _offset,
								const f_cnt_t _frames,
								const note& n,
								NotePlayHandle *parent,
								int midiEventChannel,
								Origin origin ) :
	PlayHandle( TypeNotePlayHandle, _offset ),
	note( n.length(), n.pos(), n.key(), n.getVolume(), n.getPanning(), n.detuning() ),
	m_pluginData( NULL ),
	m_filter( NULL ),
	m_instrumentTrack( instrumentTrack ),
	m_frames( 0 ),
	m_totalFramesPlayed( 0 ),
	m_framesBeforeRelease( 0 ),
	m_releaseFramesToDo( 0 ),
	m_releaseFramesDone( 0 ),
	m_released( false ),
	m_hasParent( parent != NULL  ),
	m_hadChildren( false ),
	m_muted( false ),
	m_bbTrack( NULL ),
	m_origTempo( engine::getSong()->getTempo() ),
	m_origBaseNote( instrumentTrack->baseNote() ),
	m_frequency( 0 ),
	m_unpitchedFrequency( 0 ),
	m_baseDetuning( NULL ),
	m_songGlobalParentOffset( 0 ),
	m_midiChannel( midiEventChannel >= 0 ? midiEventChannel : instrumentTrack->midiPort()->realOutputChannel() ),
	m_origin( origin )
{
	if( hasParent() == false )
	{
		m_baseDetuning = new BaseDetuning( detuning() );
		m_instrumentTrack->m_processHandles.push_back( this );
	}
	else
	{
		m_baseDetuning = parent->m_baseDetuning;

		parent->m_subNotes.push_back( this );
		parent->m_hadChildren = true;

		m_bbTrack = parent->m_bbTrack;
	}

	updateFrequency();

	setFrames( _frames );

	// inform attached components about new MIDI note (used for recording in Piano Roll)
	if( m_origin == OriginMidiInput )
	{
		m_instrumentTrack->midiNoteOn( *this );
	}

	if( hasParent() || ! m_instrumentTrack->isArpeggioEnabled() )
	{
		const int baseVelocity = m_instrumentTrack->midiPort()->baseVelocity();

		// send MidiNoteOn event
		m_instrumentTrack->processOutEvent(
			MidiEvent( MidiNoteOn, midiChannel(), midiKey(), midiVelocity( baseVelocity ) ),
			MidiTime::fromFrames( offset(), engine::framesPerTick() ), 
			offset() );
	}
}
예제 #22
0
void ZynAddSubFxInstrument::sendControlChange( MidiControllers midiCtl, float value )
{
    handleMidiEvent( MidiEvent( MidiControlChange, instrumentTrack()->midiPort()->realOutputChannel(), midiCtl, (int) value, this ) );
}
예제 #23
0
void MidiAlsaSeq::run()
{
	// watch the pipe and sequencer input events
	int pollfd_count = snd_seq_poll_descriptors_count( m_seqHandle,
								POLLIN );
	struct pollfd * pollfd_set = new struct pollfd[pollfd_count + 1];
	snd_seq_poll_descriptors( m_seqHandle, pollfd_set + 1, pollfd_count,
								POLLIN );
	pollfd_set[0].fd = m_pipe[0];
	pollfd_set[0].events = POLLIN;
	++pollfd_count;

	while( m_quit == false )
	{
		int pollRet = poll( pollfd_set, pollfd_count, EventPollTimeOut );
		if( pollRet == 0 )
		{
			continue;
		}
		else if( pollRet == -1 )
		{
			// gdb may interrupt the poll
			if( errno == EINTR )
			{
				continue;
			}
			qCritical( "error while polling ALSA sequencer handle" );
			break;
		}
		// shutdown?
		if( m_quit )
		{
			break;
		}

		m_seqMutex.lock();

		// while event queue is not empty
		while( snd_seq_event_input_pending( m_seqHandle, true ) > 0 )
		{
			snd_seq_event_t * ev;
			if( snd_seq_event_input( m_seqHandle, &ev ) < 0 )
			{
				m_seqMutex.unlock();

				qCritical( "error while fetching MIDI event from sequencer" );
				break;
			}
			m_seqMutex.unlock();

			snd_seq_addr_t * source = NULL;
			MidiPort * dest = NULL;
			for( int i = 0; i < m_portIDs.size(); ++i )
			{
				if( m_portIDs.values()[i][0] == ev->dest.port )
				{
					dest = m_portIDs.keys()[i];
				}
				if( ( m_portIDs.values()[i][1] != -1 &&
						m_portIDs.values()[i][1] == ev->source.port ) ||
							m_portIDs.values()[i][0] == ev->source.port )
				{
					source = &ev->source;
				}
			}

			if( dest == NULL )
			{
				continue;
			}

			switch( ev->type )
			{
				case SND_SEQ_EVENT_NOTEON:
					dest->processInEvent( MidiEvent( MidiNoteOn,
								ev->data.note.channel,
								ev->data.note.note -
								KeysPerOctave,
								ev->data.note.velocity,
								source
								),
							MidiTime( ev->time.tick ) );
					break;

				case SND_SEQ_EVENT_NOTEOFF:
					dest->processInEvent( MidiEvent( MidiNoteOff,
								ev->data.note.channel,
								ev->data.note.note -
								KeysPerOctave,
								ev->data.note.velocity,
								source
								),
							MidiTime( ev->time.tick) );
					break;

				case SND_SEQ_EVENT_KEYPRESS:
					dest->processInEvent( MidiEvent(
									MidiKeyPressure,
								ev->data.note.channel,
								ev->data.note.note -
								KeysPerOctave,
								ev->data.note.velocity,
								source
								), MidiTime() );
					break;

				case SND_SEQ_EVENT_CONTROLLER:
					dest->processInEvent( MidiEvent(
								MidiControlChange,
							ev->data.control.channel,
							ev->data.control.param,
							ev->data.control.value, source ),
									MidiTime() );
					break;

				case SND_SEQ_EVENT_PGMCHANGE:
					dest->processInEvent( MidiEvent(
								MidiProgramChange,
							ev->data.control.channel,
							ev->data.control.param,
							ev->data.control.value, source ),
									MidiTime() );
					break;

				case SND_SEQ_EVENT_CHANPRESS:
					dest->processInEvent( MidiEvent(
								MidiChannelPressure,
							ev->data.control.channel,
							ev->data.control.param,
							ev->data.control.value, source ),
									MidiTime() );
					break;

				case SND_SEQ_EVENT_PITCHBEND:
					dest->processInEvent( MidiEvent( MidiPitchBend,
							ev->data.control.channel,
							ev->data.control.value + 8192, 0, source ),
									MidiTime() );
					break;

				case SND_SEQ_EVENT_SENSING:
				case SND_SEQ_EVENT_CLOCK:
					break;

				default:
					fprintf( stderr,
						"ALSA-sequencer: unhandled input "
							"event %d\n", ev->type );
					break;
			}	// end switch

			m_seqMutex.lock();

		}	// end while

		m_seqMutex.unlock();

	}

	delete[] pollfd_set;
}