/** * Obtains the file types that this provider can write from the * sequence specified. * @param sequence the sequence for which midi file type support * is queried * @return array of file types. If no file types are supported, * returns an array of length 0. */ public int[] getMidiFileTypes(Sequence sequence){ int typesArray[]; Track tracks[] = sequence.getTracks(); if( tracks.length==1 ) { typesArray = new int[2]; typesArray[0] = MIDI_TYPE_0; typesArray[1] = MIDI_TYPE_1; } else { typesArray = new int[1]; typesArray[0] = MIDI_TYPE_1; } return typesArray; }
@Override public void recordEnable(Track track, int channel) { if (!findTrack(track)) { throw new IllegalArgumentException("Track does not exist in the current sequence"); } synchronized(recordingTracks) { RecordingTrack rc = RecordingTrack.get(recordingTracks, track); if (rc != null) { rc.channel = channel; } else { recordingTracks.add(new RecordingTrack(track, channel)); } } }
/** * Obtains the file types that this provider can write from the * sequence specified. * @param sequence the sequence for which midi file type support * is queried * @return array of file types. If no file types are supported, * returns an array of length 0. */ @Override public int[] getMidiFileTypes(Sequence sequence){ int typesArray[]; Track tracks[] = sequence.getTracks(); if( tracks.length==1 ) { typesArray = new int[2]; typesArray[0] = MIDI_TYPE_0; typesArray[1] = MIDI_TYPE_1; } else { typesArray = new int[1]; typesArray[0] = MIDI_TYPE_1; } return typesArray; }
/** * scan the part attribute name for a known string to create a gm program change and instrument name event * @param part * @param track the track that shall correspond to the part * @param generateProgramChanges if true, program change events are generated (useful for MIR and as a cheap kind of piano reduction) */ private void partName(Element part, Track track, boolean generateProgramChanges) { short chan = Short.parseShort(part.getAttributeValue("midi.channel")); if ((part.getAttribute("name") == null) || part.getAttributeValue("name").isEmpty()) { // if there is no name if (generateProgramChanges) track.add(EventMaker.createProgramChange(chan, 0, (short)0)); // add program change event for Acoustic Grand Piano track.add(EventMaker.createInstrumentName(0, "")); // add an empty instrument name event to the track return; } String name = part.getAttributeValue("name"); if (generateProgramChanges) track.add(EventMaker.createProgramChange(chan, 0, name)); // add program change event track.add(EventMaker.createInstrumentName(0, name)); // add an instrument name event to the track }
/** * parse the elements in the score map of part (part.dated.score) to midi events and add them to track * * @param part the msm source * @param track the midi track */ private void parseScore(Element part, Track track) { if ((part.getFirstChildElement("dated") == null) || (part.getFirstChildElement("dated").getFirstChildElement("score") == null) || (part.getAttribute("midi.channel") == null)) // if no sufficient information return; // cancel int chan = Integer.parseInt(part.getAttributeValue("midi.channel")); // get the midi channel number for (Element n = part.getFirstChildElement("dated").getFirstChildElement("score").getFirstChildElement("note"); n != null; n = Helper.getNextSiblingElement("note", n)) { // go through all note elements in score // switch (n.getLocalName()) { // case "rest": // rests are not represented in midi // break; // case "note": // for note elements create note_on and note_off events int pitch = Math.round(Float.parseFloat(n.getAttributeValue("midi.pitch"))); // Math.round(float) returns int; so far pitches are well captured by number type float long date = Math.round(Double.parseDouble(n.getAttributeValue("midi.date"))); // Math.round(double) returns long long dur = Math.round(Double.parseDouble(n.getAttributeValue("midi.duration"))); track.add(EventMaker.createNoteOn(chan, date, pitch, 100)); track.add(EventMaker.createNoteOff(chan, date + dur, pitch, 100)); // break; // } // TODO: process text (not implemented in mei-to-msm-export, yet, but planned to be added in the future) } }
/** * parse the markerMap and create marker events from it * @param part * @param track */ private void parseMarkerMap(Element part, Track track) { if ((part.getFirstChildElement("dated") == null) || (part.getFirstChildElement("dated").getFirstChildElement("markerMap") == null)) // if no sufficient information return; // cancel String message; // the marker message for (Element e = part.getFirstChildElement("dated").getFirstChildElement("markerMap").getFirstChildElement("marker"); e != null; e = Helper.getNextSiblingElement("marker", e)) { try { message = e.getAttributeValue("message"); } catch (NullPointerException | NumberFormatException error) { message = "marker"; } track.add(EventMaker.createMarker(Math.round(Double.parseDouble(e.getAttributeValue("midi.date"))), message)); } }
public void resetTracks(){ try { Sequence sequence = this.getSequencer().getSequence(); if(sequence != null){ Track[] tracks = sequence.getTracks(); if( tracks != null ){ int count = tracks.length; for( int i = 0 ; i < count; i++ ){ this.setSolo( i , false ); this.setMute( i , false ); } } } } catch (Throwable throwable) { throwable.printStackTrace(); } }
/** * Compute the length of a track as it will be written to the * output stream. * * @param track the track to measure * @param dos a MidiDataOutputStream used for helper method * @return the length of the track */ private int computeTrackLength(Track track, MidiDataOutputStream dos) { int count = 0, length = 0, i = 0, eventCount = track.size(); long ptick = 0; while (i < eventCount) { MidiEvent me = track.get(i); long tick = me.getTick(); length += dos.variableLengthIntLength((int) (tick - ptick)); ptick = tick; length += me.getMessage().getLength(); i++; } return length; }
/** * Exports the location of each slice into a MIDI file */ public Sequence exportMidiSequence(final File file, final int ppq) throws IOException { final double tempoBps = (double) getTempo() / 60.0; final MidiSequenceBuilder builder = new MidiSequenceBuilder(ppq); final Track track = builder.getTrack(); final int n = markers.size(); int startTick = 0; int key = 35; for (int i = 0; i < n; i++) { final int location = getLocation(i); startTick = (int) Math.round(ppq * tempoBps * location / samplingRate); int tickLength = 32; builder.addNote(track, startTick, tickLength, key++); } if (file != null) { builder.save(file); } return builder.getSequence(); }
/** * Add the given MidiNote into the {@link #sequence}. * * @param note The note to add. * * @throws InvalidMidiDataException If the MidiNote contains invalid Midi data. */ public void addMidiNote(MidiNote note) throws InvalidMidiDataException { int correctVoice = note.getCorrectVoice(); // Pad with enough tracks while (sequence.getTracks().length <= correctVoice) { sequence.createTrack(); } // Get the correct track Track track = sequence.getTracks()[correctVoice]; ShortMessage noteOn = new ShortMessage(); noteOn.setMessage(ShortMessage.NOTE_ON | correctVoice, note.getPitch(), note.getVelocity()); MidiEvent noteOnEvent = new MidiEvent(noteOn, note.getOnsetTick()); ShortMessage noteOff = new ShortMessage(); noteOff.setMessage(ShortMessage.NOTE_OFF | correctVoice, note.getPitch(), 0); MidiEvent noteOffEvent = new MidiEvent(noteOff, note.getOffsetTick()); track.add(noteOnEvent); track.add(noteOffEvent); }
/** * Gets the number of microseconds per quarter note for a sequence, used to * determine its BPM. * * @param sequence * @return */ private static int getMicrosecondsPerQuarterNote(Sequence sequence) { // Check all MIDI tracks for MIDI_SET_TEMPO message for (Track track : sequence.getTracks()) { for (int i = 0; i < track.size(); i++) { MidiEvent event = track.get(i); MidiMessage message = event.getMessage(); if (message instanceof MetaMessage) { MetaMessage m = (MetaMessage) message; byte[] data = m.getData(); int type = m.getType(); if (type == MIDI_SET_TEMPO) { return ((data[0] & 0xff) << 16) | ((data[1] & 0xff) << 8) | (data[2] & 0xff); } } } } return 0; }
/** * Called from Score * * Calls render in SectionInfo * * @param seq * @param time * @param track * @param transposition * @param useDrums * @param endLimitIndex * @param constantBass * @return * @throws InvalidMidiDataException */ public long render(MidiSequence seq, long time, Track track, Transposition transposition, boolean useDrums, int endLimitIndex, boolean constantBass) throws InvalidMidiDataException { // to trace sequencing info: // System.out.println("ChordPart time = " + time + ", endLimitIndex = " + endLimitIndex); long result = sectionInfo.render(seq, time, track, transposition, useDrums, endLimitIndex, constantBass); return result; }
/** * Adds this Note at the specified time on the specified Track and * channel in the specified Sequence, then returns the time that a * sequential Note should be added. * @param seq the Sequence to which to add this Note * @param track the Track in the Sequence to which to add this Note * @param time the time at which to start this Note * @param ch the channel on which to put this Note * @param transposition amount by which to transpose this note in semitones * @param sendBankSelect * @return * @throws javax.sound.midi.InvalidMidiDataException */ public long render(Sequence seq, Track track, long time, int ch, int transposition, boolean sendBankSelect) throws InvalidMidiDataException { if( sendBankSelect ) { } int dur = getRhythmValue(); long offTime = time + dur * seq.getResolution() / BEAT; render(seq, track, time, offTime, ch, transposition); return offTime; }
static public Polylist track2polylist(Track track) { PolylistBuffer buffer = new PolylistBuffer(); buffer.append(Polylist.list("ticks", track.ticks())); long len = track.size(); buffer.append(Polylist.list("events", len)); for( int i = 0; i < len; i++ ) { buffer.append(midiEvent2polylist(i, track.get(i))); } return buffer.toPolylist(); }
public void go() { setUpGui(); try { Sequencer sequencer = MidiSystem.getSequencer(); sequencer.open(); sequencer.addControllerEventListener(ml, new int[] {127}); Sequence seq = new Sequence(Sequence.PPQ, 4); Track track = seq.createTrack(); int r = 0; for (int i = 0; i < 60; i+=4) { r = (int) ((Math.random() * 50) + 1); track.add(makeEvent(144, 1, r, 100, i)); track.add(makeEvent(176, 1, 127, 0, i)); track.add(makeEvent(128, 1, r, 100, i + 2)); } // end loop sequencer.setSequence(seq); sequencer.start(); sequencer.setTempoInBPM(120); } catch (Exception ex) {ex.printStackTrace();} }
public void go() { try { Sequencer sequencer = MidiSystem.getSequencer(); sequencer.open(); int[] eventsIWant = {127}; sequencer.addControllerEventListener(this, eventsIWant); Sequence seq = new Sequence(Sequence.PPQ, 4); Track track = seq.createTrack(); for (int i = 5; i < 60; i+= 4) { track.add(makeEvent(144, 1, i, 100, i)); track.add(makeEvent(176, 1, 127, 0, i)); track.add(makeEvent(128, 1, i, 100, i + 2)); } // end loop sequencer.setSequence(seq); sequencer.setTempoInBPM(220); sequencer.start(); } catch (Exception ex) {ex.printStackTrace();} }
public static void main(String[] args) { try { // make and open a sequencer Sequencer sequencer = MidiSystem.getSequencer(); sequencer.open(); // make a sequence and a track Sequence seq = new Sequence(Sequence.PPQ, 4); Track track = seq.createTrack(); // make a bunch of events to make the notes keep going up // (from piano note 5 to piano note 61) for (int i = 5; i < 61; i+=4) { track.add(makeEvent(144, 1, i, 100, i)); track.add(makeEvent(128, 1, i, 100, i + 2)); } // end loop sequencer.setSequence(seq); sequencer.setTempoInBPM(220); sequencer.start(); } catch (Exception ex) {ex.printStackTrace();} }
/** * Find the first tempo meta message and return the tempo value * @return */ public static float findFirstTempo(Sequence sequence) throws Exception { for(Track track : sequence.getTracks()) { for(int n=0;n<track.size();n++) { MidiEvent event = track.get(n); if(event.getMessage() instanceof MetaMessage && ((MetaMessage)event.getMessage()).getType()==0x51) { float tempo = new TempoMessage((MetaMessage)event.getMessage()).getBpm(); System.out.println("Found tempomessage "+tempo+" bpm"); return tempo; } } } throw new Exception("No tempo message found"); }
/** * Returns a clone of this sequence suitable for Midi file export. What it does is to map the FTW channel setting to all the midi events * for the corresponding tracks * @return * @throws InvalidMidiDataException */ public Sequence export() throws InvalidMidiDataException { Sequence newSeq = new Sequence(getDivisionType(),getResolution()); for(FrinikaTrackWrapper ftw : frinikaTrackWrappers) { Track track = newSeq.createTrack(); for(int n=0;n<ftw.size();n++) { MidiEvent sourceMidiEvent = ftw.get(n); MidiMessage msg = sourceMidiEvent.getMessage(); if(msg instanceof ShortMessage) { ShortMessage shm = (ShortMessage)msg; ShortMessage nshm = new ShortMessage(); nshm.setMessage(shm.getCommand(),ftw.getMidiChannel(),shm.getData1(),shm.getData2()); msg = nshm; } MidiEvent newEvent = new MidiEvent(msg,sourceMidiEvent.getTick()); track.add(newEvent); } } return newSeq; }
/** * Render a bar of notes as MIDI to the specified Track from the * specified start tick with the specified ticks per bar. * @param notes the notes to render * @param track the MIDI Track to render to * @param startTick the tick at the start of the bar * @param ticksPerBar the number of ticks per bar */ public void renderBar(int[] notes, Track track, long startTick, int ppqn) throws InvalidMidiDataException { final int channel = getInstrument().getChannel(); MidiMessage msg; for ( int i = 0; i < notes.length; i++) { int note = notes[i]; float timeOn = swing(Note.getTime(note)); int pitch = Note.getPitch(note); int level = Note.getLevel(note); long onTick = ticks2MidiTicks(timeOn, ppqn); msg = ChannelMsg.createChannel( ChannelMsg.NOTE_ON, channel, pitch, level); track.add(new MidiEvent(msg, startTick + onTick)); // note off msg = ChannelMsg.createChannel( ChannelMsg.NOTE_OFF, channel, pitch, 0); float timeOff = swing(Note.getTime(note)+Note.getDuration(note)); long offTick = ticks2MidiTicks(timeOff, ppqn); track.add(new MidiEvent(msg, startTick + offTick)); } }
/** Create a sequence from an InputStream. * This is the counterpart of {@link MidiSystem#getSequence(InputStream)} * for MUS format. * * @param is MUS data (this method does not try to auto-detect the format.) */ public static Sequence getSequence(InputStream is) throws IOException, InvalidMidiDataException { DataInputStream dis = new DataInputStream(is); dis.skip(6); int rus = dis.readUnsignedShort(); short scoreStart = Swap.SHORT((char) rus); dis.skip(scoreStart - 8); Sequence sequence = new Sequence(Sequence.SMPTE_30, 14, 1); Track track = sequence.getTracks()[0]; int[] chanVelocity = new int[16]; Arrays.fill(chanVelocity, 100); EventGroup eg; long tick = 0; while ((eg = nextEventGroup(dis, chanVelocity)) != null) { tick = eg.appendTo(track, tick); } MetaMessage endOfSequence = new MetaMessage(); endOfSequence.setMessage(47, new byte[] {0}, 1); track.add(new MidiEvent(endOfSequence, tick)); return sequence; }
private void addMidiTempoEvents(Track track0) { for (QuantizedTimingInfo.TimingInfoEvent event : qtm.getTimingInfoByTick().values()) { if (event.tick > exportEndTick) break; track0.add(MidiFactory.createTempoEvent(event.info.getTempoMPQ(), event.tick)); if (event.tick == 0) { // The Java MIDI sequencer can sometimes miss a tempo event at tick 0 // Add another tempo event at tick 1 to work around the bug track0.add(MidiFactory.createTempoEvent(event.info.getTempoMPQ(), 1)); } } }
public long calcLastNoteTick() { long lastNoteTick = 0; for (Track t : sequence.getTracks()) { for (int j = t.size() - 1; j >= 0; j--) { MidiEvent evt = t.get(j); MidiMessage msg = evt.getMessage(); if (msg instanceof ShortMessage) { ShortMessage m = (ShortMessage) msg; if (m.getCommand() == ShortMessage.NOTE_OFF) { if (evt.getTick() > lastNoteTick) { lastNoteTick = evt.getTick(); } break; } } } } return lastNoteTick; }
/** * test method getPatchList() * */ public void test_getPatchList() throws Exception { //TODO /* * I don't understand how this method works */ Sequence seq = new Sequence(Sequence.PPQ, 987, 2); Track tr = seq.createTrack(); MidiEvent event1 = new MidiEvent(new MidiMessage1(new byte[] {1, 2, 3, 34, -98, -27}), -10L); MidiEvent event2 = new MidiEvent(new MidiMessage1(new byte[] {23, -16, 4, 78, -12, 5}), 3L); MidiEvent event3 = new MidiEvent(new MidiMessage1(new byte[] {3, -67, -1, 87, 9, 8, -2}), 6L); tr.add(event1); tr.add(event3); Track tr1 = seq.createTrack(); tr1.add(event2); assertEquals(0, seq.getPatchList().length); }
/** * test method getTickLength() * */ public void test_getTickLength() throws Exception { Sequence seq = new Sequence(Sequence.SMPTE_24, 67, 9); Track tr = seq.createTrack(); MidiEvent event1 = new MidiEvent(new MidiMessage1(new byte[] {1, 2, 3}), -10L); MidiEvent event2 = new MidiEvent(new MidiMessage1(new byte[] {23, -16, 4}), 2L); MidiEvent event3 = new MidiEvent(new MidiMessage1(new byte[] {3, -67, -1}), 6L); tr.add(event1); tr.add(event2); assertEquals(2, seq.getTickLength()); Track tr1 = seq.createTrack(); tr1.add(event1); tr1.add(event2); tr1.add(event3); assertEquals(6, seq.getTickLength()); seq.deleteTrack(tr1); assertEquals(2, seq.getTickLength()); seq.deleteTrack(tr); assertEquals(0, seq.getTickLength()); }
/** * test method getTracks() * */ public void test_getTracks() throws Exception { Sequence seq = new Sequence(Sequence.SMPTE_24, 67, 9); seq.createTrack(); Track tr1 = seq.createTrack(); Track[] tracks = seq.getTracks(); assertEquals(11, tracks.length); /* * actions with array doesn't influence on * initial data... */ assertEquals(tr1, tracks[10]); tracks[10] = null; assertTrue(seq.deleteTrack(tr1)); assertTrue(seq.deleteTrack(tracks[9])); /* * ...and action with initial data doesn't * influence on array */ assertEquals(11, tracks.length); }
/** * Compute the length of a track as it will be written to the * output stream. * * @param track the track to measure * @param dos a MidiDataOutputStream used for helper method * @return the length of the track */ private int computeTrackLength(Track track, MidiDataOutputStream dos) { int length = 0, i = 0, eventCount = track.size(); long ptick = 0; while (i < eventCount) { MidiEvent me = track.get(i); long tick = me.getTick(); length += dos.variableLengthIntLength((int) (tick - ptick)); ptick = tick; length += me.getMessage().getLength(); i++; } return length; }