Générateur de Son Sinusoïdal en Java


Quel est le moyen le plus simple de générer un son sinusoïdal à n'importe quelle fréquence en Java? Une taille d'échantillon supérieure à 2 octets aiderait, mais cela n'a pas vraiment d'importance.

Merci

Author: Andrew Thompson, 2011-12-26

6 answers

Voir Beeper pour un exemple.


Peut-être quelque chose de plus simple?

Que 51 lignes d'extrait (répétées ci-dessous-espacées pour une seule ligne et des commentaires en ligne) comme indiqué en haut de la réponse liée, est à peu près aussi simple que de générer un ton (OK, vous pouvez retirer 5+ lignes pour l'harmonique).

Les gens semblent supposer que ce devrait être une méthode intégrée à la boîte à outils pour produire un ton pur. Il n'est pas, et prend un peu calculateur pour en faire un.

/** 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();
    }
}
 10
Author: Andrew Thompson, 2017-05-23 12:34:14

Utilisez Java Sound API et Math.sin pour créer les niveaux d'onde réels.

Http://www.developer.com/java/other/article.php/2226701 a un excellent tutoriel autour de cela que j'avais référencé il y a quelque temps. http://jsresources.org/examples / était une autre référence utile.

 8
Author: ziesemer, 2011-12-25 23:23:27

Si vous voulez un code facile pour vous aider à démarrer, cela devrait aider

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

}
 8
Author: Thumbz, 2014-05-29 08:16:58

Dans un premier conseil, je crée une classe Note, qui renvoie des fréquences de note, et la convertit en tableau d'octets.

Puis diffusez-le très facilement

    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;
    }
}
 1
Author: Vahe Gharibyan, 2016-10-29 17:12:28

Je voudrais juste souligner qu'il existe un algorithme très efficace pour générer des ondes sinusoïdales.

Astuce DSP: Générateur de tonalité sinusoïdale http://www.dspguru.com/dsp/tricks/sine_tone_generator

 0
Author: Albin Stigo, 2015-02-11 16:51:48

Si vous cherchez juste une classe pour appeler un bip, essayez ceci: (du code emprunté à 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
Author: Baruch Atta, 2018-07-17 19:29:59