Как генерировать звуковые эффекты в Java? - PullRequest
15 голосов
/ 18 ноября 2008

Я ищу код Java, который можно использовать для генерации звука во время выполнения, а НЕ для воспроизведения существующих звуковых файлов.

Например, каков наилучший код для генерации пилообразного сигнала на частоте 440 Гц в течение 2 миллисекунд? Исходный код приветствуется!

Я помню, что у моего Commodore 128 была простая звуковая команда, которая принимала в качестве параметров голос, частоту, форму волны и длительность для определения звука. Это прекрасно работало во многих простых случаях (быстрые и грязные игры, эксперименты со звуком и т. Д.).

Я специально искал звуковые эффекты, такие как звуки, а не музыка или MIDI (которые библиотека JFugue довольно хорошо охватывает).

Ответы [ 4 ]

6 голосов
/ 15 августа 2012

Вот пример, который может помочь. Это порождает волны греха:

package notegenerator;

import java.io.IOException;

/**
 * Tone generator and player.
 * 
 * @author Cesar Vezga vcesar@yahoo.com
 */
public class Main {

public static void main(String[] args) throws IOException {

    Player player = new Player();

    player.play(BeachRock.getTack1(),BeachRock.getTack2());

}

 }

 package notegenerator;

 public class BeachRock {

// GUITAR
static String gs1 = "T332 A4-E4 F#5-C6 E5-A5 T166 G5 A5 F#5 A5 F5 A5 E5-A5 E3 G3 G#3 ";
static String gs2 = "A3 A3 A3 G3 E3 E3 G3 G#3 ";
static String gs3 = "A3 A3 A3 G3 E3 A3 C4 C#4 ";
static String gs4 = gs2 + gs2 + gs2 + gs3;
static String gs5 = "D4 D4 D4 C4 A3 A3 C4 D#4 ";
static String gs6 = "D4 D4 D4 C4 A3 E3 G3 G#3 ";
static String gs7 = gs4 + gs5 + gs6 + gs2 + "A3 A3 A3 G3 E3 B3 D3 D#3 ";
static String gs8 = "E4 E4 E4 D4 B3 B3 E4 B3 " + gs6 + gs2;
static String gs9 = "x E3-B3 E3-B3 E3-B3 E3-B3 E3 G3 G#3 ";
static String gs10 = gs7 + gs8 + gs9;
static String gs11 = "A3-D4 X*7 X*16 X*5 E3 G3 G#3 ";
static String guitar = gs1 + gs10 + gs11 + gs10 + gs11 + "A3 A3 A3";

// DRUMS
static String ds1 = "D2 X D3 D3 X*2 D3 X ";
static String ds2 = "D2 X D3 D3 X D3 D3 D3 ";
static String ds3 = "D2 D3 D3 D3 D3 T83 D3 D3 T166 D3 ";
static String ds4 = ds1 + ds1 + ds1 + ds2;
static String ds5 = ds1 + ds1 + ds1 + ds3;
static String ds6 = "D2*2 D3 D3 X*2 D3*2 ";
static String ds7 = "D2*2 D3 D3 X D3 D3 D3 ";
static String ds8 = ds6 + ds6 + ds6 + ds7;

static String drums = "V25 T166 X*16 " + ds4 + ds4 + ds5 + ds8 + ds4 + ds4
        + ds5 + ds8;

public static String getTack1(){
    return guitar;
}

public static String getTack2(){
    return drums;
}


}

package notegenerator;

import java.util.HashMap;

/**
 * 
 * Physics of Music - Notes
 * 
 * Frequencies for equal-tempered scale
 * This table created using A4 = 440 Hz
 * Speed of sound = 345 m/s = 1130 ft/s = 770 miles/hr
 *  
 *  ("Middle C" is C4 )
 * 
 * http://www.phy.mtu.edu/~suits/notefreqs.html
 * 
 * @author Cesar Vezga <vcesar@yahoo.com>
 *
 */
 public class Notes {


private static final Object[] notes = {
"C0",16.35,
"C#0/Db0",17.32,
"D0",18.35,
"D#0/Eb0",19.45,
"E0",20.6,
"F0",21.83,
"F#0/Gb0",23.12,
"G0",24.5,
"G#0/Ab0",25.96,
"A0",27.5,
"A#0/Bb0",29.14,
"B0",30.87,
"C1",32.7,
"C#1/Db1",34.65,
"D1",36.71,
"D#1/Eb1",38.89,
"E1",41.2,
"F1",43.65,
"F#1/Gb1",46.25,
"G1",49.00,
"G#1/Ab1",51.91,
"A1",55.00,
"A#1/Bb1",58.27,
"B1",61.74,
"C2",65.41,
"C#2/Db2",69.3,
"D2",73.42,
"D#2/Eb2",77.78,
"E2",82.41,
"F2",87.31,
"F#2/Gb2",92.5,
"G2",98.00,
"G#2/Ab2",103.83,
"A2",110.00,
"A#2/Bb2",116.54,
"B2",123.47,
"C3",130.81,
"C#3/Db3",138.59,
"D3",146.83,
"D#3/Eb3",155.56,
"E3",164.81,
"F3",174.61,
"F#3/Gb3",185.00,
"G3",196.00,
"G#3/Ab3",207.65,
"A3",220.00,
"A#3/Bb3",233.08,
"B3",246.94,
"C4",261.63, // Middle C
"C#4/Db4",277.18,
"D4",293.66,
"D#4/Eb4",311.13,
"E4",329.63,
"F4",349.23,
"F#4/Gb4",369.99,
"G4",392.00,
"G#4/Ab4",415.3,
"A4",440.00,
"A#4/Bb4",466.16,
"B4",493.88,
"C5",523.25,
"C#5/Db5",554.37,
"D5",587.33,
"D#5/Eb5",622.25,
"E5",659.26,
"F5",698.46,
"F#5/Gb5",739.99,
"G5",783.99,
"G#5/Ab5",830.61,
"A5",880.00,
"A#5/Bb5",932.33,
"B5",987.77,
"C6",1046.5,
"C#6/Db6",1108.73,
"D6",1174.66,
"D#6/Eb6",1244.51,
"E6",1318.51,
"F6",1396.91,
"F#6/Gb6",1479.98,
"G6",1567.98,
"G#6/Ab6",1661.22,
"A6",1760.00,
"A#6/Bb6",1864.66,
"B6",1975.53,
"C7",2093.00,
"C#7/Db7",2217.46,
"D7",2349.32,
"D#7/Eb7",2489.02,
"E7",2637.02,
"F7",2793.83,
"F#7/Gb7",2959.96,
"G7",3135.96,
"G#7/Ab7",3322.44,
"A7",3520.00,
"A#7/Bb7",3729.31,
"B7",3951.07,
"C8",4186.01,
"C#8/Db8",4434.92,
"D8",4698.64,
"D#8/Eb8",4978.03

};

private HashMap<String,Double> noteMap;

public Notes(){
    noteMap = new HashMap<String,Double>();
    for(int i=0; i<notes.length; i=i+2){
        String name = (String)notes[i];
        double freq = (Double)notes[i+1];
        String[] keys = name.split("/");
        for(String key : keys){
            noteMap.put(key,  freq);
            System.out.println(key);
        }
    }
}


public byte[] getCordData(String keys, double duration){
    int N = (int) (8000 * duration/1000);
    byte[] a = new byte[N+1];
    String[] key = keys.split(" ");
    int count=0;
    for(String k : key){
        double freq = getFrequency(k);
        byte[] tone = tone(freq,duration);
            if(count==0){
               a = tone;
            }else{
               a = addWaves(a,tone);
            }
        count++;
    }

    return a;
}


public byte[] addWaves(byte[] a, byte[] b){
    int len = Math.max(a.length, b.length);
    byte[] c = new byte[len];
    for(int i=0; i<c.length; i++){
        byte aa = ( i < a.length ? a[i] : 0);
        byte bb = ( i < b.length ? b[i] : 0);

           c[i] = (byte) (( aa + bb ) / 2);
    }
    return c;
}


public double getFrequency(String key){
    Double f = noteMap.get(key);
    if(f==null){
        System.out.println("Key not found. "+key);
        f = 0D;
    }
    return f;
}

public byte[] tone(String key, double duration) {
    double freq = getFrequency(key);

    return tone(freq,duration); 
 } 

 public byte[] tone(double hz, double duration) {
        int N = (int) (8000 * duration/1000);
        byte[] a = new byte[N+1];
        for (int i = 0; i <= N; i++) {
            a[i] = (byte) ( Math.sin(2 * Math.PI * i * hz / 8000) * 127 );
        }
        return a; 
 } 


}

package notegenerator;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

public class Player {

private SourceDataLine line = null;

private Notes notes = new Notes();

private long time = 250;

private double volumen = 1;

public void play(String keys) {

    byte[] data = parse(keys);

    start();

    line.write(data, 0, data.length);

    stop();

}

public void play(String... track) {

    byte[] data2 = parseAll(track);

    if (data2 != null) {
        start();

        line.write(data2, 0, data2.length);

        stop();
    }

}

private byte[] parseAll(String... track) {

    byte[] data2 = null;

    for (String t : track) {
        byte[] data1 = parse(t);
        if (data2 == null) {
            data2 = data1;
        } else {
            data2 = notes.addWaves(data1, data2);
        }
    }

    return data2;

}

private byte[] parse(String song) {
    time = 250;

    volumen = 1;

    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    String[] key = song.split(" ");

    byte[] data = null;

    for (String k : key) {
        int mult = 1;

        if (k.indexOf("*") > -1) {
            String keyAux = k.split("\\*")[0];
            mult = Integer.parseInt(k.split("\\*")[1]);
            k = keyAux;
        } else if (k.startsWith("T")) {
            time = Long.parseLong(k.substring(1));
            continue;
        } else if (k.startsWith("V")) {
            volumen =  Double.parseDouble(k.substring(1)) / 100;

            if(volumen>1) volumen = 1;
            if(volumen<0) volumen = 0;

            continue;
        }

        if (k.indexOf("-") > -1) {
            k = k.replaceAll("-", " ").trim();
            data = notes.getCordData(k, time * mult);
        } else {
            data = notes.tone(k, time * mult);
        }

        volumen(data);

        try {
            baos.write(data);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    return baos.toByteArray();

}



private void volumen(byte[] data) {
    for(int i=0; i<data.length; i++){
        data[i] = (byte) (data[i] * volumen);
    }

}

private void stop() {
    line.drain();
    line.stop();

}

private void start() {

    AudioFormat format = new AudioFormat(8000.0F, 8, 1, true, false);

    SourceDataLine.Info info = new DataLine.Info(SourceDataLine.class,
            format); // format
    // is
    // an
    // AudioFormat
    // object
    if (!AudioSystem.isLineSupported(info)) {
        System.out.println("Format not supported");
        System.exit(1);
    }

    // Obtain and open the line.
    try {
        line = (SourceDataLine) AudioSystem.getLine(info);
        line.open(format);
    } catch (LineUnavailableException ex) {
        ex.printStackTrace();
    }

    // Assume that the TargetDataLine, line, has already
    // been obtained and opened.
    int numBytesRead;

    line.start();

}

public void save(String track, String fname) throws IOException {
    byte[] data = parse(track);

    FileOutputStream fos = new FileOutputStream(fname);

    fos.write(data);
    fos.flush();
    fos.close();

}

}
5 голосов
/ 18 декабря 2008

Вы можете легко генерировать сэмплированные звуковые данные в Java и воспроизводить их без использования собственного кода. Если вы говорите о MIDI, то все может быть сложно, но я не баловался в этой области.

Чтобы сгенерировать сэмплированные звуковые данные, вам нужно вернуться к процессу в обратном направлении. Мы будем действовать как A-to-D и со временем сэмплировать непрерывную звуковую функцию. Ваша звуковая карта делает то же самое для аудио через микрофон или линейный вход.

Сначала выберите частоту дискретизации (НЕ частоту тона, который мы генерируем). Давайте поработаем с частотой 44100 Гц, так как это, скорее всего, частота воспроизведения звуковой карты (следовательно, без преобразования частоты дискретизации, это непросто, если аппаратное обеспечение не сделает этого).

// in hz, number of samples in one second
sampleRate = 44100

// this is the time BETWEEN Samples
samplePeriod = 1.0 / sampleRate

// 2ms
duration = 0.002;
durationInSamples = Math.ceil(duration * sampleRate);

time = 0;
for(int i = 0; i < durationInSamples; i++)
{
  // sample a sine wave at 440 hertz at each time tick
  // substitute a function that generates a sawtooth as a function of time / freq
  // rawOutput[i] = function_of_time(other_relevant_info, time);
  rawOutput[i] = Math.sin(2 * Math.PI * 440 * time);
  time += samplePeriod;
}

// now you can playback the rawOutput
// streaming this may be trickier
4 голосов
/ 18 ноября 2008

Java Media Framework делает и то, и другое. Вы можете воспроизводить записанные звуки или использовать интерфейс MIDI для синтеза собственных звуков и музыки. Он также предоставляет API микшера.

Конечно, если вам известны подробности формы волны, которую вы хотите воспроизвести, вы можете «сэмплировать» функцию через равные промежутки времени и передавать полученные сэмплы в API воспроизведения, как если бы это был предварительно записанный звуковой файл.

JMF активно не поддерживается Sun, но есть функционирующие дистрибутивы для различных платформ.

Моим первым компьютером был Commodore 64, и я помню, как Tears for Fears «Все хотят править миром» при откачке его чипа SID. Я не могу сказать, является ли этот чистый эмулятор Java SID открытым исходным кодом или нет, но он может дать вам несколько советов по реализации высокоуровневых функций Attack-Decay-Sustain-Release и Waveform.

0 голосов
/ 18 ноября 2008

Вероятно, вам нужен не звуковой API, а какой-то код синтезатора. Я уверен, что вам нужно более низкоуровневое управление звуковым драйвером, чем допускает Java (это интерпретируемый язык, обычно работающий в «песочнице»). ).

Но хорошая новость заключается в том, что быстрый поиск " java синтезирующего звука " в Google обнаружил плагин под названием JSyn , который использует нативные методы C (которые, как я догадался, был одним из способов делать это) для генерации звука. Похоже, что она бесплатна для некоммерческого использования и доступна в коммерческих лицензиях. :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...