260 lines
10 KiB
Java
260 lines
10 KiB
Java
/*
|
|
* Copyright (c) 2007, 2013, 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. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* 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.
|
|
*/
|
|
package com.sun.media.sound;
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.util.Arrays;
|
|
|
|
import javax.sound.midi.Patch;
|
|
|
|
/**
|
|
* A tuning program container, for use with MIDI Tuning.
|
|
* See: http://www.midi.org
|
|
*
|
|
* @author Karl Helgason
|
|
*/
|
|
public final class SoftTuning {
|
|
|
|
private String name = null;
|
|
private final double[] tuning = new double[128];
|
|
private Patch patch = null;
|
|
|
|
public SoftTuning() {
|
|
name = "12-TET";
|
|
for (int i = 0; i < tuning.length; i++)
|
|
tuning[i] = i * 100;
|
|
}
|
|
|
|
public SoftTuning(byte[] data) {
|
|
for (int i = 0; i < tuning.length; i++)
|
|
tuning[i] = i * 100;
|
|
load(data);
|
|
}
|
|
|
|
public SoftTuning(Patch patch) {
|
|
this.patch = patch;
|
|
name = "12-TET";
|
|
for (int i = 0; i < tuning.length; i++)
|
|
tuning[i] = i * 100;
|
|
}
|
|
|
|
public SoftTuning(Patch patch, byte[] data) {
|
|
this.patch = patch;
|
|
for (int i = 0; i < tuning.length; i++)
|
|
tuning[i] = i * 100;
|
|
load(data);
|
|
}
|
|
|
|
private boolean checksumOK(byte[] data) {
|
|
int x = data[1] & 0xFF;
|
|
for (int i = 2; i < data.length - 2; i++)
|
|
x = x ^ (data[i] & 0xFF);
|
|
return (data[data.length - 2] & 0xFF) == (x & 127);
|
|
}
|
|
|
|
/*
|
|
private boolean checksumOK2(byte[] data) {
|
|
int x = data[1] & 0xFF; // 7E
|
|
x = x ^ (data[2] & 0xFF); // <device ID>
|
|
x = x ^ (data[4] & 0xFF); // nn
|
|
x = x ^ (data[5] & 0xFF); // tt
|
|
for (int i = 22; i < data.length - 2; i++)
|
|
x = x ^ (data[i] & 0xFF);
|
|
return (data[data.length - 2] & 0xFF) == (x & 127);
|
|
}
|
|
*/
|
|
public void load(byte[] data) {
|
|
// Universal Non-Real-Time / Real-Time SysEx
|
|
if ((data[1] & 0xFF) == 0x7E || (data[1] & 0xFF) == 0x7F) {
|
|
int subid1 = data[3] & 0xFF;
|
|
switch (subid1) {
|
|
case 0x08: // MIDI Tuning Standard
|
|
int subid2 = data[4] & 0xFF;
|
|
switch (subid2) {
|
|
case 0x01: // BULK TUNING DUMP (NON-REAL-TIME)
|
|
{
|
|
// http://www.midi.org/about-midi/tuning.shtml
|
|
//if (!checksumOK2(data))
|
|
// break;
|
|
try {
|
|
name = new String(data, 6, 16, "ascii");
|
|
} catch (UnsupportedEncodingException e) {
|
|
name = null;
|
|
}
|
|
int r = 22;
|
|
for (int i = 0; i < 128; i++) {
|
|
int xx = data[r++] & 0xFF;
|
|
int yy = data[r++] & 0xFF;
|
|
int zz = data[r++] & 0xFF;
|
|
if (!(xx == 127 && yy == 127 && zz == 127))
|
|
tuning[i] = 100.0 *
|
|
(((xx * 16384) + (yy * 128) + zz) / 16384.0);
|
|
}
|
|
break;
|
|
}
|
|
case 0x02: // SINGLE NOTE TUNING CHANGE (REAL-TIME)
|
|
{
|
|
// http://www.midi.org/about-midi/tuning.shtml
|
|
int ll = data[6] & 0xFF;
|
|
int r = 7;
|
|
for (int i = 0; i < ll; i++) {
|
|
int kk = data[r++] & 0xFF;
|
|
int xx = data[r++] & 0xFF;
|
|
int yy = data[r++] & 0xFF;
|
|
int zz = data[r++] & 0xFF;
|
|
if (!(xx == 127 && yy == 127 && zz == 127))
|
|
tuning[kk] = 100.0*(((xx*16384) + (yy*128) + zz)/16384.0);
|
|
}
|
|
break;
|
|
}
|
|
case 0x04: // KEY-BASED TUNING DUMP (NON-REAL-TIME)
|
|
{
|
|
// http://www.midi.org/about-midi/tuning_extens.shtml
|
|
if (!checksumOK(data))
|
|
break;
|
|
try {
|
|
name = new String(data, 7, 16, "ascii");
|
|
} catch (UnsupportedEncodingException e) {
|
|
name = null;
|
|
}
|
|
int r = 23;
|
|
for (int i = 0; i < 128; i++) {
|
|
int xx = data[r++] & 0xFF;
|
|
int yy = data[r++] & 0xFF;
|
|
int zz = data[r++] & 0xFF;
|
|
if (!(xx == 127 && yy == 127 && zz == 127))
|
|
tuning[i] = 100.0*(((xx*16384) + (yy*128) + zz)/16384.0);
|
|
}
|
|
break;
|
|
}
|
|
case 0x05: // SCALE/OCTAVE TUNING DUMP, 1 byte format
|
|
// (NON-REAL-TIME)
|
|
{
|
|
// http://www.midi.org/about-midi/tuning_extens.shtml
|
|
if (!checksumOK(data))
|
|
break;
|
|
try {
|
|
name = new String(data, 7, 16, "ascii");
|
|
} catch (UnsupportedEncodingException e) {
|
|
name = null;
|
|
}
|
|
int[] octave_tuning = new int[12];
|
|
for (int i = 0; i < 12; i++)
|
|
octave_tuning[i] = (data[i + 23] & 0xFF) - 64;
|
|
for (int i = 0; i < tuning.length; i++)
|
|
tuning[i] = i * 100 + octave_tuning[i % 12];
|
|
break;
|
|
}
|
|
case 0x06: // SCALE/OCTAVE TUNING DUMP, 2 byte format
|
|
// (NON-REAL-TIME)
|
|
{
|
|
// http://www.midi.org/about-midi/tuning_extens.shtml
|
|
if (!checksumOK(data))
|
|
break;
|
|
try {
|
|
name = new String(data, 7, 16, "ascii");
|
|
} catch (UnsupportedEncodingException e) {
|
|
name = null;
|
|
}
|
|
double[] octave_tuning = new double[12];
|
|
for (int i = 0; i < 12; i++) {
|
|
int v = (data[i * 2 + 23] & 0xFF) * 128
|
|
+ (data[i * 2 + 24] & 0xFF);
|
|
octave_tuning[i] = (v / 8192.0 - 1) * 100.0;
|
|
}
|
|
for (int i = 0; i < tuning.length; i++)
|
|
tuning[i] = i * 100 + octave_tuning[i % 12];
|
|
break;
|
|
}
|
|
case 0x07: // SINGLE NOTE TUNING CHANGE (NON
|
|
// REAL-TIME/REAL-TIME) (BANK)
|
|
// http://www.midi.org/about-midi/tuning_extens.shtml
|
|
int ll = data[7] & 0xFF;
|
|
int r = 8;
|
|
for (int i = 0; i < ll; i++) {
|
|
int kk = data[r++] & 0xFF;
|
|
int xx = data[r++] & 0xFF;
|
|
int yy = data[r++] & 0xFF;
|
|
int zz = data[r++] & 0xFF;
|
|
if (!(xx == 127 && yy == 127 && zz == 127))
|
|
tuning[kk] = 100.0
|
|
* (((xx*16384) + (yy*128) + zz) / 16384.0);
|
|
}
|
|
break;
|
|
case 0x08: // scale/octave tuning 1-byte form (Non
|
|
// Real-Time/REAL-TIME)
|
|
{
|
|
// http://www.midi.org/about-midi/tuning-scale.shtml
|
|
int[] octave_tuning = new int[12];
|
|
for (int i = 0; i < 12; i++)
|
|
octave_tuning[i] = (data[i + 8] & 0xFF) - 64;
|
|
for (int i = 0; i < tuning.length; i++)
|
|
tuning[i] = i * 100 + octave_tuning[i % 12];
|
|
break;
|
|
}
|
|
case 0x09: // scale/octave tuning 2-byte form (Non
|
|
// Real-Time/REAL-TIME)
|
|
{
|
|
// http://www.midi.org/about-midi/tuning-scale.shtml
|
|
double[] octave_tuning = new double[12];
|
|
for (int i = 0; i < 12; i++) {
|
|
int v = (data[i * 2 + 8] & 0xFF) * 128
|
|
+ (data[i * 2 + 9] & 0xFF);
|
|
octave_tuning[i] = (v / 8192.0 - 1) * 100.0;
|
|
}
|
|
for (int i = 0; i < tuning.length; i++)
|
|
tuning[i] = i * 100 + octave_tuning[i % 12];
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// am: getTuning(int) is more effective.
|
|
// currently getTuning() is used only by tests
|
|
public double[] getTuning() {
|
|
return Arrays.copyOf(tuning, tuning.length);
|
|
}
|
|
|
|
public double getTuning(int noteNumber) {
|
|
return tuning[noteNumber];
|
|
}
|
|
|
|
public Patch getPatch() {
|
|
return patch;
|
|
}
|
|
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
|
|
public void setName(String name) {
|
|
this.name = name;
|
|
}
|
|
}
|