1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
| import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.ByteBuffer;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
public class JFrame_sliderSine extends JFrame {
/**
*
*/
private static final long serialVersionUID = 3481827887325136254L;
private SampleThread m_thread;
private JSlider m_sliderPitch;
//Launch the app
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JFrame_sliderSine frame = new JFrame_sliderSine();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public JFrame_sliderSine() {
//UI stuff, created with WindowsBuilder
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
m_thread.exit();
System.exit(0);
}
});
setTitle("Slider Frequency Sine Wave Demo");
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 793, 166);
setLocationRelativeTo(null);
getContentPane().setLayout(new BorderLayout(0, 0));
m_sliderPitch = new JSlider();
m_sliderPitch.setName("");
m_sliderPitch.setMinimum(100);
m_sliderPitch.setPaintLabels(true);
m_sliderPitch.setPaintTicks(true);
m_sliderPitch.setMajorTickSpacing(500);
m_sliderPitch.setMinorTickSpacing(100);
m_sliderPitch.setMaximum(4100);
m_sliderPitch.setValue(880);
getContentPane().add(m_sliderPitch);
JLabel lblAdjustPitch = new JLabel("Adjust pitch");
lblAdjustPitch.setHorizontalAlignment(SwingConstants.CENTER);
lblAdjustPitch.setFont(new Font("Tahoma", Font.PLAIN, 18));
getContentPane().add(lblAdjustPitch, BorderLayout.NORTH);
//Non-UI stuff
m_thread = new SampleThread();
m_thread.start();
}
class SampleThread extends Thread{
final static public int SAMPLING_RATE = 44100;
final static public int SAMPLE_SIZE = 2; //Sample size in bytes
final static public double BUFFER_DURATION = 0.426; //About a 500ms buffer
//You can play with the size of this buffer if you want. Making it smaller speeds up
//the response to the slider movement, but if you make it too small you will get
//noise in your output from buffer underflows, etc...
// Size in bytes of sine wave samples we'll create on each loop pass
final static public int SINE_PACKET_SIZE = (int)(BUFFER_DURATION * SAMPLING_RATE * SAMPLE_SIZE);
SourceDataLine line; //$
public double fFreq;
public boolean bExitThread = false;
//Get the number of queued samples in the SourceDataLine buffer
private int getLineSampleCount() {
return line.getBufferSize() - line.available();
}
//Continually fill the audio output buffer whenever it starts to get empty, SINE_PACKET_SIZE/2
//samples at a time, until we tell the thread to exit
public void run() {
//Position through the sine wave as a percentage (i.e. 0-1 is 0-2*PI)
double fCyclePosition = 0;
//Open up the audio output, using a sampling rate of 44100hz, 16 bit samples, mono, and big
// endian byte ordering. Ask for a buffer size of at least 2*SINE_PACKET_SIZE
try {
AudioFormat format = new AudioFormat(44100, 16, 1, true, true);
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format, SINE_PACKET_SIZE * 2);
if(!AudioSystem.isLineSupported(info)) throw new LineUnavailableException();
line = (SourceDataLine)AudioSystem.getLine(info);
line.open(format);
line.start();
} catch (LineUnavailableException e){
System.out.println("Line of that type is not available");
e.printStackTrace();
System.exit(-1);
}
System.out.println("Requested line buffer size = " + SINE_PACKET_SIZE*2);
System.out.println("Actual line buffer size = " + line.getBufferSize());
ByteBuffer cBuff = ByteBuffer.allocate(SINE_PACKET_SIZE);
//On each pass main loop fills the available free space in the audio buffer
//Main loop creates audio samples for sine wave, runs until we tell the thread to exit
//Each sample is spaced 1/SAMPLING_RATE apart in time
while(bExitThread == false) {
fFreq = m_sliderPitch.getValue();
double fCycleInc = fFreq / SAMPLING_RATE; //Fraction of cycle between samples
cBuff.clear(); //Toss out samples from previous pass
//Generate SINE_PACKET_SIZE samples based on the current fCycleInc from fFreq
for(int i = 0; i < SINE_PACKET_SIZE / SAMPLE_SIZE; i++){
cBuff.putShort((short)(Short.MAX_VALUE * Math.sin(2 * Math.PI * fCyclePosition)));
fCyclePosition += fCycleInc;
if(fCyclePosition > 1) fCyclePosition -= 1;
}
//Write sine samples to the line buffer
// If the audio buffer is full, this would block until there is enough room,
// but we are not writing unless we know there is enough space.
line.write(cBuff.array(), 0, cBuff.position());
//Wait here until there are less than SINE_PACKET_SIZE samples in the buffer
//(Buffer size is 2*SINE_PACKET_SIZE at least, so there will be room for
// at least SINE_PACKET_SIZE samples when this is true)
try {
while(getLineSampleCount() > SINE_PACKET_SIZE) Thread.sleep(1);
} catch (InterruptedException e) {
}
}
line.drain();
line.close();
}
public void exit() {
bExitThread = true;
}
}
} |
Partager