de Java incorporado en las capacidades Midi
El off-the-shelf Java 8 JRE definitivamente tiene lo que usted específicamente solicitado: una biblioteca de sintetizador incorporada. Se describe con cierto detalle en Synthesizing Sound.
Un quite refined example proporciona un acceso visual teclado a un sintetizador de música muestreada.
La biblioteca contiene instrumentos que javax.sound.midi y la capacidad de reproducir notas sobre ellos, basado en la tecnología MIDI y de instrumento muestreado. Los sonidos no son tan auténticos como los de la línea clásica de instrumentos musicales Kurzweil, pero el marco admite ese nivel de sofisticación si desea hacer su propio muestreo en múltiples rangos de tono para un solo instrumento y resolver los detalles de una transición bastante fluida entre rangos.
Trivial Ejemplo de Vista rápida del uso
He aquí un ejemplo trivial de clase.
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.MidiChannel;
public class PlayMidiNote
{
private static void sleep(int iUSecs)
{
try
{
Thread.sleep(iUSecs);
}
catch (InterruptedException e)
{
}
}
public static void main(String[] args) throws Exception
{
if (args.length < 3 && args.length > 4)
{
System.out.println("usage: java PlayNote
<8.bit.midi.note.number> <8.bit.velocity>
<usec.duration> [<midi.channel>]");
System.exit(1);
}
int iMidiKey = Math.min(127, Math.max(0,
Integer.parseInt(args[0])));
int iVelocity = Math.min(127, Math.max(0,
Integer.parseInt(args[1])));
int iUSecsDuration = Math.max(0,
Integer.parseInt(args[2]));
int iChannel = args.length > 3
? Math.min(15, Math.max(0,
Integer.parseInt(args[3])))
: 0;
Synthesizer synth = MidiSystem.getSynthesizer();
synth.open();
MidiChannel[] channels = synth.getChannels();
MidiChannel channel = channels[iChannel];
channel.noteOn(iMidiKey, iVelocity);
sleep(iUSecsDuration);
channel.noteOff(iMidiKey);
synth.close();
}
}
El uso de múltiples hilos o un implementaciones de javax.sound.midi.Sequencer como los disponibles en GitHub.com proporcionará la estructura necesaria para hacer realidad la música.
forma de onda Generación
Si desea generar sus propias formas de onda en lugar de utilizar las muestras, entonces la respuesta a su pregunta es, "No", sin embargo, se puede jugar con este sintetizador de tonos que escribí para esta pregunta . Tiene varias características.
- de control de tono (en ciclos por segundo)
- de control de amplitud (en pasos digitales)
- min y estadísticas max para indicar cuando la amplitud es demasiado alta (que provoca la distorsión del tono de recorte de audio)
- control de la duración del tono (en segundos)
- de control de la amplitud relativa de un número arbitrario de armónicos (que determina la calidad del tono o forma de onda, que es uno de varios factores que crean el timbre de una nota musical)
Este sintetizador carece de muchas características de sintetizadores de generación de onda de alto nivel.
- modificación en tiempo real de la amplitud de los principales armónicos armónicos y otros sobre la duración de una nota
- No juega secuencias de notas (pero podría ser modificado para hacerlo con relativa facilidad)
- n facilidad de desplazamiento de fase de los armónicos o bien (pero que es una deficiencia tanto irrelevante, ya que las características de fase de los armónicos no es algo que el oído humano es capaz de detectar)
SimpleSynth es una buena demostración de
- Los principios de la síntesis de audio
- El efecto timbral de armónicos
- El uso de Java para generar matrices de muestra de audio
- La colocación de muestras en una matriz de bytes
- La presentación de un byte tales matriz al sistema operativo a través de una línea
La terminología de audio digital estándar se utilizaba para nombres constantes y variables. La matemática se explica en los comentarios.
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.SourceDataLine;
class SimpleSynth
{
private static int SAMPLE_BITS = 16;
private static int CHANNELS = 1;
private static boolean SIGNED_TRUE = true;
private static boolean BIG_ENDIAN_FALSE = false;
private static float CDROM_SAMPLE_FREQ = 44100;
private SourceDataLine line;
private double dDuration;
private double dCyclesPerSec;
private double dAmplitude;
private double[] adHarmonics;
private double dMin;
private double dMax;
public SimpleSynth(String[] asArguments) throws Exception
{
dDuration = Double.parseDouble(asArguments[0]);
dCyclesPerSec = Double.parseDouble(asArguments[1]);
dAmplitude = Double.parseDouble(asArguments[2]);
adHarmonics = new double[asArguments.length - 3];
for (int i = 0; i < adHarmonics.length; ++ i)
adHarmonics[i] = Double.parseDouble(
asArguments[i + 3]);
AudioFormat format = new AudioFormat(
CDROM_SAMPLE_FREQ, SAMPLE_BITS,
CHANNELS, SIGNED_TRUE, BIG_ENDIAN_FALSE);
line = AudioSystem.getSourceDataLine(format);
line.open();
line.start();
}
public void closeLine()
{
line.drain();
line.stop();
}
public void playSound()
{
// allocate and prepare byte buffer and its index
int iBytes = (int) (2.0 * (0.5 + dDuration)
* CDROM_SAMPLE_FREQ);
byte[] ab = new byte[iBytes];
int i = 0;
// iterate through sample radian values
// for the specified duration
short i16;
double dSample;
double dRadiansPerSample = 2.0 * Math.PI
* dCyclesPerSec/CDROM_SAMPLE_FREQ;
double dDurationInRadians = 2.0 * Math.PI
* dCyclesPerSec * dDuration;
dMin = 0.0;
dMax = 0.0;
for (double d = 0.0;
d < dDurationInRadians;
d += dRadiansPerSample)
{
// add principle and the dot product of harmonics
// and their amplitudes relative to the principle
dSample = Math.sin(d);
for (int h = 0; h < adHarmonics.length; ++ h)
dSample += adHarmonics[h]
* Math.sin((h + 2) * d);
// factor in amplitude
dSample *= dAmplitude;
// adjust statistics
if (dMin > dSample)
dMin = dSample;
if (dMax < dSample)
dMax = dSample;
// store in byte buffer
i16 = (short) (dSample);
ab[i ++] = (byte) (i16);
ab[i ++] = (byte) (i16 >> 8);
}
// send the byte array to the audio line
line.write(ab, 0, i);
}
public void printStats()
{
System.out.println("sample range was ["
+ dMin + ", " + dMax + "]"
+ " in range of [-32768, 32767]");
if (dMin < -32768.0 || dMax > 32767.0)
System.out.println("sound is clipping"
+ "(exceeding its range),"
+ " so use a lower amplitude");
}
public static void main(String[] asArguments)
throws Exception
{
if (asArguments.length < 3)
{
System.err.println("usage: java SimpleSynth"
+ " <duration>"
+ " <tone.cycles.per.sec>"
+ " <amplitude>"
+ " [<relative.amplitude.harmonic.2>"
+ " [...]]");
System.err.println("pure tone:"
+ " java SimpleSynth 1 440 32767");
System.err.println("oboe-like:"
+ " java SimpleSynth 1 440 15000 0 1 0 .9");
System.err.println("complex:"
+ " java SimpleSynth 1 440 800 .3"
+ " .5 .4 .2 .9 .7 5 .1 .9 12 0 3"
+ " .1 5.2 2.5 .5 1 7 6");
System.exit(0);
}
SimpleSynth synth = new SimpleSynth(asArguments);
synth.playSound();
synth.closeLine();
synth.printStats();
System.exit(0);
}
}
temas de estudio para aumentar la síntesis de la música Experiencia
Hay algunos temas para leer sobre si desea convertirse en un experto sintetizador digital.
- digital de audio
- señal de muestreo
- criterios de Nyquist
- Cómo desplumar armónicos en un instrumento de cuerda (como una guitarra)
- trigonometría básica, específicamente la función seno
El enlace al foro de Sun está muerto. – RealHowTo
IIRC, la discusión incluyó un [enfoque] (http://stackoverflow.com/a/7782749/230513) debido a [Andrew Thompson] (http://stackoverflow.com/users/418556/andrew-thompson), citado [aquí] (http://stackoverflow.com/a/2065693/230513). – trashgod