Sine Wave Sound Generator en Java
Quelle est la façon la plus simple de générer un son sinusoïdal à N'importe quelle fréquence en Java? Une taille d'échantillon de plus de 2 octets aiderait, mais cela n'a pas vraiment d'importance.
Merci
6 réponses
Voir Beeper
pour un exemple.
peut-être quelque chose de plus simple?
que 51 lignes de snippet (répété ci-dessous-espacées pour les commentaires de ligne simple et en ligne) comme montré en haut de la réponse liée, est aussi simple que de générer un gets de ton (OK, vous pouvez prendre 5+ lignes pour l'harmonique).
les Gens semblent supposer qu'il devrait être une méthode intégrée dans la boîte à outils pour produire un son pur. Il n'est pas, et prend un peu de calcul 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();
}
}
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 à ce sujet que j'avais mentionné il y a quelque temps. http://jsresources.org/examples/ était une autre référence utile.
Si vous voulez un peu de code facile à démarrer, ce qui 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();
}
}
Dans un premier je le conseil à créer de la classe Remarque:, qui renvoie les fréquences de note, et les convertit en byte array.
Puis de le transmettre 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;
}
}
je voudrais juste signaler qu'il existe un algorithme efficace pour la génération d'ondes sinusoïdales.
astuce DSP: générateur de tonus sinusoïdal http://www.dspguru.com/dsp/tricks/sine_tone_generator
si vous cherchez juste une classe pour appeler un bip, alors essayez ceci: (un 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;
}
}