注意:我不想「讀取音頻文件foo.bar並播放它。」java是否已經建立了音頻_synthesis_庫?
我想以編程方式隨時生成音頻文件並播放它們。
Java是否已經爲此構建了庫,還是屬於依賴於系統的庫?
謝謝!
注意:我不想「讀取音頻文件foo.bar並播放它。」java是否已經建立了音頻_synthesis_庫?
我想以編程方式隨時生成音頻文件並播放它們。
Java是否已經爲此構建了庫,還是屬於依賴於系統的庫?
謝謝!
This Sun forum post有一些有趣的代碼來產生sin音。另外,鑑於WAV文件格式不會過於複雜,您可以創建一個代表所需波形的表格,然後將其寫入文件。周圍有幾個例子,例如a raw audio converter和how to write a wav file。
你看過嗎JSyn?我不認爲Java核心庫可以做你想做的。
使用,這裏是一個播放equal tempered scale的示例。
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class Tone {
public static void main(String[] args) throws LineUnavailableException {
final AudioFormat af =
new AudioFormat(Note.SAMPLE_RATE, 8, 1, true, true);
SourceDataLine line = AudioSystem.getSourceDataLine(af);
line.open(af, Note.SAMPLE_RATE);
line.start();
for (Note n : Note.values()) {
play(line, n, 500);
play(line, Note.REST, 10);
}
line.drain();
line.close();
}
private static void play(SourceDataLine line, Note note, int ms) {
ms = Math.min(ms, Note.SECONDS * 1000);
int length = Note.SAMPLE_RATE * ms/1000;
int count = line.write(note.data(), 0, length);
}
}
enum Note {
REST, A4, A4$, B4, C4, C4$, D4, D4$, E4, F4, F4$, G4, G4$, A5;
public static final int SAMPLE_RATE = 16 * 1024; // ~16KHz
public static final int SECONDS = 2;
private byte[] sin = new byte[SECONDS * SAMPLE_RATE];
Note() {
int n = this.ordinal();
if (n > 0) {
double exp = ((double) n - 1)/12d;
double f = 440d * Math.pow(2d, exp);
for (int i = 0; i < sin.length; i++) {
double period = (double)SAMPLE_RATE/f;
double angle = 2.0 * Math.PI * i/period;
sin[i] = (byte)(Math.sin(angle) * 127f);
}
}
}
public byte[] data() {
return sin;
}
}
這種低級別的方法可能適用於較老的功能較差的平臺。另請考慮javax.sound.midi
;示出了一個完整的示例here並且Synthesizing Sound教程被引用爲here。
Java包javax.sound.sampled不是一個綜合庫。它只是簡化了已經合成到操作系統本地音頻系統的數字表示的傳遞。 – 2017-02-24 06:16:34
@DouglasDaseeco:謝謝你畫出這個區別;而提問者希望「以編程方式生成音頻文件」,我已經更新了答案,以引用您考慮替代方案的理由。 – trashgod 2017-02-24 10:00:44
感謝您的讚賞。提問者並不十分具體地詢問該庫是否是波形生成庫或告訴OS到播放波形庫。你可能喜歡嘗試一個使用MIDI圖書館的小程序。它以採樣合成器的方式產生音符。對器官或合成聲音的音符不太有用,但更好地產生傳統樂器的聲音。 – 2017-02-24 15:43:56
Jcollider是SuperCollider綜合服務器的Java接口。如果你想合成音樂,這將使事情變得更加容易(它從音源發生器抽象到合成器,處理圖形生成等事情,從合成圖中刪除靜音合成器,直到再次需要它們,修補合成器之間的信號動態等)。
要做到這一點,最簡單的方法是使用Java的內置MIDI庫:
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();
}
這是一個很好的解決方案,我會用這個很多的東西!乾杯 – Stevo 2015-11-09 00:29:39
Java的內置MIDI兼容性
關閉的,現成的Java 8 JRE肯定有你特別要求:內置合成器庫。在Synthesizing Sound中有詳細的描述。
A quite refined example提供了對採樣音樂合成器的視覺鍵盤訪問。
javax.sound.midi庫包含基於MIDI和採樣儀器技術的樂器以及播放音符的功能。這些聲音並不如經典的Kurzweil樂器系列的真實,但是如果您希望在單個樂器的多個音高範圍內進行自己的採樣並制定出相當平滑過渡的細節,則該框架支持這種複雜程度範圍之間。
簡單的例子,對於使用
的快速查看下面是一個簡單的例子類。
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();
}
}
使用多線程或javax.sound.midi.Sequencer中的那些一樣可以用GitHub.com的實現將提供必要的真正做音樂的結構。
波形產生
如果你想生成自己的波形,而不是使用的樣品,然後回答了你的問題是,「不」,但是你可以用這口氣合成我寫的這個問題上發揮。它有幾個特點。間距的
該合成器缺少高端波形生成合成器的許多功能。原則諧波和其他諧波在音符
SimpleSynth是
良好的示範個標準數字音頻術語用於常量和變量命名。數學在評論中解釋。研究
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);
}
}
主題,以增加音樂合成專業
有幾個主題,如果你想成爲一個數字合成器專家讀了。
太陽論壇鏈接已經死了。 – RealHowTo 2013-09-15 16:49:25
IIRC,討論包括[方法](http://stackoverflow.com/a/7782749/230513)由於[安德魯湯普森](http://stackoverflow.com/users/418556/andrew-thompson),引用[這裏](http://stackoverflow.com/a/2065693/230513)。 – trashgod 2014-08-02 15:34:55