Ошибка Java при генерации звуковой волны синуса
У меня есть этот код, который я получил из учебника о том, как создать звуковую волну греха:
import java.nio.ByteBuffer;
import javax.sound.sampled.*;
public class FixedFreqSine {
//This is just an example - you would want to handle LineUnavailable properly...
public static void main(String[] args) throws InterruptedException, LineUnavailableException
{
final int SAMPLING_RATE = 44100; // Audio sampling rate
final int SAMPLE_SIZE = 2; // Audio sample size in bytes
SourceDataLine line;
double fFreq = 440; // Frequency of sine wave in hz
//Position through the sine wave as a percentage (i.e. 0 to 1 is 0 to 2*PI)
double fCyclePosition = 0;
//Open up audio output, using 44100hz sampling rate, 16 bit samples, mono, and big
// endian byte ordering
AudioFormat format = new AudioFormat(SAMPLING_RATE, 16, 1, true, true);
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
if (!AudioSystem.isLineSupported(info)){
System.out.println("Line matching " + info + " is not supported.");
throw new LineUnavailableException();
}
line = (SourceDataLine)AudioSystem.getLine(info);
line.open(format);
line.start();
// Make our buffer size match audio system's buffer
ByteBuffer cBuf = ByteBuffer.allocate(line.getBufferSize());
int ctSamplesTotal = SAMPLING_RATE*5; // Output for roughly 5 seconds
//On each pass main loop fills the available free space in the audio buffer
//Main loop creates audio samples for sine wave, runs until we tell the thread to exit
//Each sample is spaced 1/SAMPLING_RATE apart in time
while (ctSamplesTotal>0) {
double fCycleInc = fFreq/SAMPLING_RATE; // Fraction of cycle between samples
cBuf.clear(); // Discard samples from previous pass
// Figure out how many samples we can add
int ctSamplesThisPass = line.available()/SAMPLE_SIZE;
for (int i=0; i < ctSamplesThisPass; i++) {
cBuf.putShort((short)(Short.MAX_VALUE * Math.sin(2*Math.PI * fCyclePosition)));
fCyclePosition += fCycleInc;
if (fCyclePosition > 1)
fCyclePosition -= 1;
}
//Write sine samples to the line buffer. If the audio buffer is full, this will
// block until there is room (we never write more samples than buffer will hold)
line.write(cBuf.array(), 0, cBuf.position());
ctSamplesTotal -= ctSamplesThisPass; // Update total number of samples written
//Wait until the buffer is at least half empty before we add more
while (line.getBufferSize()/2 < line.available())
Thread.sleep(1);
}
//Done playing the whole waveform, now wait until the queued samples finish
//playing, then clean up and exit
line.drain();
line.close();
}
}
Он отлично работает на Windows 10 и отлично генерирует звук. Однако на моем MacBook Pro я получаю эту ошибку:
2015-11-17 11:20:16.549 java[5899:9037084] Error loading /Library/Audio/Plug-Ins/HAL/SeratoVirtualAudioPlugIn.plugin/Contents/MacOS/SeratoVirtualAudioPlugIn: dlopen(/Library/Audio/Plug-Ins/HAL/SeratoVirtualAudioPlugIn.plugin/Contents/MacOS/SeratoVirtualAudioPlugIn, 262): no suitable image found. Did find:
/Library/Audio/Plug-Ins/HAL/SeratoVirtualAudioPlugIn.plugin/Contents/MacOS/SeratoVirtualAudioPlugIn: mach-o, but wrong architecture
2015-11-17 11:20:16.549 java[5899:9037084] Cannot find function pointer New_SHP_PlugIn for factory 834FC054-C1CC-11D6-BD01-00039315CD46 in CFBundle/CFPlugIn 0x7fd672c25910 </Library/Audio/Plug-Ins/HAL/SeratoVirtualAudioPlugIn.plugin> (bundle, not loaded)
2015-11-17 11:20:16.580 java[5899:9037084] 11:20:16.580 WARNING: >compload> 472: Kickstart.component -- file://localhost/Library/Audio/Plug-Ins/Components/: trouble parsing Info.plist's AudioComponents, key (null); entry: <CFBasicHash 0x7fd67521c3f0 [0x7fff73159390]>{type = mutable dict, count = 7,
entries =>
2 : <CFString 0x7fff730e39f0 [0x7fff73159390]>{contents = "manufacturer"} = <CFString 0x7fd675231660 [0x7fff73159390]>{contents = "CaNR"}
7 : <CFString 0x7fff730e74b0 [0x7fff73159390]>{contents = "factoryFunction"} = <CFString 0x7fd6752319f0 [0x7fff73159390]>{contents = "KickstartAUFactory"}
8 : <CFString 0x7fd675230f10 [0x7fff73159390]>{contents = "subtype"} = <CFString 0x7fd675230f50 [0x7fff73159390]>{contents = "CNKS"}
9 : <CFString 0x7fff7310b6f0 [0x7fff73159390]>{contents = "description"} = <CFString 0x7fd67520fa20 [0x7fff73159390]>{contents = "Kickstart"}
10 : <CFString 0x7fff7310a3d0 [0x7fff73159390]>{contents = "type"} = <CFString 0x7fd675231030 [0x7fff73159390]>{contents = "kAudioUnitType_Effect"}
11 : <CFString 0x7fff73095bb0 [0x7fff73159390]>{contents = "name"} = <CFString 0x7fd675231630 [0x7fff73159390]>{contents = "Nicky Romero: Kickstart"}
12 : <CFString 0x7fff73114370 [0x7fff73159390]>{contents = "version"} = <CFNumber 0x1000937 [0x7fff73159390]>{value = +65545, type = kCFNumberSInt64Type}
}
2015-11-17 11:20:16.586 java[5899:9037084] 11:20:16.586 WARNING: >compload> 472: Primer.component -- file://localhost/Library/Audio/Plug-Ins/Components/: trouble parsing Info.plist's AudioComponents, key (null); entry: <CFBasicHash 0x7fd672c2dc50 [0x7fff73159390]>{type = mutable dict, count = 7,
entries =>
2 : <CFString 0x7fff730e39f0 [0x7fff73159390]>{contents = "manufacturer"} = <CFString 0x7fd672c2e720 [0x7fff73159390]>{contents = "AudG"}
7 : <CFString 0x7fff730e74b0 [0x7fff73159390]>{contents = "factoryFunction"} = <CFString 0x7fd672c2e8a0 [0x7fff73159390]>{contents = "PrimerAUFactory"}
8 : <CFString 0x7fd672c2e9d0 [0x7fff73159390]>{contents = "subtype"} = <CFString 0x7fd672c2ea10 [0x7fff73159390]>{contents = "agp"}
9 : <CFString 0x7fff7310b6f0 [0x7fff73159390]>{contents = "description"} = <CFString 0x7fd672c2c4a0 [0x7fff73159390]>{contents = "Primer"}
10 : <CFString 0x7fff7310a3d0 [0x7fff73159390]>{contents = "type"} = <CFString 0x7fd672c2ec50 [0x7fff73159390]>{contents = "aumu"}
11 : <CFString 0x7fff73095bb0 [0x7fff73159390]>{contents = "name"} = <CFString 0x7fd672c2e900 [0x7fff73159390]>{contents = "Audible Genius: Primer"}
12 : <CFString 0x7fff73114370 [0x7fff73159390]>{contents = "version"} = <CFNumber 0x1010137 [0x7fff73159390]>{value = +65793, type = kCFNumberSInt64Type}
}
Я совсем не понимаю эту ошибку. Единственное, что я знаю, это то, что это доступ к моим аудио плагинам. Я также знаю, что ошибка происходит в:
line = (SourceDataLine)AudioSystem.getLine(info);
line.open(format);
Кто-нибудь знает, в чем причина этой ошибки? Или как это исправить?
1 ответ
У меня есть предложение попробовать: откройте строку с настройками по умолчанию в обоих контекстах и проверьте форматы. Код, который вы написали, может возражать, например, если формат, который вы жестко запрограммировали, не поддерживается.
Чтобы открыть со значениями по умолчанию, опустите аргументы метода line.open(). Чтобы получить формат, используйте метод line.getFormat (). Вы также можете проверить работоспособность линии, воспроизведя файл wav на разных ОС. Если wavs воспроизводится нормально, используйте тот же формат в коде урока.
Основная причина, по которой я предлагаю это, заключается в том, что я удивлен тем, что BigEndian используется как часть формата. Я всегда использовал LittleEndian.
Если по умолчанию используется стерео, вы должны иметь возможность создавать и использовать идентичный формат, единственное отличие - моно, так что вам не придется изменять остальную часть кода.
Тем не менее, есть некоторые различия в остальной части кода, который я вроде как задаю. Я написал и использую следующую базовую форму для отправки нормализованных аудиоданных PCM на рабочие столы Java:
float[] normalizedOut = float[2];
byte[] buffer = new byte[outBufferSize];
int i;
while(playing)
{
i = 0;
while(i < outBufferSize)
{
// obtain normalized, stereo PCM output from synth
normalizedOut = synth.getNextFrame();
// convert normalized to stereo bytes, "CD quality"
normalizedOut[0] *= 32767;
normalizedOut[1] *= 32767;
// this part converts to Little Endian
outBuffer[i++] = (byte) normalizedOut[0];
outBuffer[i++] = (byte)((int)normalizedOut[0] >> 8);
outBuffer[i++] = (byte) normalizedOut[1];
outBuffer[i++] = (byte)((int)normalizedOut[1] >> 8 );
}
line.write(outBuffer, 0, outBufferSize);
}
Я думаю, что вполне нормально разрешить Java обрабатывать блокировки. В конечном итоге система потратит что-то вроде 98% (догадка с дикой оценкой) блокировки в этом потоке, если только ваш "синтезаторный" алгоритм не слишком тяжелый.
Вышеуказанные циклы по одному кадру за раз. Вероятно, было бы немного лучше получить синусоидальные данные большими кусками, но мне нравится простота вышеописанного. Кроме того, это, кажется, выполняет "достаточно хорошо". Например, вы можете скачать и попробовать написанную мною реализацию, которая включает в себя вышеупомянутое, в котором используются 6 FM-синтезаторов (каждый из которых использует несколько синусов в качестве носителей и модуляторов), и все они воспроизводятся одновременно.
circleounds.jar demo(Использует Java 8. Что напоминает мне, что некоторые старые версии Mac OS не поддерживают некоторые версии Java. Я вспоминаю друга с ноутбуком Mac, который не мог запускать программы на Java 7, которые я хотел, чтобы он попробуйте. Я не в курсе истории этого.)