Я пытаюсь сгенерировать звуковую форму волны, читая существующий WAV-файл, который обновляется при воспроизведении музыки c в режиме реального времени. Например, если песня воспроизводится, я хочу, чтобы форма волны непрерывно генерировалась по ходу песни. До сих пор мне удавалось читать данные из файла .wav и генерировать сигнал STATI C, используя javafx для примерно первых 2500 сэмплов песни. Я сравнил форму волны с тем, как она выглядит в смелости, и она очень хорошо ей соответствует. Вот как это выглядит:
![Generated Waveform using javafx](https://i.stack.imgur.com/z11YO.png)
Однако я не совсем понимаю, как заставить генерацию сигнала генерироваться не только статически для конкретного окна, но и генерировать постоянно обновляемый сигнал на протяжении всей песни. Я изучал графики в реальном времени и использовал ScheduledExecutorService, но я не могу заставить линейный график рисовать новую точку быстрее, чем раз в секунду, не вызывая проблем. Есть ли другой способ, которым я должен go сделать это? Я потратил много времени на это и не хочу сейчас сдаваться. Я приложил свой код ниже, посмотрите. Спасибо.
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);
}
}