Skip to content

Commit

Permalink
it was good thing for me to wake up this morning - i fixed note linki…
Browse files Browse the repository at this point in the history
…ng. combining a semibreve with an eight now sounds brilliantly, like it realy was a single note
  • Loading branch information
klesun authored and klesun committed Dec 25, 2015
1 parent 0b3a955 commit f77980b
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 48 deletions.
2 changes: 2 additions & 0 deletions src/org/shmidusic/sheet_music/staff/StaffComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.stream.Stream;

// TODO: merge with AbstractPainter
public class StaffComponent extends JPanel implements IComponent
Expand Down
2 changes: 1 addition & 1 deletion src/org/shmidusic/sheet_music/staff/chord/Chord.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public Note addNewNote(INote source) {
}

public Note addNewNote(int tune, int channel) {
return add(new Note().setTune(tune).setChannel(channel)
return add(new Note(tune, channel)
.setKeydownTimestamp(System.currentTimeMillis()));
}

Expand Down
13 changes: 9 additions & 4 deletions src/org/shmidusic/sheet_music/staff/chord/note/Note.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

import org.json.JSONObject;

// TODO: rename to Note
public class Note extends AbstractModel implements INote
{
// <editor-fold desc="model field declaration">
Expand All @@ -27,14 +26,20 @@ public class Note extends AbstractModel implements INote
final public Field<Boolean> isSharp = new Field<>("isSharp", false, this);
/** @unused */
final private Field<Boolean> isMuted = new Field<>("isMuted", false, this);
/** @broken */
final private Field<Boolean> isLinkedToNext = new Field<>("isLinkedToNext", false, this);
final public Field<Boolean> isLinkedToNext = new Field<>("isLinkedToNext", false, this);

final private static int MAX_DOT_COUNT = 3;
final private static int PAUSE_POSITION = 3 * 7;

// </editor-fold>

public Note() {}

public Note(int tuneValue, int channelValue) {
tune.set(tuneValue);
channel.set(channelValue);
}

public long keydownTimestamp;

public Boolean isLongerThan(Note rival) { return getRealLength().compareTo(rival.getRealLength()) > 0; }
Expand Down Expand Up @@ -153,8 +158,8 @@ public Note setTune(int value) {
/** @Bug - note is immutable, this will blow with fatal !!! */
public Note setChannel(int value) { this.channel.set(value); return this; }
public Note setIsSharp(Boolean value) { this.isSharp.set(value); return this; }
public Note setIsTriplet(Boolean value) { this.isTriplet.set(value); return this; }
public Note setIsMuted(Boolean value) { this.isMuted.set(value); return this; }
public Note setIsLinkedToNext(Boolean value) { this.isLinkedToNext.set(value); return this; }

// </editor-fold>

Expand Down
7 changes: 4 additions & 3 deletions src/org/shmidusic/stuff/midi/DeviceEbun.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import org.klesun_model.Explain;
import org.shmidusic.sheet_music.staff.staff_config.StaffConfig;
import org.shmidusic.stuff.tools.ISound;
import org.shmidusic.stuff.tools.Logger;
import org.shmidusic.stuff.tools.INote;

Expand All @@ -28,7 +29,7 @@ public class DeviceEbun {
static DeviceEbun instance = null;

// TODO: It's very bad that we have one set for both devices. Try pressing ctrl-d while something is sounding, it will be fun ^_^.
private static TreeSet<INote> openNoteSet = new TreeSet<>();
private static TreeSet<ISound> openNoteSet = new TreeSet<>();

private static MidiDevice device;
private static MidiDevice gervill;
Expand Down Expand Up @@ -137,7 +138,7 @@ public static void setInstrument(int channel, int value) {
sendMessage(ShortMessage.PROGRAM_CHANGE, channel, value, 0);
}

synchronized public static void openNote(INote note)
synchronized public static void openNote(ISound note)
{
if (openNoteSet.contains(note)) {
closeNote(note);
Expand All @@ -153,7 +154,7 @@ synchronized public static void openNote(INote note)

// TODO: when a note was opened more than one time: blink
// sounding and don't close till all are closed (like on the site)
synchronized public static void closeNote(INote note)
synchronized public static void closeNote(ISound note)
{
openNoteSet.remove(note);
if (note.getChannel() != DRUM_CHANNEL) {
Expand Down
8 changes: 7 additions & 1 deletion src/org/shmidusic/stuff/midi/IMidiScheduler.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@

public interface IMidiScheduler
{
void addNoteTask(Fraction when, INote note);
// read "final"
default void addNoteTask(Fraction when, INote note) {
addNoteOnTask(when, note.getTune(), note.getChannel());
addNoteOffTask(when.add(note.getRealLength()), note.getTune(), note.getChannel());
}
void addNoteOnTask(Fraction when, int tune, int channel);
void addNoteOffTask(Fraction when, int tune, int channel);
}
18 changes: 12 additions & 6 deletions src/org/shmidusic/stuff/midi/SmfScheduler.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@ public SmfScheduler(Map<Integer, Track> trackDict, StaffConfig config) {
this.config = config;
}

public void addNoteTask(Fraction when, INote note) {
if (!trackDict.containsKey(note.getChannel())) {
trackDict.put(note.getChannel(), new Track());
}
trackDict.get(note.getChannel()).addEvent(new NoteOn(note, time(when)));
trackDict.get(note.getChannel()).addEvent(new NoteOff(note, time(when.add(note.getRealLength()))));
public void addNoteOnTask(Fraction when, int tune, int channel) {
getTrack(channel).addEvent(new NoteOn(new Note(tune, channel), time(when)));
}

public void addNoteOffTask(Fraction when, int tune, int channel) {
getTrack(channel).addEvent(new NoteOff(new Note(tune, channel), time(when)));
}

private Track getTrack(int channel) {
return trackDict.containsKey(channel)
? trackDict.get(channel)
: trackDict.put(channel, new Track());
}

private int time(Fraction f) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import org.shmidusic.stuff.midi.standard_midi_file.MidiUtil;
import org.shmidusic.stuff.tools.INote;
import org.shmidusic.stuff.tools.ISound;

import java.io.DataOutputStream;
import java.io.DataInputStream;
Expand Down Expand Up @@ -62,7 +63,7 @@ public NoteOn(short pitch, short velocity, short midiChannel, int time){
this.time = time;
}

public NoteOn(INote note, int time)
public NoteOn(ISound note, int time)
{
this(note.getTune().shortValue(), (short)127, note.getChannel().shortValue(), time);
}
Expand Down
66 changes: 44 additions & 22 deletions src/org/shmidusic/stuff/musica/Playback.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@
import org.klesun_model.Explain;
import org.shmidusic.sheet_music.staff.Staff;
import org.apache.commons.math3.fraction.Fraction;
import org.shmidusic.sheet_music.staff.chord.ChordComponent;
import org.shmidusic.sheet_music.staff.chord.note.Note;
import org.shmidusic.sheet_music.staff.chord.note.NoteComponent;
import org.shmidusic.stuff.midi.DeviceEbun;
import org.shmidusic.stuff.midi.IMidiScheduler;
import org.shmidusic.stuff.midi.SmfScheduler;
import org.shmidusic.stuff.tools.INote;
import org.shmidusic.stuff.tools.Logger;

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class Playback {

Expand All @@ -26,31 +32,30 @@ public Playback(StaffComponent staffComp) {
}

public void trigger() {
interrupt();
if (this.runningProcess == null) {
DeviceEbun.closeAllNotes();
play();
} else {
interrupt();
}
}

public Boolean interrupt() {
if (this.runningProcess != null) {
DeviceEbun.closeAllNotes();
this.runningProcess.interrupt();
this.runningProcess = null;
}
DeviceEbun.closeAllNotes();
return true;
}

private Explain play() {
Staff staff = staffComp.staff;
if (!staff.getChordList().isEmpty()) {
if (runningProcess != null) { interrupt(); }
if (staff.getConfig().useHardcoreSynthesizer.get()) {
// TODO: try to do it with two PlaybackTimer-s - one for music and other for repaint requests
runningProcess = new PlaybackTimer.KlesunthesizerTimer(staff.getConfig());
} else {
runningProcess = new PlaybackTimer(staff.getConfig());
}

runningProcess = staff.getConfig().useHardcoreSynthesizer.get()
? new PlaybackTimer.KlesunthesizerTimer(staff.getConfig())
: new PlaybackTimer(staff.getConfig());

staffComp.moveFocus(-1);
int startFrom = staff.getFocusedIndex() + 1;
Expand All @@ -72,26 +77,43 @@ public void streamTo(IMidiScheduler scheduler) {
private void streamTo(IMidiScheduler scheduler, int startFrom, Consumer<Fraction> onAccord)
{
Fraction sumFraction = new Fraction(0);
Set<Note> openedLinks = new HashSet<>();

for (Chord chord : staffComp.staff.getChordList().subList(startFrom, staffComp.staff.getChordList().size())) {
final Fraction finalStart = sumFraction;

chord.noteStream(n -> true).forEach(n -> playNote(n, finalStart, scheduler));
final Fraction noteStart = sumFraction;

chord.noteStream().forEach(note -> {
if (note.getTune() != 0) { // 0 means pause in my world

// TODO: we don't handle a case here when a note with same tune
// and channel happened during linked sounding cuz we just ignore
// linked note length, what should be remastered. it's a rare case,
// so low priority and i can't think how it can be done... something
// like storing supposed time with Note in the set... i'm not sure we
// even need this, cuz it's same as if we played a do when the do is
// already sounding with normal lengths (it's impossible, midi would screw up)
// TODO: move this todo to a task on github

if (!openedLinks.contains(note)) {
scheduler.addNoteOnTask(noteStart, note.tune.get(), note.getChannel());
if (note.isLinkedToNext.get()) {
openedLinks.add(note);
}
}

if (!note.isLinkedToNext.get()) {
scheduler.addNoteOffTask(noteStart.add(note.getRealLength()), note.tune.get(), note.getChannel());
openedLinks.remove(note);
}
}
});
onAccord.accept(sumFraction);
sumFraction = sumFraction.add(chord.getFraction());
}
}

private static void playNote(INote note, Fraction start, IMidiScheduler scheduler)
{
if (note.getTune() != 0) { // 0 means pause in my world
if (!Main.isLinux || scheduler instanceof SmfScheduler || true) { /** @debug */
scheduler.addNoteTask(start, note);
} else {
// making sound lag a bit, so it fitted lagging graphics ^_^
// TODO: maybe move this hack into preferences with parameter one day...
scheduler.addNoteTask(start.add(new Fraction(1, 16)), note);
}
if (openedLinks.size() > 0) {
Logger.warning("Got unclosed linked notes: " + Arrays.toString(openedLinks.toArray()));
}
}

Expand Down
9 changes: 6 additions & 3 deletions src/org/shmidusic/stuff/musica/PlaybackTimer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ public PlaybackTimer(StaffConfig config) {
this.config = config;
}

public void addNoteTask(Fraction when, INote note) {
addTask(when, () -> DeviceEbun.openNote(note));
addTask(when.add(note.getRealLength()), () -> DeviceEbun.closeNote(note));
public void addNoteOnTask(Fraction when, int tune, int channel) {
addTask(when, () -> DeviceEbun.openNote(new Note(tune, channel)));
}

public void addNoteOffTask(Fraction when, int tune, int channel) {
addTask(when, () -> DeviceEbun.closeNote(new Note(tune, channel)));
}

public void addTask(Fraction fraction, Runnable task)
Expand Down
8 changes: 1 addition & 7 deletions src/org/shmidusic/stuff/tools/INote.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,11 @@

import java.util.Arrays;

public interface INote extends Comparable<INote> {
public interface INote extends ISound {

Integer getTune();
Integer getChannel();
Fraction getLength();
Boolean isTriplet();

default int compareTo(INote n) {
return ((n.getTune() - this.getTune()) << 4) + (n.getChannel() - this.getChannel());
}

static Fraction legnthNorm(Fraction value) {
// Commented for now, but not sure that made right thing
// if (value.equals(new Fraction(0))) {
Expand Down
13 changes: 13 additions & 0 deletions src/org/shmidusic/stuff/tools/ISound.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.shmidusic.stuff.tools;

// a note without length

public interface ISound extends Comparable<ISound>
{
Integer getTune();
Integer getChannel();

default int compareTo(ISound n) {
return ((n.getTune() - this.getTune()) << 4) + (n.getChannel() - this.getChannel());
}
}

0 comments on commit f77980b

Please sign in to comment.