improved the MIDI component

This commit is contained in:
hneemann 2019-02-10 20:20:18 +01:00
parent 39c0c921ee
commit 9bc188d69e
5 changed files with 64 additions and 36 deletions

View File

@ -22,30 +22,34 @@ import static de.neemann.digital.core.element.PinInfo.input;
/** /**
* The speaker. * The speaker.
*/ */
public class Speaker extends Node implements Element { public class MIDI extends Node implements Element {
/** /**
* The Speakers description * The Speakers description
*/ */
public static final ElementTypeDescription DESCRIPTION public static final ElementTypeDescription DESCRIPTION
= new ElementTypeDescription(Speaker.class, input("N"), input("V"), input("en")) {} = new ElementTypeDescription(MIDI.class,
input("N"),
input("V"),
input("OnOff"),
input("C").setClock())
.addAttribute(Keys.MIDICHANNEL) .addAttribute(Keys.MIDICHANNEL)
.addAttribute(Keys.ROTATE); .addAttribute(Keys.ROTATE);
private final int chanNum; private final int chanNum;
private ObservableValue note; private ObservableValue note;
private ObservableValue volume; private ObservableValue volume;
private ObservableValue enable; private ObservableValue clock;
private ObservableValue onOff;
private MidiChannel channel; private MidiChannel channel;
private boolean lastEn = false; private boolean lastCl = false;
private int notePlaying;
/** /**
* Creates a new instance * Creates a new instance
* *
* @param attributes the elements attributes * @param attributes the elements attributes
*/ */
public Speaker(ElementAttributes attributes) { public MIDI(ElementAttributes attributes) {
chanNum = attributes.get(Keys.MIDICHANNEL); chanNum = attributes.get(Keys.MIDICHANNEL);
} }
@ -53,7 +57,8 @@ public class Speaker extends Node implements Element {
public void setInputs(ObservableValues inputs) throws NodeException { public void setInputs(ObservableValues inputs) throws NodeException {
note = inputs.get(0).checkBits(7, this, 0); note = inputs.get(0).checkBits(7, this, 0);
volume = inputs.get(1).checkBits(7, this, 1); volume = inputs.get(1).checkBits(7, this, 1);
enable = inputs.get(2).checkBits(1, this, 2).addObserverToValue(this); onOff = inputs.get(2).checkBits(1, this, 2);
clock = inputs.get(3).checkBits(1, this, 3).addObserverToValue(this);
} }
@Override @Override
@ -63,17 +68,16 @@ public class Speaker extends Node implements Element {
@Override @Override
public void readInputs() throws NodeException { public void readInputs() throws NodeException {
boolean en = enable.getBool(); boolean cl = clock.getBool();
if (channel != null) { if (!lastCl && cl) {
if (!lastEn && en) { int note = (int) this.note.getValue();
notePlaying = (int) note.getValue(); if (onOff.getBool()) {
int v = (int) volume.getValue(); int v = (int) volume.getValue();
channel.noteOn(notePlaying, v); channel.noteOn(note, v);
} else if (lastEn && !en) { } else
channel.noteOff(notePlaying); channel.noteOff(note);
} }
} lastCl = cl;
lastEn = en;
} }
@Override @Override
@ -86,10 +90,16 @@ public class Speaker extends Node implements Element {
Synthesizer synth = MidiSystem.getSynthesizer(); Synthesizer synth = MidiSystem.getSynthesizer();
synth.open(); synth.open();
MidiChannel[] channels = synth.getChannels(); MidiChannel[] channels = synth.getChannels();
if (chanNum >= channels.length) if (chanNum >= channels.length) {
channel = channels[0]; synth.close();
else throw new NodeException(Lang.get("err_midiChannel_N_NotAvailable", chanNum));
}
channel = channels[chanNum]; channel = channels[chanNum];
if (channel == null) {
synth.close();
throw new NodeException(Lang.get("err_midiChannel_N_NotAvailable", chanNum));
}
model.addObserver(event -> { model.addObserver(event -> {
if (event.equals(ModelEvent.STOPPED)) if (event.equals(ModelEvent.STOPPED))

View File

@ -141,7 +141,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
.add(RotEncoder.DESCRIPTION) .add(RotEncoder.DESCRIPTION)
.add(Keyboard.DESCRIPTION) .add(Keyboard.DESCRIPTION)
.add(Terminal.DESCRIPTION) .add(Terminal.DESCRIPTION)
.add(Speaker.DESCRIPTION))) .add(MIDI.DESCRIPTION)))
.add(new LibraryNode(Lang.get("lib_wires")) .add(new LibraryNode(Lang.get("lib_wires"))
.add(Ground.DESCRIPTION) .add(Ground.DESCRIPTION)
.add(VDD.DESCRIPTION) .add(VDD.DESCRIPTION)

View File

@ -258,11 +258,13 @@
<string name="elem_Terminal_pin_D">Über diesen Eingang werden die anzuzeigenden Daten an das Terminal weitergegeben.</string> <string name="elem_Terminal_pin_D">Über diesen Eingang werden die anzuzeigenden Daten an das Terminal weitergegeben.</string>
<string name="elem_Terminal_pin_en">Ein High an diesem Eingang aktiviert den Takteingang.</string> <string name="elem_Terminal_pin_en">Ein High an diesem Eingang aktiviert den Takteingang.</string>
<string name="elem_Speaker">Lautsprecher</string> <string name="elem_MIDI">MIDI</string>
<string name="elem_Speaker_tt">Nutzt das MIDI-System, um Noten abzuspielen.</string> <string name="elem_MIDI_tt">Nutzt das MIDI-System, um Noten abzuspielen.</string>
<string name="elem_Speaker_pin_N">Note</string> <string name="elem_MIDI_pin_N">Note</string>
<string name="elem_Speaker_pin_V">Lautstärke</string> <string name="elem_MIDI_pin_V">Lautstärke</string>
<string name="elem_Speaker_pin_en">Wenn gesetzt, wird der Ton ausgegeben.</string> <string name="elem_MIDI_pin_OnOff">Wenn gesetzt, enspricht das dem Drücken eine Keyboard-Taste (key down).
Wenn nicht gesetzt, entspricht das einem Loslassen der Taste (key up).</string>
<string name="elem_MIDI_pin_C">Takteingang</string>
<!-- Leitungen --> <!-- Leitungen -->
@ -999,6 +1001,7 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
<string name="err_ProgMemLabelsNotDifferent">Wenn Programme in mehrere RAMs geladen werden sollen, müssen alle RAMs <string name="err_ProgMemLabelsNotDifferent">Wenn Programme in mehrere RAMs geladen werden sollen, müssen alle RAMs
unterschiedliche Bezeichnungen haben. Die lexikalische Ordnung legt dann die Reihenfolge der RAMs fest.</string> unterschiedliche Bezeichnungen haben. Die lexikalische Ordnung legt dann die Reihenfolge der RAMs fest.</string>
<string name="err_midiSystemNotAvailable">Das MIDI-System ist nicht verfügbar.</string> <string name="err_midiSystemNotAvailable">Das MIDI-System ist nicht verfügbar.</string>
<string name="err_midiChannel_N_NotAvailable">Der MIDI-Kanal {0} ist nicht verfügbar.</string>
<string name="key_AddrBits">Adress-Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM --> <string name="key_AddrBits">Adress-Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
<string name="key_AddrBits_tt">Anzahl der Adress-Bits, die verwendet werden.</string> <string name="key_AddrBits_tt">Anzahl der Adress-Bits, die verwendet werden.</string>

View File

@ -263,11 +263,13 @@
<string name="elem_Terminal_pin_D">The data to write to the terminal</string> <string name="elem_Terminal_pin_D">The data to write to the terminal</string>
<string name="elem_Terminal_pin_en">A high at this input enables the clock input.</string> <string name="elem_Terminal_pin_en">A high at this input enables the clock input.</string>
<string name="elem_Speaker">Speaker</string> <string name="elem_MIDI">MIDI</string>
<string name="elem_Speaker_tt">Uses the MIDI system to play notes.</string> <string name="elem_MIDI_tt">Uses the MIDI system to play notes.</string>
<string name="elem_Speaker_pin_N">Note</string> <string name="elem_MIDI_pin_N">Note</string>
<string name="elem_Speaker_pin_V">Valume</string> <string name="elem_MIDI_pin_V">Volume</string>
<string name="elem_Speaker_pin_en">When set, the note is played.</string> <string name="elem_MIDI_pin_OnOff">If set, this translates to pressing a keyboard key (key down event),
if not set, this translates to releasing the key (key up event).</string>
<string name="elem_MIDI_pin_C">Clock</string>
<!-- Wires --> <!-- Wires -->
@ -992,6 +994,7 @@
<string name="err_ProgMemLabelsNotDifferent">If programs are to be loaded into several RAMs, all RAMs must have <string name="err_ProgMemLabelsNotDifferent">If programs are to be loaded into several RAMs, all RAMs must have
different names. The lexical order then determines the order of the RAMs.</string> different names. The lexical order then determines the order of the RAMs.</string>
<string name="err_midiSystemNotAvailable">The MIDI-System is not available.</string> <string name="err_midiSystemNotAvailable">The MIDI-System is not available.</string>
<string name="err_midiChannel_N_NotAvailable">The MIDI channel {0} is not available.</string>
<string name="key_AddrBits">Address Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM --> <string name="key_AddrBits">Address Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
<string name="key_AddrBits_tt">Number of address bits used.</string> <string name="key_AddrBits_tt">Number of address bits used.</string>

View File

@ -579,11 +579,6 @@
<elementAttributes/> <elementAttributes/>
<pos x="120" y="900"/> <pos x="120" y="900"/>
</visualElement> </visualElement>
<visualElement>
<elementName>Speaker</elementName>
<elementAttributes/>
<pos x="300" y="940"/>
</visualElement>
<visualElement> <visualElement>
<elementName>Const</elementName> <elementName>Const</elementName>
<elementAttributes> <elementAttributes>
@ -604,6 +599,11 @@
</elementAttributes> </elementAttributes>
<pos x="280" y="960"/> <pos x="280" y="960"/>
</visualElement> </visualElement>
<visualElement>
<elementName>MIDI</elementName>
<elementAttributes/>
<pos x="300" y="940"/>
</visualElement>
</visualElements> </visualElements>
<wires> <wires>
<wire> <wire>
@ -836,6 +836,10 @@
</wire> </wire>
<wire> <wire>
<p1 x="240" y="980"/> <p1 x="240" y="980"/>
<p2 x="280" y="980"/>
</wire>
<wire>
<p1 x="280" y="980"/>
<p2 x="300" y="980"/> <p2 x="300" y="980"/>
</wire> </wire>
<wire> <wire>
@ -1006,6 +1010,10 @@
<p1 x="1140" y="360"/> <p1 x="1140" y="360"/>
<p2 x="1160" y="360"/> <p2 x="1160" y="360"/>
</wire> </wire>
<wire>
<p1 x="280" y="1000"/>
<p2 x="300" y="1000"/>
</wire>
<wire> <wire>
<p1 x="1080" y="940"/> <p1 x="1080" y="940"/>
<p2 x="1100" y="940"/> <p2 x="1100" y="940"/>
@ -1498,6 +1506,10 @@
<p1 x="920" y="100"/> <p1 x="920" y="100"/>
<p2 x="920" y="620"/> <p2 x="920" y="620"/>
</wire> </wire>
<wire>
<p1 x="280" y="980"/>
<p2 x="280" y="1000"/>
</wire>
<wire> <wire>
<p1 x="220" y="220"/> <p1 x="220" y="220"/>
<p2 x="220" y="300"/> <p2 x="220" y="300"/>