Does java have built in libraries for audio _synth

2019-01-02 21:13发布

Note: I do NOT want to "read audio file foo.bar and play it."

I want to programmatically generate audio files on the fly and play them.

Does Java have built in libraries for this, or does this fall into the system-dependent libraries?

Thanks!

标签: java audio
7条回答
春风洒进眼中
2楼-- · 2019-01-02 21:19

The easiest way to do this is with java's in built MIDI libraries:

int channel = 0; // 0 is a piano, 9 is percussion, other channels are for other instruments

    int volume = 80; // between 0 et 127
    int duration = 200; // in milliseconds

    try {
        Synthesizer synth = MidiSystem.getSynthesizer();
        synth.open();
        MidiChannel[] channels = synth.getChannels();

        // --------------------------------------
        // Play a few notes.
        // The two arguments to the noteOn() method are:
        // "MIDI note number" (pitch of the note),
        // and "velocity" (i.e., volume, or intensity).
        // Each of these arguments is between 0 and 127.
        channels[channel].noteOn( 60, volume ); // C note
        Thread.sleep( duration );
        channels[channel].noteOff( 60 );
        channels[channel].noteOn( 62, volume ); // D note
        Thread.sleep( duration );
        channels[channel].noteOff( 62 );
        channels[channel].noteOn( 64, volume ); // E note
        Thread.sleep( duration );
        channels[channel].noteOff( 64 );

        Thread.sleep( 500 );

        // --------------------------------------
        // Play a C major chord.
        channels[channel].noteOn( 60, volume ); // C
        channels[channel].noteOn( 64, volume ); // E
        channels[channel].noteOn( 67, volume ); // G
        Thread.sleep( 3000 );
        channels[channel].allNotesOff();
        Thread.sleep( 500 );



        synth.close();
    }
    catch (Exception e) {
        e.printStackTrace();
    }
查看更多
与风俱净
3楼-- · 2019-01-02 21:20

Jcollider is a Java interface to the SuperCollider synthesis server. If you want to synthesize music, this will make things much easier (it abstracts away from the tone generator to a synthesizer, takes care of things like graph generation, deleting muted synths from the synthesis graph until they are needed again, patching signals between synths dynamically, etc.).

查看更多
千与千寻千般痛.
4楼-- · 2019-01-02 21:27

This Sun forum post has some interesting code for generating sin tones. Also, given that the WAV file format is not overly complicated, you could create a table representing the desired waveform and then write it to a file. There are a few examples around, e.g. a raw audio converter and how to write a wav file.

查看更多
旧时光的记忆
5楼-- · 2019-01-02 21:29

Have you looked at JSyn? I don't think the Java Core libraries can do what you want.

查看更多
皆成旧梦
6楼-- · 2019-01-02 21:30

Java's Built-in Midi Capabilities

The off-the-shelf Java 8 JRE definitely has what you specifically requested: A built-in synth library. It is described in some detail in Synthesizing Sound.

A quite refined example provides a visual keyboard access to a sampled music synth.

The javax.sound.midi library contains instruments that and the ability to play notes on them, based on MIDI and sampled instrument technology. The sounds are not as authentic as those of the classic Kurzweil musical instrument line, but the framework supports that level of sophistication if you wish to do your own sampling in multiple pitch ranges for a single instrument and work out the details of a fairly seamless transition between ranges.

Trivial Example for Quick View of Usage

Here's a trivial example class.

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();
    }
}

Using multi-threading or an implementations of javax.sound.midi.Sequencer like those available on GitHub.com will provide the structure necessary to actually make music.

Waveform Generation

If you wish to generate your own waveforms rather than using samples, then the answer to your question is, "No," however you can play with this tone synthesizer I wrote for this question. It has several features.

  • Control of pitch (in cycles per second)
  • Control of amplitude (in digital steps)
  • Min and max statistics to indicate when the amplitude is too high (which causes the distortion of the tone from audio clipping)
  • Control of tone duration (in seconds)
  • Control of the relative amplitude of an arbitrary number of harmonics (which determines tone quality or waveform, which is one of several factors that create a musical note's timbre)

This synth lacks many features of high end waveform-generating synths.

  • Real time modification of the amplitude of the principle harmonic and other harmonics over the duration of a note
  • Does not play sequences of notes (but could be modified to do so with relative ease)
  • No facility to phase shift the harmonics either (but that is a somewhat irrelevant shortcoming, since phase characteristics of harmonics is not something the human ear is capable of detecting)

SimpleSynth is a good demonstration of

  • The principles of audio synthesis
  • The timbral effect of harmonics
  • The use of Java to generate audio sample arrays
  • The placing of samples into a byte array
  • The submittal of such a byte array to the OS through a line

Standard digital audio terminology was used for both constant and variable naming. The math is explained in comments.

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);
    }
}

Topics of Study to Augment Music Synthesis Expertise

There are a few topics to read up on if you wish to become a digital synth expert.

  • Digital audio
  • Signal sampling
  • Nyquist criteria
  • How to pluck harmonics on a stringed instrument (such as a guitar)
  • Basic trigonometry, specifically the sine function
查看更多
长期被迫恋爱
7楼-- · 2019-01-02 21:37

See Java Sound API.

Looking a bit more, I also found Jass.

查看更多
登录 后发表回答