Sine Wave Sound Generator in Java

后端 未结 7 1955
时光说笑
时光说笑 2020-12-05 01:22

What\'s the simplest way to generate a sine wave sound at any frequency in Java? A sample size more than 2 bytes would help, but it doesn\'t really matter.

相关标签:
7条回答
  • 2020-12-05 01:53

    In a first I advice create class Note, which return frequences of note, and convert it to byte array.

    Then stream it very 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;
        }
    }
    
    0 讨论(0)
  • 2020-12-05 01:53

    I'd just like to point out that there is a very efficient algorithm for generating sine waves.

    DSP Trick: Sinusoidal Tone Generator http://www.dspguru.com/dsp/tricks/sine_tone_generator

    0 讨论(0)
  • 2020-12-05 02:00

    Use the Java Sound API, and Math.sin to create the actual wave levels.

    http://www.developer.com/java/other/article.php/2226701 has an excellent tutorial around this that I had referenced some time ago. http://jsresources.org/examples/ was another useful reference.

    0 讨论(0)
  • 2020-12-05 02:01

    See Beeper for a self-contained example.


    Perhaps something simpler?

    That 51 lines of snippet (repeated below - spaced out for single line & in-line comments) as shown at the top of the linked answer, is about as simple as generating a tone gets (OK, you can take out 5+ lines for the harmonic).

    People seem to assume it should be a method built into the toolkit to produce a pure tone. It is not, and takes a little calculating to make one.

    /** 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();
        }
    }
    
    0 讨论(0)
  • 2020-12-05 02:10

    If you want some easy code to get you started, this should help

    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 讨论(0)
  • 2020-12-05 02:11

    if you are looking for just a class to call for a beep, then try this: (some code borrowed from 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;
    }
    

    }

    0 讨论(0)
提交回复
热议问题