2011-12-25 48 views
7

Cách đơn giản nhất để tạo ra âm thanh sóng sin ở bất kỳ tần số nào trong Java? Kích thước mẫu hơn 2 byte sẽ giúp ích, nhưng nó không thực sự quan trọng.Máy phát âm thanh sóng sin trong Java

Cảm ơn

Trả lời

9

Xem Beeper để có ví dụ độc lập.


Có lẽ một cái gì đó đơn giản hơn?

Đó 51 dòng đoạn (lặp đi lặp lại bên dưới - cách nhau ra cho dòng đơn & comments in-line) như thể hiện ở đầu câu trả lời liên quan, là về đơn giản như tạo ra một giai điệu được (OK, bạn có thể lấy ra 5 dòng cho hài hòa).

Mọi người dường như cho rằng đó phải là phương pháp được tích hợp vào bộ công cụ để tạo ra âm thanh thuần túy. Nó không phải là, và mất một chút tính toán để làm cho một.

/** 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(); 
    } 
} 
+1

Xem thêm ['Note'] (http://stackoverflow.com/a/2065693/230513). – trashgod

7

Sử dụng Java Sound API, và Math.sin để tạo ra các mức sóng thực tế.

http://www.developer.com/java/other/article.php/2226701 có hướng dẫn tuyệt vời về điều này mà tôi đã tham chiếu một thời gian trước đây. http://jsresources.org/examples/ là một tài liệu tham khảo hữu ích khác.

+0

Một số mẫu mã sẽ giúp đỡ, nhưng tôi sẽ cố gắng nhìn qua có – milo

+0

Bài viết developer.com là đầy đủ mẫu mã. – ziesemer

6

Nếu bạn muốn một số mã dễ dàng để giúp bạn bắt đầu, điều này sẽ giúp

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(); 
    } 

} 
+0

dễ đọc, nhưng số ma thuật 127f đến từ đâu? – nont

+1

@nont sin trả về một giá trị -1,0 đến 1.0, nhân nó với 127 cho bạn một làn sóng sin với một tỷ lệ đầy đủ của một byte -127 đến +127, (nó được đúc thành một byte) –

0

Trong một lời khuyên tôi lần đầu tiên tạo ra lớp Note, mà trở frequences chú ý, và chuyển nó sang mảng byte.

Sau đó, dòng nó rất easly

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; 
    } 
} 
Các vấn đề liên quan