2011-12-25 26 views
7

जावा में किसी भी आवृत्ति पर साइन लहर ध्वनि उत्पन्न करने का सबसे आसान तरीका क्या है? 2 बाइट से अधिक नमूना आकार मदद करेगा, लेकिन यह वास्तव में कोई फर्क नहीं पड़ता।जावा में साइन वेव साउंड जनरेटर

धन्यवाद

उत्तर

9

एक आत्मनिर्भर उदाहरण के लिए Beeper देखें।


शायद कुछ सरल?

स्निपेट की 51 लाइनें (नीचे भी दोहराया - एक पंक्ति & में लाइन टिप्पणी के लिए थोड़े-थोड़े अंतराल) यही कारण है कि के रूप में जुड़े हुए जवाब के शीर्ष पर दिखाया गया है, एक स्वर पैदा करने के रूप में के बारे में के रूप में सरल है हो जाता है (ठीक है, आप कर सकते हैं हार्मोनिक के लिए 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(); 
    } 
} 
+1

यह भी देखें ['नोट'] (http://stackoverflow.com/a/2065693/230513)। – trashgod

7

Java Sound API, और Math.sin का उपयोग वास्तविक लहर स्तरों बनाने के लिए।

http://www.developer.com/java/other/article.php/2226701 इस बारे में एक उत्कृष्ट ट्यूटोरियल है जिसे मैंने कुछ समय पहले संदर्भित किया था। http://jsresources.org/examples/ एक और उपयोगी संदर्भ था।

+0

कुछ नमूना कोड में मदद मिलेगी स्ट्रीम है, लेकिन मैं वहाँ – milo

+0

के माध्यम से देख developer.com लेख नमूना कोड से भरा हुआ है की कोशिश करेंगे। – ziesemer

6

आप आरंभ करने के लिए कुछ आसान कोड चाहते हैं, यह मदद करनी चाहिए

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

यह पढ़ने में आसान है, लेकिन जादू संख्या 127f कहां से आया? – nont

+1

@ नॉन पाप एक मान -1.0 से 1.0 देता है, 127 द्वारा इसे गुणा करके आपको एक बाइट -127 से +127 के पूर्ण पैमाने के साथ एक साइन लहर देता है, (यह बाइट में डाला जाता है) –

0

मैं सिर्फ बाहर बात करने के लिए साइन लहरों पैदा करने के लिए एक बहुत ही कुशल एल्गोरिथ्म है कि वहाँ चाहते हैं।

डीएसपी चाल: Sinusoidal टोन जनरेटर http://www.dspguru.com/dsp/tricks/sine_tone_generator

0

एक पहले मैं सलाह में बनाने वर्ग नोट, जो टिप्पणी की frequences लौटने के लिए, और यह बाइट सरणी में बदलने का।

तो यह बहुत 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; 
    } 
}