tl; dr Для будущих читателей запись звука в реальном времени невозможна (на данный момент) с Java или С#. Используйте С++, поскольку он предоставляет множество аудио файлов api.
Моя цель - получить текущий звук, воспроизводимый на Windows-машине, и проанализировать звук так же, как графический аудио визуализатор (получить свойство громкости и Hz (базовый и высокий)). Когда я говорю о текущем звуке, я имею в виду, если бы кто-то играл в видео Youtube или Spotify, и эта программа будет читать этот аудиовыход. У меня нет намерения играть в звук, но фиксировать его в режиме реального времени и визуализировать.
При попытке сделать это я прочитал, как построить отображение звуковых сигналов, и затрагивает, как преобразовать аудиофайл в массив байтов (строка). Это не помогает, потому что он не получит текущий звук. Я также прочитал, как захватить аудио, а также этот java доступ к звуковому руководству, ни один из них не отвечает на мой вопрос, потому что они оба требуют, чтобы файл песни был загружен.
Я просто не понимаю этого. Я совершенно незнакома, и любая помощь будет оценена.
Изменить: я немного поглядел вокруг, а второй ответ из этого источника привел меня к выводу, что: я мог бы найти все аудиоустройства, посмотрите, какой из них производит звук. Я не знаю, что делать после этого.
Изменить 2 (снова отредактировано): от эксперимента и осмотра, я написал этот код ниже. Я думаю, что это приводит меня в том направлении, в котором я хочу, но я не знаю, как его закончить.
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
for (Mixer.Info mixerInfo : mixers) {
Mixer mixer = AudioSystem.getMixer(mixerInfo);
try {
mixer.open();
Line.Info[] lines = mixer.getTargetLineInfo();
for (Line.Info linfo : lines) {
Line line = AudioSystem.getLine(linfo);
//here I'm opening the line, but I don't know how to grab data
line.open();
}
} catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Я использовал этот источник: Проверка уровня аудиовоспроизведения в строке микшера, но я не хочу проверять все строки, которые воспроизводят громкость, Мне просто нужен микшер по умолчанию для пользователей, получите эту Линию и сможете анализировать данные.
Изменить 3: Я пробовал:
//creating a format for getting sound
float sampleRate = 8000;
int sampleSizeInBits = 16;
int channels = 2;
boolean signed = true;
boolean bigEndian = true;
AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits, channels,
signed, bigEndian);
//creating a line based off of the format
DataLine.Info info = new DataLine.Info( TargetDataLine.class, format);
TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
//opening and starting that line
line.open(format);
line.start();
while (conditionIsTrue){
//here, I don't know what to put as the parameters.
//Had I known, I don't know how I would get to analyze the data
line.read();
}
Я думаю, что я на правильном пути, используя код выше, но я не знаю, как извлечь звук и найти bpm, base, highble и т.д.
Редактировать 4: Это было интересно прочитать: Обработка звука с низкой задержкой в режиме реального времени в Java. Это не касается того, какие классы и как реализовать на самом деле, но дает некоторое представление.
Изменить 5: @AndrewThompson Используя этот фрагмент кода, основанный на вашей ссылке, я смог выполнить итерацию по доступным исходным и целевым строкам.
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
for (Mixer.Info mixerInfo : mixers) {
Mixer mixer = AudioSystem.getMixer(mixerInfo);
try {
mixer.open();
Line.Info[] sourceLines = mixer.getSourceLineInfo();
Line.Info[] targetLine = mixer.getTargetLineInfo();
for (Line.Info sourceLinfo : sourceLines) {
System.out.println(sourceLinfo );
}
for (Line.Info targetLinefo : targetLine) {
System.out.println(targetLinefo);
}
} catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Результат выглядит следующим образом:
interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes
interface Clip supporting 8 audio formats, and buffers of at least 32 bytes
interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes
interface Clip supporting 8 audio formats, and buffers of at least 32 bytes
interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes
interface Clip supporting 8 audio formats, and buffers of at least 32 bytes
HEADPHONE target port
SPEAKER target port
Затем я создал метод, который получает уровни звука всех строк, которые выглядят следующим образом:
private static void getVolumeOfAllLines() {
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
for (Mixer.Info mixerInfo : mixers) {
Mixer mixer = AudioSystem.getMixer(mixerInfo);
try {
mixer.open();
Line.Info[] lines = mixer.getSourceLineInfo();
for (Line.Info linfo : lines) {
DataLine line = (DataLine)AudioSystem.getLine(linfo);
if(line != null)
System.out.println(line.getLevel());
}
} catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
- позволяет найти текущую строку, воспроизводящую звук, указывая на более высокий уровень громкости. Это возвращает:
-1.0
-1.0
-1.0
-1.0
-1.0
-1.0
Нет прогресса.
Новый код:
private static void debug(){
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
for (Mixer.Info mixerInfo : mixers) {
Mixer mixer = AudioSystem.getMixer(mixerInfo);
try {
mixer.open();
Line.Info[] lines = mixer.getTargetLineInfo();
AudioFormat format = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
44100,
16, 2, 4,
44100, false);
AudioFormat[] tdl = AudioSystem.getTargetFormats(AudioFormat.Encoding.PCM_SIGNED, format);
for (Line.Info linfo : lines) {
//Line line = AudioSystem.getLine(linfo);
TargetDataLine line = null;
DataLine.Info info = new DataLine.Info(TargetDataLine.class,
format); // format is an AudioFormat object
if (!AudioSystem.isLineSupported(info))
{
System.out.println("line not supported:" + line );
}
try
{
line = (TargetDataLine) AudioSystem.getLine(info); //error
line.open(format);
System.out.println("line opened:" + line);
line.start();
byte[] buffer = new byte[1024];
int ii = 0;
int numBytesRead = 0;
while (ii++ < 100) {
// Read the next chunk of data from the TargetDataLine.
numBytesRead = line.read(buffer, 0, buffer.length);
System.out.println("\nnumBytesRead:" + numBytesRead);
if (numBytesRead == 0) continue;
// following is a quickie test to see if content is only 0 vals
// present in the data that was read.
for (int i = 0; i < 16; i++)
{
if (buffer[i] != 0)
System.out.print(".");
else
System.out.print("0");
}
}
} catch (LineUnavailableException ex) {
ex.printStackTrace();
//...
}
}
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
}