Как сгенерировать звуковые эффекты на Java?

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

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

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

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
16
0
16 434
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

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

Это полностью обратная награда. требования безопасности. Апплет с песочницей может воспроизводить звук, созданный в памяти. OTOH для использования любой нативной библиотеки потребует апплет с цифровой подписью и доверенный апплет.

Andrew Thompson 22.08.2011 16:35

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

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

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

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

Код эмулятора доступен как JaC64 на SourceForge.

Burkhard 19.11.2008 12:27
Ответ принят как подходящий

Вы можете легко сгенерировать дискретизированные звуковые данные на 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

Для таких манекенов, как я, когда вы его сгенерировали, как в него играть?

skiphoppy 08.02.2009 07:53

@skiphoppy: Воспроизвести образцы с помощью javax.sound

Cees Timmerman 24.01.2012 19:43

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

package notegenerator;

import java.io.IOException;

/**
 * Tone generator and player.
 * 
 * @author Cesar Vezga [email protected]
 */
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 <[email protected]>
 *
 */
 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();

}

}

Другие вопросы по теме