【问题标题】:Sine Wave Sound Generator in JavaJava中的正弦波声音发生器
【发布时间】:2012-01-27 18:15:38
【问题描述】:

在 Java 中生成任意频率的正弦波声音的最简单方法是什么? 超过 2 个字节的样本大小会有所帮助,但这并不重要。

【问题讨论】:

    标签: java audio javasound wave trigonometry


    【解决方案1】:

    这些答案中的 createSinWaveBuffer() 方法不会产生良好的波形数据以供连续播放。需要使最后一个字节接近零才能获得完整的波形。更好的例子 -

    protected static final float SAMPLE_RATE = 16 * 1024;
    
    public static byte[] createSinWaveBuffer(double freq) {
       double waveLen = 1.0/freq;
       int samples = (int) Math.round(waveLen * 5 * SAMPLE_RATE);
       byte[] output = new byte[samples];
       double period = SAMPLE_RATE / freq;
       for (int i = 0; i < output.length; i++) {
           double angle = 2.0 * Math.PI * i / period;
           output[i] = (byte)(Math.sin(angle) * 127f);  }
    
       return output;
    }
    

    【讨论】:

      【解决方案2】:

      如果您只是在寻找一个需要哔哔声的类,那么试试这个:(从 Thumbz 借来的一些代码)

        package ditdah;
      
       import javax.sound.sampled.AudioFormat;
       import javax.sound.sampled.AudioSystem;
       import javax.sound.sampled.LineUnavailableException;
       import javax.sound.sampled.SourceDataLine;
      
       public class Beep {
      
      protected static final int SAMPLE_RATE = 16 * 1024;
      
      public void play(double freq, int length) {
          final AudioFormat af = new AudioFormat(SAMPLE_RATE, 8, 1, true, true);
          try {
              SourceDataLine line = AudioSystem.getSourceDataLine(af);
              line.open(af, SAMPLE_RATE);
              line.start();
      
              byte[] toneBuffer = this.createSinWaveBuffer(freq, length);
              say.it(toneBuffer.toString() + " " + toneBuffer.length);
              int count = line.write(toneBuffer, 0, toneBuffer.length);
              line.drain();
              line.close();
          } catch (LineUnavailableException e) {
              say.it(e.getLocalizedMessage());
          }
      }
      
      public byte[] createSinWaveBuffer(double freq, int ms) {
          int samples = (int) ((ms * SAMPLE_RATE) / 1000);
          byte[] output = new byte[samples];
          //
          double period = (double) SAMPLE_RATE / freq;
          for (int i = 0; i < output.length; i++) {
              double angle = 2.0 * Math.PI * i / period;
              output[i] = (byte) (Math.sin(angle) * 127f);
          }
      
          return output;
      }
      

      }

      【讨论】:

        【解决方案3】:

        首先我建议创建类Note,它返回音符的频率,并将其转换为字节数组。

        然后非常轻松地进行流式传输

            protected static final int SAMPLE_RATE = 8 * 1024;
        
        
            public static void main(String[] args) throws LineUnavailableException {
                final AudioFormat af = new AudioFormat(SAMPLE_RATE, 8, 1, true, true);
                SourceDataLine line = AudioSystem.getSourceDataLine(af);
                line.open(af, SAMPLE_RATE);
                line.start();
        
                // fist argument is duration of playing note 
                byte[] noteDo = Note.DO.getTone(1, SAMPLE_RATE);
                byte[] noteRe = Note.RE.getTone(0.5, SAMPLE_RATE);
                byte[] noteMi = Note.MI.getTone(1.5, SAMPLE_RATE);
        
                line.write(noteDo, 0, noteDo.length);
                line.write(noteRe, 0, noteRe.length);
                line.write(noteMi, 0, noteMi.length);
        
                line.drain();
                line.close();
            }
        
        
        
        public enum Note {
        
            DO(0.0f), DO_DIEZ(1.0f),
            RE(2.0f), RE_DIEZ(3.0f),
            MI(4.0f),
            FA(5.0f), FA_DIEZ(6.0f),
            SOL(7.0f),SOL_DIEZ(8.0f),
            LYA(9.0f),LYA_DIEZ(10.0f),
            SI(11.0f);
        
        
            private final double mPhase;
        
            Note(double phase) {
                mPhase = phase;
            }
        
            public double getNoteFrequencies() {
        
                double index = getmPhase()/ 12.0d;
        
                return 440 * Math.pow(2, index);
            }
        
            public static Note getNote(double phase) throws Exception {
        
                Note findNote = null;
        
                for (Note note : Note.values()){
                    if (note.getmPhase() == phase){
                        findNote = note;
                    }
                }
        
                if (findNote == null)
                    throw new Exception("Note not found: Ilegal phase " + phase);
                else
                    return findNote;
            }
        
            public byte[] getTone(double duration, int rate){
        
                double frequencies = getNoteFrequencies();
        
                int maxLength = (int)(duration * rate);
                byte generatedTone[] = new byte[2 * maxLength];
        
                double[] sample = new double[maxLength];
                int idx = 0;
        
                for (int x = 0; x < maxLength; x++){
                    sample[x] = sine(x, frequencies / rate);
                }
        
        
                for (final double dVal : sample) {
        
                    final short val = (short) ((dVal * 100f));
        
                    // in 16 bit wav PCM, first byte is the low order byte
                    generatedTone[idx++] = (byte) (val & 0x00ff);
                    generatedTone[idx++] = (byte) ((val & 0xff00) >>> 8);
        
                }
        
                return generatedTone;
            }
        
            private double sine(int x, double frequencies){
                return Math.sin(  2*Math.PI * x * frequencies);
            }
        
            public double getmPhase() {
                return mPhase;
            }
        }
        

        【讨论】:

        • 你从哪里得到的类:AudioFormat SourceDataLine AudioSystem?当有人发布代码并且没有发布他/她使用的类的来源时,应该会自动投反对票。
        【解决方案4】:

        我只想指出,有一种非常有效的算法可以生成正弦波。

        DSP 技巧:正弦音调发生器 http://www.dspguru.com/dsp/tricks/sine_tone_generator

        【讨论】:

          【解决方案5】:

          如果您想要一些简单的代码来帮助您入门,这应该会有所帮助

          import javax.sound.sampled.AudioFormat;
          import javax.sound.sampled.AudioSystem;
          import javax.sound.sampled.LineUnavailableException;
          import javax.sound.sampled.SourceDataLine;
          
          public class SinSynth {
              //
             protected static final int SAMPLE_RATE = 16 * 1024;
          
          
             public static byte[] createSinWaveBuffer(double freq, int ms) {
                 int samples = (int)((ms * SAMPLE_RATE) / 1000);
                 byte[] output = new byte[samples];
                     //
                 double period = (double)SAMPLE_RATE / freq;
                 for (int i = 0; i < output.length; i++) {
                     double angle = 2.0 * Math.PI * i / period;
                     output[i] = (byte)(Math.sin(angle) * 127f);  }
          
                 return output;
             }
          
          
          
             public static void main(String[] args) throws LineUnavailableException {
                 final AudioFormat af = new AudioFormat(SAMPLE_RATE, 8, 1, true, true);
                 SourceDataLine line = AudioSystem.getSourceDataLine(af);
                 line.open(af, SAMPLE_RATE);
                 line.start();
          
                 boolean forwardNotBack = true;
          
                 for(double freq = 400; freq <= 800;)  {
                     byte [] toneBuffer = createSinWaveBuffer(freq, 50);
                     int count = line.write(toneBuffer, 0, toneBuffer.length);
          
                     if(forwardNotBack)  {
                         freq += 20;  
                         forwardNotBack = false;  }
                     else  {
                         freq -= 10;
                         forwardNotBack = true;  
                 }   }
          
                 line.drain();
                 line.close();
              }
          
          }
          

          【讨论】:

          • 这很容易阅读,但神奇的数字 127f 是从哪里来的?
          • @nont sin 返回一个值 -1.0 到 1.0,将它乘以 127 得到一个满量程为一个字节 -127 到 +127 的正弦波,(它被转换为一个字节)跨度>
          【解决方案6】:

          请参阅 Beeper 了解独立示例。


          也许更简单一些?

          如链接答案顶部所示的 51 行 sn-p(在下面重复 - 为单行和内联 cmets 间隔开),与生成音调一样简单(好的,你可以采取谐波超过 5 行)。

          人们似乎认为它应该是工具包中内置的一种方法来产生纯音。它不是,而且需要一点计算才能做出来。

          /** Generates a tone, and assigns it to the Clip. */
          public void generateTone()
              throws LineUnavailableException {
              if ( clip!=null ) {
                  clip.stop();
                  clip.close();
              } else {
                  clip = AudioSystem.getClip();
              }
              boolean addHarmonic = harmonic.isSelected();
          
              int intSR = ((Integer)sampleRate.getSelectedItem()).intValue();
              int intFPW = framesPerWavelength.getValue();
          
              float sampleRate = (float)intSR;
          
              // oddly, the sound does not loop well for less than
              // around 5 or so, wavelengths
              int wavelengths = 20;
              byte[] buf = new byte[2*intFPW*wavelengths];
              AudioFormat af = new AudioFormat(
                  sampleRate,
                  8,  // sample size in bits
                  2,  // channels
                  true,  // signed
                  false  // bigendian
                  );
          
              int maxVol = 127;
              for(int i=0; i<intFPW*wavelengths; i++){
                  double angle = ((float)(i*2)/((float)intFPW))*(Math.PI);
                  buf[i*2]=getByteValue(angle);
                  if(addHarmonic) {
                      buf[(i*2)+1]=getByteValue(2*angle);
                  } else {
                      buf[(i*2)+1] = buf[i*2];
                  }
              }
          
              try {
                  byte[] b = buf;
                  AudioInputStream ais = new AudioInputStream(
                      new ByteArrayInputStream(b),
                      af,
                      buf.length/2 );
          
                  clip.open( ais );
              } catch(Exception e) {
                  e.printStackTrace();
              }
          }
          

          【讨论】:

            【解决方案7】:

            使用Java Sound APIMath.sin 创建实际的波级。

            http://www.developer.com/java/other/article.php/2226701 有一个很好的教程,我前段时间参考过。 http://jsresources.org/examples/ 是另一个有用的参考。

            【讨论】:

            • 一些示例代码会有所帮助,但我会尝试查看那里
            猜你喜欢
            • 2012-01-08
            • 2011-07-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-04-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多