2015-11-17 81 views
2

我這裏有這個代碼,我從如何創建一個可聽正弦波的教程有: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); 

有沒有人知道這個錯誤的原因是什麼?或者如何解決它?

回答

0

我有一個建議嘗試:在上下文中打開默認設置的行並檢查格式。例如,如果您硬編碼的格式不受支持,則您編寫的代碼可能會反對。

要使用默認值打開,請省略參數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合成器(每個都採用多個正弦信號作爲載波和調製器),並一次播放。

circlesounds.jar demo (使用Java 8.這提醒了我,有些舊版本的Mac OS不支持某些版本的Java,我記得有一臺Mac筆記本電腦的朋友無法運行Java 7程序。他來試試看,我沒有注意到這個歷史。)