关于Java的音频采样

简述

我的目标是用Java制作合成器。要添加的功能是

    • キーボードとドレミファソラシドを紐づけて、ピアノのようにする

 

    • 波形(サイン・のこぎり・矩形)

 

    • エンベローブ(減衰)

 

    • フィルタ(音色)

 

    • モジュレーション(周期的な変調)

 

    • リズムの定型を複数用意して繰り返し流す(ドラム)

 

    • 和音・コード入力

 

    • 録音+繰り返し

 

    • ハイゲイン(ギター)

 

    • リバーブ

 

    • 波形・FFT表示

 

    繰り返し等を使う場合、楽譜と現在位置の表示

我的目标就是成为一位音乐家。因为我自己并不熟悉音乐,所以我也想了解更多关于音乐的知识。

请查看有关合成器功能说明的部分。

 

用Java播放用PCM(脉冲编码调制)描述的音频数据的方法是什么?

 

我已参考此信息。

 

请看完这个话题后,您将对API的概述有所了解。

学习Java声音库。

 

虽然提供了整体性的解释,但是没有任何示范程序。

图书馆的继承关系是基于Line派生的。

1.png

音声ファイルをロードして再生する場合はClipインスタンスを事前に生成することで可能

SourceDataLineインスタンスに逐次データを追加してリアルタイムで再生する

TargetDataLineインスタンス録音や音声データを取得することができる

通过使用 Port 和 Mixer 实例可以构建以下系统,并进行播放和录音。

3.gif

搅拌机内的元素

混音器是将多个音频流合成在一起。
在这里,我们将解释混音器内的元素。

リバーブ = 残響
パン = 左右の強度差 (zuǒ de dù chā)
ゲイン = 音の大きさ de dà duō)

Line对象

成员变量1:Control实例

我們將其作為成員變量持有Control實例。

 

Control(Control.Type type)

将以生成的Control实例作为成员变量。

Control实例包含Control.Type类的实例。Control.Type类表示

 

Control.Type("Gain")
Control.Type("Balance")

宣言后,我们将功能添加到Line对象中。

请点击这里了解更多详情。

 

成员变量2: LineListener实例

您可以通过注册事先生成的LineListener实例,以便在Line实例的状态发生变化时接收事件。

每次变化时,将调用LineListener实例内的update()方法。在此过程中,将传递LineEvent对象,因此可以获取事件的信息和播放停止位置等。

 

示例代码

 

成员变量3: Line.Info对象

 

詳細不明

端口对象

 

作为成员,拥有 Port.Info 对象。

 

可以选择耳机和麦克风等设备。

音频数据行

您可以使用字节数据设置音频数据。

 

open(AudioFormat format)
or
open(AudioFormat format, int bufferSize)

以中文本地化方式解释:调用超类的Line实例的open()方法(Line实例的打开是生成内存吗?)。

int write(byte[] b,
          int off,
          int len)

b是字节数据。
off是缓冲的写入起始点。
len是b的大小。

缓冲区不必始终保持满状态,当缓冲区为空时,音频将无法播放。
如果写入的数据超过缓冲区的大小,则会在播放的同时逐个进行缓冲区的传送和数据的写入。当所有数据都被放入缓冲区后,处理就会返回。如果写入的数据小于缓冲区的大小,则会立即返回。

 

line.start();
while (total < totalToRead && !stopped)}
    numBytesRead = stream.read(myData, 0, numBytesToRead);
    if (numBytesRead == -1) break;
    total += numBytesRead; 
    line.write(myData, 0, numBytesRead);
}

这是一个示例。
start()和stop()方法是DataLine的方法。

 

建立再生系统

2.gif

 

阅读此内容后,我们过去一直认为Mixer是在Java内生成的实例,但根据上面的链接所述。

系统中安装了多个混音器。通常情况下,至少有一个用于音频输入,一个用于音频输出。

有可能指的是位於Windows內的軟體。

 

根据所述,可能是通过AudioSystem类将具体的Windows软件连接起来。

关于AudioSystem类

获取格式:通过指定文件名

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.File;
import java.io.IOException;

public class AudioSystem_test {
    public static void main(String[] args) throws UnsupportedAudioFileException, IOException {
        System.out.println("start");
        AudioFileFormat format = AudioSystem.getAudioFileFormat(new File("C:/Users/~/test2.wav"));
        System.out.println(format.toString());
    }
}

结果

WAVE (.wav) file, byte length: 178382796, data format: PCM_SIGNED 96000.0 Hz,
 32 bit, stereo, 8 bytes/frame, little-endian, frame length: 22297844

MP3不支持,但可以使用WAV文件。似乎还可以使用AIFF、AU和SND格式。

 

音频文件格式

 

        System.out.println(format.toString());
        System.out.println(format.getFormat());
        System.out.println(format.getType());
        Map<String,Object> map = format.properties();
        System.out.println(format.getProperty("title"));

可以这样看。getProperty是null。原因不明。

获取混音器信息

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;

public class AudioSystem_test {
    public static void main(String[] args) throws UnsupportedAudioFileException, IOException {
        System.out.println("start");
        Mixer.Info[] info = AudioSystem.getMixerInfo();
        for(Mixer.Info i:info){
            System.out.println(i.toString());
        }
    }
}

结果: 东西变成了这样。

Port ヘッドホン (WI-C310 Stereo), version 0.0
Port ヘッドホン (Realtek(R) Audio), version 10.0
Port PL2492H (NVIDIA High Definition, version 10.0
~
ヘッドセット (WI-C310 Hands-Free AG A, version Unknown Version

你可以获得所有正在使用的音频设备。

关于Mixer.Info,请点击这里。

 

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;

public class AudioSystem_test {
    public static void main(String[] args) throws UnsupportedAudioFileException, IOException {
        System.out.println("start");
        Mixer.Info[] info = AudioSystem.getMixerInfo();
        for(Mixer.Info i:info){
            System.out.println("----------------------------");
            System.out.println(i.getName());
            System.out.println(i.getDescription());
            System.out.println(i.getVendor());
            System.out.println(i.getVersion());

        }
    }
}

得到混音器 (Dé qì)

接下来,我们将根据先前获得的Mixer信息获取与耳机名称匹配的Mixer。
我正在使用无线耳机WI-C310。

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Line;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;

public class AudioSystem_test {
    public static void main(String[] args) throws UnsupportedAudioFileException, IOException {
        System.out.println("start");
        Mixer.Info[] info = AudioSystem.getMixerInfo();
        Mixer mixer = null;
        for(Mixer.Info i:info){
            System.out.println(i.getName());
            if(i.getName().equals("Port ヘッドホン (WI-C310 Stereo)")){
                mixer = AudioSystem.getMixer(i);
                System.out.println("find");
                break;
            }
        }
        Line[] lines = mixer.getTargetLines();
        System.out.println(lines.length);
        
        for(Line i:lines){
            System.out.println(i.toString());
        }

    }
}

结果,似乎成功获取了混音器,但是没有连接任何数据线到调音台。

使用Clip实例进行播放

 

这将是一个很好的参考。

获取AudioInputStream。

clip.open(AudioInputStream);

你正在播放中。

最初提到的

 

这边也可以

clip.open(AudioFormat format, byte[] data, int offset, int bufferSize);

正在使用的进行再生。

使用SourceDataLine进行播放

这个过程跟Clip类似,先通过open方法分配内存和其他资源,然后通过write方法将数据写入缓冲区。

我不确定是否需要连接到混频器等设备上,还是会自动连接。
哎,无所谓了。我们试着模仿Clip的代码来创建一下吧。

import javax.sound.sampled.*;

public class SourceDataLine_test {
    public static void main(String[] args) throws InterruptedException, LineUnavailableException {
        byte[] wave_data= new byte[44100*2];                      // @A-sta@
        double l1      = 44100.0/440.0;    // A 440hz
        for(int i=0;i<wave_data.length;i++){
            wave_data[i]= (byte)(110*Math.sin((i/l1)*Math.PI*2));
        }                                                      //@A-end@

        AudioFormat frmt= new AudioFormat(44100,8,1,true,false);
        DataLine.Info info= new DataLine.Info(SourceDataLine.class,frmt);
        SourceDataLine source = (SourceDataLine) AudioSystem.getLine(info);
        source.open(frmt);

        System.out.println(source.toString());

        source.flush();
        source.write(wave_data,0,wave_data.length);
        source.start();
        System.out.println(source.getBufferSize());
        System.out.println(source.available());
        System.out.println(source.isRunning());
        Thread.sleep(3000);
        System.out.println(source.isRunning());
    }

}

暫且有聲音響起。

MIDI 是一种音频短消息传输协议。

音樂譜、演奏資訊、通訊標準,與通訊電纜無關。

利用MIDI信息生成音乐的音频源。

DAW(数字音频工作站)是一种软件,可以编辑MIDI信息、音频、混音器和效果器。

广告
将在 10 秒后关闭
bannerAds