3789983e89
Reviewed-by: darcy, ihse
251 lines
9.5 KiB
Java
251 lines
9.5 KiB
Java
/*
|
|
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
/* @test
|
|
@summary Test RealTime-tunings using SoftReciver.send method
|
|
@modules java.desktop/com.sun.media.sound
|
|
*/
|
|
|
|
import java.io.IOException;
|
|
|
|
import javax.sound.midi.*;
|
|
import javax.sound.sampled.*;
|
|
|
|
import com.sun.media.sound.*;
|
|
|
|
public class RealTimeTuning {
|
|
|
|
private static class PitchSpy {
|
|
public float pitch = 0;
|
|
|
|
public Soundbank getSoundBank() {
|
|
ModelOscillator osc = new ModelOscillator() {
|
|
public float getAttenuation() {
|
|
return 0;
|
|
}
|
|
|
|
public int getChannels() {
|
|
return 0;
|
|
}
|
|
|
|
public ModelOscillatorStream open(float samplerate) {
|
|
return new ModelOscillatorStream() {
|
|
public void close() throws IOException {
|
|
pitch = 0;
|
|
}
|
|
|
|
public void noteOff(int velocity) {
|
|
pitch = 0;
|
|
}
|
|
|
|
public void noteOn(MidiChannel channel,
|
|
VoiceStatus voice, int noteNumber, int velocity) {
|
|
pitch = noteNumber * 100;
|
|
}
|
|
|
|
public int read(float[][] buffer, int offset, int len)
|
|
throws IOException {
|
|
return len;
|
|
}
|
|
|
|
public void setPitch(float ipitch) {
|
|
pitch = ipitch;
|
|
}
|
|
};
|
|
}
|
|
};
|
|
ModelPerformer performer = new ModelPerformer();
|
|
performer.getOscillators().add(osc);
|
|
SimpleInstrument testinstrument = new SimpleInstrument();
|
|
testinstrument.setPatch(new Patch(0, 0));
|
|
testinstrument.add(performer);
|
|
SimpleSoundbank testsoundbank = new SimpleSoundbank();
|
|
testsoundbank.addInstrument(testinstrument);
|
|
return testsoundbank;
|
|
}
|
|
}
|
|
|
|
public static void sendTuningChange(Receiver recv, int channel,
|
|
int tuningpreset, int tuningbank) throws InvalidMidiDataException {
|
|
// Data Entry
|
|
ShortMessage sm1 = new ShortMessage();
|
|
sm1.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x64, 04);
|
|
ShortMessage sm2 = new ShortMessage();
|
|
sm2.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x65, 00);
|
|
|
|
// Tuning Bank
|
|
ShortMessage sm3 = new ShortMessage();
|
|
sm3.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x06, tuningbank);
|
|
// Data Increment
|
|
ShortMessage sm4 = new ShortMessage();
|
|
sm4.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x60, 0x7F);
|
|
// Data Decrement
|
|
ShortMessage sm5 = new ShortMessage();
|
|
sm5.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x61, 0x7F);
|
|
|
|
// Data Entry
|
|
ShortMessage sm6 = new ShortMessage();
|
|
sm6.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x64, 03);
|
|
ShortMessage sm7 = new ShortMessage();
|
|
sm7.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x65, 00);
|
|
|
|
// Tuning program
|
|
ShortMessage sm8 = new ShortMessage();
|
|
sm8
|
|
.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x06,
|
|
tuningpreset);
|
|
// Data Increment
|
|
ShortMessage sm9 = new ShortMessage();
|
|
sm9.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x60, 0x7F);
|
|
// Data Decrement
|
|
ShortMessage sm10 = new ShortMessage();
|
|
sm10.setMessage(ShortMessage.CONTROL_CHANGE, channel, 0x61, 0x7F);
|
|
|
|
recv.send(sm1, -1);
|
|
recv.send(sm2, -1);
|
|
recv.send(sm3, -1);
|
|
recv.send(sm4, -1);
|
|
recv.send(sm5, -1);
|
|
recv.send(sm6, -1);
|
|
recv.send(sm7, -1);
|
|
recv.send(sm8, -1);
|
|
recv.send(sm9, -1);
|
|
recv.send(sm10, -1);
|
|
|
|
}
|
|
|
|
private static void assertTrue(boolean value) throws Exception {
|
|
if (!value)
|
|
throw new RuntimeException("assertTrue fails!");
|
|
}
|
|
|
|
public static void testTunings(int[] msg, int tuningProgram,
|
|
int tuningBank, int targetNote, float targetPitch, boolean realtime)
|
|
throws Exception {
|
|
AudioSynthesizer synth = new SoftSynthesizer();
|
|
AudioInputStream stream = synth.openStream(null, null);
|
|
Receiver recv = synth.getReceiver();
|
|
MidiChannel channel = synth.getChannels()[0];
|
|
byte[] buff = new byte[2048];
|
|
|
|
// Create test instrument which we can use to monitor pitch changes
|
|
PitchSpy pitchspy = new PitchSpy();
|
|
|
|
synth.unloadAllInstruments(synth.getDefaultSoundbank());
|
|
synth.loadAllInstruments(pitchspy.getSoundBank());
|
|
|
|
SysexMessage sysex = null;
|
|
|
|
// Send tuning changes
|
|
if (msg != null) {
|
|
byte[] bmsg = new byte[msg.length];
|
|
for (int i = 0; i < bmsg.length; i++)
|
|
bmsg[i] = (byte) msg[i];
|
|
sysex = new SysexMessage();
|
|
sysex.setMessage(bmsg, bmsg.length);
|
|
if (targetPitch == 0) {
|
|
targetPitch = (float) new SoftTuning(bmsg)
|
|
.getTuning(targetNote);
|
|
// Check if targetPitch != targetNote * 100
|
|
assertTrue(Math.abs(targetPitch - targetNote * 100.0) > 0.001);
|
|
}
|
|
}
|
|
|
|
if (tuningProgram != -1)
|
|
sendTuningChange(recv, 0, tuningProgram, tuningBank);
|
|
|
|
// First test without tunings
|
|
channel.noteOn(targetNote, 64);
|
|
stream.read(buff, 0, buff.length);
|
|
assertTrue(Math.abs(pitchspy.pitch - (targetNote * 100.0)) < 0.001);
|
|
|
|
// Test if realtime/non-realtime works
|
|
if (sysex != null)
|
|
recv.send(sysex, -1);
|
|
stream.read(buff, 0, buff.length);
|
|
if (realtime)
|
|
assertTrue(Math.abs(pitchspy.pitch - targetPitch) < 0.001);
|
|
else
|
|
assertTrue(Math.abs(pitchspy.pitch - (targetNote * 100.0)) < 0.001);
|
|
|
|
// Test if tunings works
|
|
channel.noteOn(targetNote, 0);
|
|
stream.read(buff, 0, buff.length);
|
|
assertTrue(Math.abs(pitchspy.pitch - 0.0) < 0.001);
|
|
|
|
channel.noteOn(targetNote, 64);
|
|
stream.read(buff, 0, buff.length);
|
|
assertTrue(Math.abs(pitchspy.pitch - targetPitch) < 0.001);
|
|
|
|
channel.noteOn(targetNote, 0);
|
|
stream.read(buff, 0, buff.length);
|
|
assertTrue(Math.abs(pitchspy.pitch - 0.0) < 0.001);
|
|
|
|
stream.close();
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
// Test with no-tunings
|
|
testTunings(null, -1, -1, 60, 6000, false);
|
|
|
|
int[] msg;
|
|
// 0x02 SINGLE NOTE TUNING CHANGE (REAL-TIME)
|
|
msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x02, 0x10, 0x02, 36, 36, 64,
|
|
0, 60, 70, 0, 0, 0xf7 };
|
|
testTunings(msg, 0x10, 0, 60, 7000, true);
|
|
|
|
// 0x07 SINGLE NOTE TUNING CHANGE (NON REAL-TIME) (BANK)
|
|
msg = new int[] { 0xf0, 0x7e, 0x7f, 0x08, 0x07, 0x05, 0x07, 0x02, 36,
|
|
36, 64, 0, 60, 80, 0, 0, 0xf7 };
|
|
testTunings(msg, 0x07, 0x05, 60, 8000, false);
|
|
|
|
// 0x07 SINGLE NOTE TUNING CHANGE (REAL-TIME) (BANK)
|
|
msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x07, 0x05, 0x07, 0x02, 36,
|
|
36, 64, 0, 60, 80, 0, 0, 0xf7 };
|
|
testTunings(msg, 0x07, 0x05, 60, 8000, true);
|
|
|
|
// 0x08 scale/octave tuning 1-byte form (Non Real-Time)
|
|
msg = new int[] { 0xf0, 0x7e, 0x7f, 0x08, 0x08, 0x03, 0x7f, 0x7f, 5,
|
|
10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 0xf7 };
|
|
testTunings(msg, -1, -1, 60, 0, false);
|
|
|
|
// 0x08 scale/octave tuning 1-byte form (REAL-TIME)
|
|
msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x08, 0x03, 0x7f, 0x7f, 5,
|
|
10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 0xf7 };
|
|
testTunings(msg, -1, -1, 60, 0, true);
|
|
|
|
// 0x09 scale/octave tuning 2-byte form (Non Real-Time)
|
|
msg = new int[] { 0xf0, 0x7e, 0x7f, 0x08, 0x09, 0x03, 0x7f, 0x7f, 5,
|
|
10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 5, 10, 15, 20, 25,
|
|
30, 35, 40, 45, 50, 51, 52, 0xf7 };
|
|
testTunings(msg, -1, -1, 60, 0, false);
|
|
|
|
// 0x09 scale/octave tuning 2-byte form (REAL-TIME)
|
|
msg = new int[] { 0xf0, 0x7f, 0x7f, 0x08, 0x09, 0x03, 0x7f, 0x7f, 5,
|
|
10, 15, 20, 25, 30, 35, 40, 45, 50, 51, 52, 5, 10, 15, 20, 25,
|
|
30, 35, 40, 45, 50, 51, 52, 0xf7 };
|
|
testTunings(msg, -1, -1, 60, 0, true);
|
|
|
|
}
|
|
}
|