Я работаю над проектом, который будет изменять яркость подсветки клавиатуры с помощью сигнала ШИМ в соответствии с уровнем выходного звука. Проблема в том, что мне нужен выходной поток в реальном времени. До сих пор я использовал пакет javax.sound.sampled, и мне так и не удалось получить аудиовыход. Однако, что я сделал, так это использовал targetDataLine и sourceDataLine, которые не похожи на go, хотя я все еще пытаюсь. Мне нужен провайдер аудиопотока, который мое java приложение может «услышать» и обработать. До сих пор я просмотрел много уроков, видео, постов, некоторые статьи (например, эту: https://cr.openjdk.java.net/~iris/se/12/latestSpec/api/java.desktop/javax/sound/sampled/class-use/Mixer.Info.html) и c. но без результатов. Кто-нибудь делал это раньше? Или есть библиотека, отличная от выборочной? Буду признателен за любую помощь.
Я получаю ошибку для каждого отдельного формата:
java.lang.IllegalArgumentException: Line unsupported: interface TargetDataLine supporting format PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian
at com.sun.media.sound.DirectAudioDevice.getLine(Unknown Source)
at javax.sound.sampled.AudioSystem.getTargetDataLine(Unknown Source)
Используемый код:
package audio;
import javax.sound.sampled.*;
public class App1 {
public static String getWord(String arr) {
int i = 0;
for(; i < arr.length(); i++) {
if (arr.charAt(i) == ' ')
break;
}
return arr.substring(0,i);
}
public static void wait(int ms) {
try{
Thread.sleep(ms);
}
catch(InterruptedException ex){
Thread.currentThread().interrupt();
}
}
public static AudioFormat getAudioFormat(){
float sampleRate = 44100;
//8000,11025,16000,22050,44100
int sampleSizeInBits = 16;
//8,16
int channels = 1;
//1,2
boolean signed = true;
//true,false
boolean bigEndian = false;
//true,false
//return new AudioFormat(Encoding.PCM_SIGNED, sampleRate, 16, 1, 2, sampleRate, false);
return new AudioFormat(sampleRate,
sampleSizeInBits,
channels,
signed,
bigEndian);
}
public static void main(String [] args) {
try {
//-----DECLARATIONS-----
TargetDataLine targetDataLine = null;
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
Mixer.Info m = null;
String expectedMixer = "Speakers";
//-----MIXER FINDER-----
System.out.println("Number of mixers: " + mixers.length);
for(int i = 0; i < mixers.length; i++) {
System.out.println(getWord(mixers[i].getName()));
if(getWord(mixers[i].getName()).compareTo(expectedMixer) == 0){
m = mixers[i];
}
}
if(m==null) throw new Exception("No such mixer found: " + expectedMixer);
else System.out.println('\n'+"Device choosen: "+m.getName());
//-----LINE TESTER-----
boolean v = false, showError = true; // show error or keep trying several times
int tries = 3, i = 0;
while(v==false && i++ < tries){
try {
//sourceDataLine = AudioSystem.getTargetDataLine(getAudioFormat(), m);
targetDataLine = AudioSystem.getTargetDataLine(getAudioFormat(), m);
targetDataLine.open(getAudioFormat());
v=true;
//System.out.println("Success!");
} catch (IllegalArgumentException e){
if (showError) {
v = true;
e.printStackTrace();
}
else {
System.out.println("Error! Retrying... "+i+'/'+tries);
v = false;
}
wait(2000);
}
}
if(i-1==tries)
//System.out.println("No success :(");
throw new Exception("No success :(");
else
if(v==false)
System.out.println("SourceData line found and accepted !");
//-----SIGNAL PROCESSING-----
//nothing here because the rest isn't working
} catch(Exception e) { e.printStackTrace();}
}
}
В последнее время я искал для некоторого фрагмента кода для обнаружения доступных форматов, и я сделал что-то между моим кодом и кодом edoloughlin :
package audio;
import javax.sound.sampled.*;
public class App2 {
public static String getWord(String arr) {
int i = 0;
for(; i < arr.length(); i++) {
if (arr.charAt(i) == ' ')
break;
}
return arr.substring(0,i);
}
public static void wait(int ms) {
try{
Thread.sleep(ms);
}
catch(InterruptedException ex){
Thread.currentThread().interrupt();
}
}
public static AudioFormat getAudioFormat(){
float sampleRate = 44100;
//8000,11025,16000,22050,44100
int sampleSizeInBits = 16;
//8,16
int channels = 1;
//1,2
boolean signed = true;
//true,false
boolean bigEndian = false;
//true,false
//return new AudioFormat(Encoding.PCM_SIGNED, sampleRate, 16, 1, 2, sampleRate, false);
return new AudioFormat(sampleRate,
sampleSizeInBits,
channels,
signed,
bigEndian);
}
public static void main(String [] args) {
try {
String expectedMixer = "Speakers";
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
Mixer.Info m = null;
for(int i = 0; i < mixers.length; i++) {
if(getWord(mixers[i].getName()).compareTo(expectedMixer) == 0){
m = mixers[i];
}
}
int sampleRates[] = { 8000, 11025, 16000, 22050, 44100 };
int channels[] = { 1, 2 };
int bytesPerSample[] = { 1, 2 };
boolean signature[] = {true, false};
AudioFormat format;
DataLine.Info lineInfo;
//for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) {
for (int a = 0; a < sampleRates.length; a++) {
for (int b = 0; b < channels.length; b++) {
for (int c = 0; c < bytesPerSample.length; c++) {
for(int d = 0; d < signature.length; d++) {
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
(float)sampleRates[a], 8 * bytesPerSample[c], channels[b], bytesPerSample[c],
(float)sampleRates[a], signature[d]);
lineInfo = new DataLine.Info(/*dataLineClass*/TargetDataLine.class, format);
if (AudioSystem.isLineSupported(lineInfo)) {
/*
* TODO: To perform an exhaustive search on supported lines, we should open
* TODO: each Mixer and get the supported lines. Do this if this approach
* TODO: doesn't give decent results. For the moment, we just work with whatever
* TODO: the unopened mixers tell us.
*/
if (AudioSystem.getMixer(/*mixerInfo*/m).isLineSupported(lineInfo)) {
//formats.add(format);
System.out.println(format);
}
}
}
}
}
}
//}
}catch(Exception e) {e.printStackTrace();}
}
}
Как показано выше, я использовал много комбинаций форматов, но в консоли ничего не распечатывается. Интересно, поддерживает ли моя система / java приложение такую задачу? Если нет, есть ли способ достичь цели? (читать вывод в режиме реального времени)