#java #eclipse
Вопрос:
У меня такое чувство, что это будет тривиальный вопрос, но это заставляет меня биться головой о стену.
Мне нужна была программа на Java, которая могла бы записывать звук так быстро, как только это возможно. Я искал какой-то уже существующий код, я нашел его и внес ровно одно изменение в код: я гарантировал, что первым делом после создания графического интерфейса будет сама Java, чтобы нажать кнопку записи.
Ниже приведен измененный основной метод, найденный в классе SwingSoundRecorder
:
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
SwingSoundRecorder GUI = null;
GUI = new SwingSoundRecorder();
GUI.setVisible(true);
// This line ensures the GUI will start recording immediately
GUI.buttonPlay.doClick();
}
});
}
Сделав это, я попытался экспортировать его как исполняемый файл Java. Поскольку я использую Eclipse, я подумал, что это будет очень просто: нужно просто указать, где вы хотите получить файл .jar и что является основным классом.
Ну, по-видимому, Java не признает SwingSoundRecorder
, что у нее есть основной метод для использования. И я действительно не понимаю, почему.
Есть идеи? Какая-нибудь помощь?
Редактировать: полный код всех четырех задействованных классов, как справедливо хотел @аниш Шарма:
public class SwingSoundRecorder extends JFrame implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 2747541100831140840L;
private JButton buttonRecord = new JButton("Record");
private JButton buttonPlay = new JButton("Play");
private JLabel labelRecordTime = new JLabel("Record Time: 00:00:00");
private SoundRecordingUtil recorder = new SoundRecordingUtil();
private AudioPlayer player = new AudioPlayer();
private Thread playbackThread;
private RecordTimer timer;
private boolean isRecording = false;
private boolean isPlaying = false;
private String saveFilePath;
// Icons used for buttons
private ImageIcon iconRecord = new ImageIcon(getClass().getResource(
"/net/codejava/sound/images/Record.gif"));
private ImageIcon iconStop = new ImageIcon(getClass().getResource(
"/net/codejava/sound/images/Stop.gif"));
private ImageIcon iconPlay = new ImageIcon(getClass().getResource(
"/net/codejava/sound/images/Play.gif"));
/**
* launch the program
*
*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
SwingSoundRecorder GUI = null;
GUI = new SwingSoundRecorder();
GUI.setVisible(true);
// This line ensures the GUI will start recording immediately
GUI.buttonPlay.doClick();
}
});
}
public SwingSoundRecorder() {
super("Swing Sound Recorder");
setLayout(new FlowLayout());
buttonRecord.setFont(new Font("Sans", Font.BOLD, 14));
buttonRecord.setIcon(iconRecord);
buttonPlay.setFont(new Font("Sans", Font.BOLD, 14));
buttonPlay.setIcon(iconPlay);
buttonPlay.setEnabled(false);
labelRecordTime.setFont(new Font("Sans", Font.BOLD, 12));
add(buttonRecord);
add(labelRecordTime);
add(buttonPlay);
buttonRecord.addActionListener(this);
buttonPlay.addActionListener(this);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
/**
* Handle click events on the buttons.
*/
@Override
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
if (button == buttonRecord) {
if (!isRecording) {
startRecording();
} else {
stopRecording();
}
} else if (button == buttonPlay) {
if (!isPlaying) {
playBack();
} else {
stopPlaying();
}
}
}
/**
* Start recording sound, the time will count up.
*/
private void startRecording() {
Thread recordThread = new Thread(new Runnable() {
@Override
public void run() {
try {
isRecording = true;
buttonRecord.setText("Stop");
buttonRecord.setIcon(iconStop);
buttonPlay.setEnabled(false);
recorder.start();
} catch (LineUnavailableException ex) {
JOptionPane.showMessageDialog(SwingSoundRecorder.this,
"Error", "Could not start recording sound!",
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
}
}
});
recordThread.start();
timer = new RecordTimer(labelRecordTime);
timer.start();
}
/**
* Stop recording and save the sound into a WAV file
*/
private void stopRecording() {
isRecording = false;
try {
timer.cancel();
buttonRecord.setText("Record");
buttonRecord.setIcon(iconRecord);
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
recorder.stop();
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
saveFile();
} catch (IOException ex) {
JOptionPane.showMessageDialog(SwingSoundRecorder.this, "Error",
"Error stopping sound recording!",
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
}
}
/**
* Start playing back the sound.
*/
private void playBack() {
timer = new RecordTimer(labelRecordTime);
timer.start();
isPlaying = true;
playbackThread = new Thread(new Runnable() {
@Override
public void run() {
try {
buttonPlay.setText("Stop");
buttonPlay.setIcon(iconStop);
buttonRecord.setEnabled(false);
player.play(saveFilePath);
timer.reset();
buttonPlay.setText("Play");
buttonRecord.setEnabled(true);
buttonPlay.setIcon(iconPlay);
isPlaying = false;
} catch (UnsupportedAudioFileException ex) {
ex.printStackTrace();
} catch (LineUnavailableException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
playbackThread.start();
}
/**
* Stop playing back.
*/
private void stopPlaying() {
timer.reset();
timer.interrupt();
player.stop();
playbackThread.interrupt();
}
/**
* Save the recorded sound into a WAV file.
*
* @author Nam Ha Minh, source is <a href="https://www.codejava.net/coding/capture-and-record-sound-into-wav-file-with-java-sound-api">here</a>
*/
private void saveFile() {
JFileChooser fileChooser = new JFileChooser();
FileFilter wavFilter = new FileFilter() {
@Override
public String getDescription() {
return "Sound file (*.WAV)";
}
@Override
public boolean accept(File file) {
if (file.isDirectory()) {
return true;
} else {
return file.getName().toLowerCase().endsWith(".wav");
}
}
};
fileChooser.setFileFilter(wavFilter);
fileChooser.setAcceptAllFileFilterUsed(false);
int userChoice = fileChooser.showSaveDialog(this);
if (userChoice == JFileChooser.APPROVE_OPTION) {
saveFilePath = fileChooser.getSelectedFile().getAbsolutePath();
if (!saveFilePath.toLowerCase().endsWith(".wav")) {
saveFilePath = ".wav";
}
File wavFile = new File(saveFilePath);
try {
recorder.save(wavFile);
JOptionPane.showMessageDialog(SwingSoundRecorder.this,
"Saved recorded sound to:n" saveFilePath);
buttonPlay.setEnabled(true);
} catch (IOException ex) {
JOptionPane.showMessageDialog(SwingSoundRecorder.this, "Error",
"Error saving to sound file!",
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
}
}
}
}
public class SoundRecordingUtil {
private static final int BUFFER_SIZE = 4096;
private ByteArrayOutputStream recordBytes;
private TargetDataLine audioLine;
private AudioFormat format;
private boolean isRunning;
/**
* Defines a default audio format used to record
*/
AudioFormat getAudioFormat() {
float sampleRate = 44100;
int sampleSizeInBits = 16;
int channels = 2;
boolean signed = true;
boolean bigEndian = true;
return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,
bigEndian);
}
/**
* Start recording sound.
* @throws LineUnavailableException if the system does not support the specified
* audio format nor open the audio data line.
*/
public void start() throws LineUnavailableException {
format = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
// checks if system supports the data line
if (!AudioSystem.isLineSupported(info)) {
throw new LineUnavailableException(
"The system does not support the specified format.");
}
audioLine = AudioSystem.getTargetDataLine(format);
audioLine.open(format);
audioLine.start();
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = 0;
recordBytes = new ByteArrayOutputStream();
isRunning = true;
while (isRunning) {
bytesRead = audioLine.read(buffer, 0, buffer.length);
recordBytes.write(buffer, 0, bytesRead);
}
}
/**
* Stop recording sound.
* @throws IOException if any I/O error occurs.
*/
public void stop() throws IOException {
isRunning = false;
if (audioLine != null) {
audioLine.drain();
audioLine.close();
}
}
/**
* Save recorded sound data into a .wav file format.
* @param wavFile The file to be saved.
* @throws IOException if any I/O error occurs.
* @throws UnsupportedAudioFileException
*/
public void save(File wavFile) throws IOException {
byte[] audioData = recordBytes.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(audioData);
AudioInputStream audioInputStream = new AudioInputStream(bais, format,
audioData.length / format.getFrameSize());
AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, wavFile);
audioInputStream.close();
recordBytes.close();
}
}
public class RecordTimer extends Thread {
private DateFormat dateFormater = new SimpleDateFormat("HH:mm:ss");
private boolean isRunning = false;
private boolean isReset = false;
private long startTime;
private JLabel labelRecordTime;
RecordTimer(JLabel labelRecordTime) {
this.labelRecordTime = labelRecordTime;
}
public void run() {
isRunning = true;
startTime = System.currentTimeMillis();
while (isRunning) {
try {
Thread.sleep(1000);
labelRecordTime.setText("Record Time: " toTimeString());
} catch (InterruptedException ex) {
ex.printStackTrace();
if (isReset) {
labelRecordTime.setText("Record Time: 00:00:00");
isRunning = false;
break;
}
}
}
}
/**
* Cancel counting record/play time.
*/
void cancel() {
isRunning = false;
}
/**
* Reset counting to "00:00:00"
*/
void reset() {
isReset = true;
isRunning = false;
}
/**
* Generate a String for time counter in the format of "HH:mm:ss"
* @return the time counter
*/
private String toTimeString() {
long now = System.currentTimeMillis();
Date current = new Date(now - startTime);
dateFormater.setTimeZone(TimeZone.getTimeZone("GMT"));
String timeCounter = dateFormater.format(current);
return timeCounter;
}
}
public class AudioPlayer implements LineListener {
/**
* this flag indicates whether the playback completes or not.
*/
boolean playCompleted;
/**
* this flag indicates whether the playback is stopped or not.
*/
boolean isStopped;
/**
* Play a given audio file.
*
* @param audioFilePath
* Path of the audio file.
* @throws IOException
* @throws UnsupportedAudioFileException
* @throws LineUnavailableException
*/
void play(String audioFilePath) throws UnsupportedAudioFileException,
IOException, LineUnavailableException {
File audioFile = new File(audioFilePath);
AudioInputStream audioStream = AudioSystem
.getAudioInputStream(audioFile);
AudioFormat format = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip audioClip = (Clip) AudioSystem.getLine(info);
audioClip.addLineListener(this);
audioClip.open(audioStream);
audioClip.start();
playCompleted = false;
while (!playCompleted) {
// wait for the playback completes
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
if (isStopped) {
audioClip.stop();
break;
}
}
}
audioClip.close();
}
/**
* Stop playing back.
*/
public void stop() {
isStopped = true;
}
/**
* Listens to the audio line events to know when the playback completes.
*/
@Override
public void update(LineEvent event) {
LineEvent.Type type = event.getType();
if (type == LineEvent.Type.STOP) {
playCompleted = true;
}
}
}
Комментарии:
1. пожалуйста, вставьте полный код класса
2. Вы пытались вставить в
net.codejava.sound.SwingSoundRecorder
текстовое поле основного класса «вручную»?3. @анишшарма Готово
4. @g00se Вы не можете в Eclipse: есть поле со списком, в котором должен отображаться каждый класс Java с основным методом, затем вы выбираете тот, который является основным классом вашего проекта. Я установил второе затмение только для того, чтобы этот проект был единственным в моем рабочем пространстве, и поле со списком пусто.
5. Ну, я только что попробовал, и вы можете в той версии, в которой я это пробовал (Версия: 2020-03 (4.15.0)). Я тоже обнаружил, что не могу перейти к правильному основному классу. Возможно, метаданные Eclipse в их файлах проекта являются неполными… (Я не использую IDE, когда могу этого избежать)