我正在尝试通过读取现有的.wav文件来生成音频波形,该文件会随着音乐的实时播放而更新。例如,如果播放歌曲,我希望随着歌曲的进行不断产生波形。到目前为止,我已经能够从.wav文件中读取数据并使用javafx生成大约2500首歌曲的STATIC波形。我将波形与大胆的波形进行了比较,并且非常匹配。看起来是这样的:
但是,我对如何使波形不仅针对特定窗口静态生成还是在整个歌曲持续时间内生成不断更新的波形感到困惑。我一直在研究实时图表并使用ScheduledExecutorService,但似乎无法使折线图绘制新点的速度快于每秒一次,而不会引起问题。我还有其他方法可以做到这一点吗?我在此上花了很多时间,现在不想放弃。我在下面附加了我的代码,看看吧。谢谢。
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.shape.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.geometry.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.scene.text.Text;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.Group;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.TargetDataLine;
import java.net.*;
import java.io.*;
import java.nio.*;
public class Practice2 extends Application {
public static AudioInputStream audioInputStream;
@Override
public void start(Stage primaryStage) {
int channelCounter = 2; //used to jump between left and right channel in the loop
try {
File file = new File("testData/record.wav");
byte[] data = new byte[(int)file.length()];
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
in.read(data);
in.close();
File leftChannelFile = new File("audioData/leftChannelAmpData.txt");
File rightChannelFile = new File("audioData/rightChannelAmpData.txt");
//Defining the x axis
NumberAxis xAxis = new NumberAxis(0, 2490, 1);
xAxis.setLabel("Samples");
//Defining the y axis
NumberAxis yAxis = new NumberAxis (-675, 675, 1);
yAxis.setLabel("Amplitude");
//Creating the line chart
LineChart linechart = new LineChart(xAxis, yAxis);
linechart.setPrefHeight(1350); //picked 1350 and 2500 because it is slightly less than the height and width of my monitor. Will definitely change these values in the future
linechart.setPrefWidth(2500);
linechart.setMaxHeight(1350);
linechart.setMaxWidth(2500);
//Prepare XYChart.Series objects by setting data
XYChart.Series series = new XYChart.Series();
series.setName("Amplitude from sample");
for (int i=44; i < data.length - 1; i+=2) { //start at the 44th byte of the .wav file. This skips the header info and reads the raw data
if (channelCounter % 2 == 0) { //This represents the loop for the left channel
channelCounter++;
short tempAmp = calculateAmpValue(data[i], data[i+1]); // Since the amplitude value for each sample is represented by 2 bytes instead of 1, this function takes the next 2 bytes and gives an integer representation for it (-32728 to 32727)
if (i < 2491)
series.getData().add(new XYChart.Data(i-43, tempAmp / 50)); //divide by 50 so the amplitude values can fit within the range of my graph.
}
else if (channelCounter % 2 == 1) { //this represents the loop for the right channel. ***I'M ONLY BUILDING A WAVEFORM FOR THE LEFT CHANNEL AT THE MOMENT. ***
channelCounter++;
short tempAmp = calculateAmpValue(data[i], data[i+1]);
}
}
//Setting the data to Line chart
linechart.getData().add(series);
Group root = new Group(linechart);
Scene scene = new Scene(root, 2500, 1350);
primaryStage.setTitle("Generated Waveform");
primaryStage.setScene(scene);
primaryStage.show();
}
catch (FileNotFoundException ex){ex.printStackTrace();}
catch (IOException ex){ex.printStackTrace();}
}
public static short calculateAmpValue(byte byte1, byte byte2) {
ByteBuffer bb = ByteBuffer.allocate(2);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.put(byte1);
bb.put(byte2);
short ampVal = bb.getShort(0);
return ampVal;
}
public static void main(String[] args) {
Application.launch(args);
}
}
最佳答案
如果我想使用JavaFX绘制实时图表,则可能会假设我正在使用AnimationTimer进行绘制。它以60 fps的速度运行。因此,绘制的任何内容都将反射(reflect)该时间段内所做的更改。如果音频为44100 fps,则每个动画周期内有735个音频数据点。不过,我不清楚您正在尝试什么。您是否要编写与示波器等效的东西?
关于javafx - 使用Java实时生成音频波形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60768352/