Portaudio записывает странную искаженную форму сигнала при записи устройств jack и FirefoxJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Portaudio записывает странную искаженную форму сигнала при записи устройств jack и Firefox

Сообщение Anonymous »

Я не понимаю, почему это происходит, поэтому прихожу сюда за любой помощью, которую могу получить. По сути, при записи любого устройства, такого как Firefox, в моем приложении оно получается искаженным. Но он прекрасно работает при записи в WAV-файл в прилагаемом демонстрационном коде или при записи с моего микрофона. Полный исходный код моего приложения находится по адресу https://github.com/1vers1on/bolt.
На этом изображении показаны импульсы при записи Firefox.
Изображение

Это форма волны при записи Firefox, когда ничего не происходит. играет.
Изображение

Эта форма сигнала отображается при записи с моего микрофона. Совершенно нормально, как и ожидалось.
Изображение

Соответствующими файлами в моем исходном коде являются "Bolt.java", "PortAudioInputStream.java", "InputThread.java", а также все папки jni и исходный код c.
Следующий демонстрационный код полностью работает со всеми устройствами ввода, как и ожидалось.
package net.ellie.bolt;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.List;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;

import net.ellie.bolt.jni.portaudio.AudioInputStream;
import net.ellie.bolt.jni.portaudio.PortAudioJNI;

public class Main {
public static void main(String[] args) {
// try {
// Bolt.run();
// } catch (Exception e) {
// e.printStackTrace();
// }

final int durationSeconds = 5;
final int channelsPreferred = 2;
final double sampleRatePreferred = 48000.0;

PortAudioJNI pa = new PortAudioJNI();
int init = pa.initialize();
if (init != 0) {
System.err.println("Failed to initialize PortAudio (code=" + init + ")");
return;
}

try {
List devices = pa.enumerateDevices();
if (devices == null || devices.isEmpty()) {
System.err.println("No audio devices found");
return;
}

for (PortAudioJNI.DeviceInfo d : devices) {
System.out.printf("Device %d: %s (in: %d ch, out: %d ch, default SR: %.1f)\n",
d.index(), d.name(), d.maxInputChannels(), d.maxOutputChannels(), d.defaultSampleRate());
}

PortAudioJNI.DeviceInfo device = devices.get(27);

int channels = Math.min(device.maxInputChannels(), channelsPreferred);
double sampleRate = sampleRatePreferred;

if (!pa.isFormatSupported(device.index(), channels, sampleRate)) {
channels = Math.max(1, Math.min(device.maxInputChannels(), 1));
sampleRate = device.defaultSampleRate() > 0 ? device.defaultSampleRate() : sampleRatePreferred;
}

long framesPerBuffer = 256;
AudioInputStream inputStream = pa.openInputStream(device.index(), channels, sampleRate, framesPerBuffer);

try (inputStream) {
inputStream.start();

int totalFrames = (int) (sampleRate * durationSeconds);
int bytesPerSample = 2;
int bytesPerFrame = bytesPerSample * channels;
byte[] data = new byte[totalFrames * bytesPerFrame];

int bytesCaptured = 0;
while (bytesCaptured < data.length) {
int remaining = data.length - bytesCaptured;
int toRead = Math.max(bytesPerFrame, Math.min(remaining, bytesPerFrame * 1024));
int read = inputStream.read(data, bytesCaptured, toRead);
if (read 1.0f)
f = 1.0f;
if (f < -1.0f)
f = -1.0f;
int s;
if (f >= 0) {
s = (int) Math.round(f * 32767.0);
} else {
s = (int) Math.round(f * 32768.0);
}
out[bi++] = (byte) (s & 0xFF);
out[bi++] = (byte) ((s >>> 8) & 0xFF);
}
return out;
}
}


Вот PortAudioInputSource.java
package net.ellie.bolt.input.sources.real;

import java.io.IOException;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.ellie.bolt.contexts.PortAudioContext;
import net.ellie.bolt.input.CloseableInputSource;
import net.ellie.bolt.jni.portaudio.AudioInputStream;
import net.ellie.bolt.jni.portaudio.PortAudioJNI;

public class PortAudioInputSource implements CloseableInputSource {
private final Logger logger = LoggerFactory.getLogger(PortAudioInputSource.class);
private volatile boolean running = true;
private AudioInputStream audioInputStream;
private final int sampleRate;
private final int channelCount;
private final int framesPerBuffer;
private byte[] byteBuffer; // re-used between reads to avoid allocations

public PortAudioInputSource(int deviceIndex, int channels, double sampleRate, long framesPerBuffer) {
PortAudioJNI pa = PortAudioContext.getInstance().getPortAudioJNI();

PortAudioJNI.DeviceInfo device = null;
List devices = pa.enumerateDevices();
for (PortAudioJNI.DeviceInfo d : devices) {
if (d.index() == deviceIndex) {
device = d;
break;
}
}

if (device == null) {
throw new RuntimeException("Device not found: " + deviceIndex);
}

int maxInputChannels = device.maxInputChannels();

int actualChannels = channels;
if (channels == 1 && maxInputChannels < 1) {
actualChannels = Math.max(1, maxInputChannels);
logger.warn("Device {} doesn't support {} channels, using {} channels instead",
device.name(), channels, actualChannels);
}

this.sampleRate = (int) sampleRate;
this.channelCount = Math.max(1, actualChannels);
this.framesPerBuffer = (int) Math.max(1, framesPerBuffer);

logger.info("Opening PortAudio input stream with deviceIndex={}, channels={} (requested: {}), sampleRate={}, framesPerBuffer={}",
deviceIndex, this.channelCount, channels, sampleRate, framesPerBuffer);

audioInputStream = PortAudioContext.getInstance().getPortAudioJNI()
.openInputStream(deviceIndex, this.channelCount, sampleRate, framesPerBuffer);

this.byteBuffer = new byte[this.framesPerBuffer * this.channelCount * 2];

audioInputStream.start();
}

@Override
public int read(float[] buffer, int offset, int length) throws InterruptedException, IOException {
if (!running || audioInputStream == null) {
return 0;
}

int bytesToRead = Math.min(byteBuffer.length, length * 2 * channelCount);
int bytesRead = audioInputStream.read(byteBuffer, 0, bytesToRead);
if (bytesRead = byteBuffer.length) break;

int lo = byteBuffer[bi++] & 0xFF;
int hi = byteBuffer[bi++];
int sample = (hi = 0 ? (sample / 32767.0f) : (sample / 32768.0f);
sum += f;
channelsRead++;
}

if (channelsRead > 0) {
buffer[offset + i] = sum / channelsRead;
} else {
buffer[offset + i] = 0;
}
}

return framesToCopy;
}

@Override
public int getSampleRate() {
return sampleRate;
}

@Override
public void stop() {
running = false;
if (audioInputStream != null) {
audioInputStream.stop();
audioInputStream.close();
audioInputStream = null;
}
}

@Override
public String getName() {
return "PortAudio Input Source";
}

@Override
public boolean isRunning() {
return running;
}

@Override
public boolean isComplex() {
return false;
}

@Override
public void close() {
stop();
}
}

Это файл InputThread.java
package net.ellie.bolt.input;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;

import net.ellie.bolt.config.Configuration;
import net.ellie.bolt.dsp.buffers.CircularFloatBuffer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class InputThread implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(InputThread.class);

private final CloseableInputSource inputSource;
private final AtomicBoolean running = new AtomicBoolean(false);
private final CircularFloatBuffer buffer;

// Throttling state
private final int complexFactor;
private final int sampleRate; // samples per second for one channel; effective rate accounts for complexFactor
private long nextReadDeadlineNanos = 0L;

private final float[] readBuffer;

private Thread localInputThread = null;

public InputThread(CloseableInputSource inputSource, int sampleRate) {
this.inputSource = inputSource;

this.complexFactor = inputSource.isComplex() ? 2 : 1;
this.sampleRate = sampleRate;

int bufferSize = Configuration.getFftSize() * 32 * complexFactor; // TODO: figure out the correct size
this.buffer = new CircularFloatBuffer(bufferSize);

this.readBuffer = new float[4 * 16384 * complexFactor]; // TODO: maybe increase the size
}

public void start() {
running.set(true);
localInputThread = new Thread(this, "InputThread-" + inputSource.getName());
localInputThread.start();
}

@Override
public void run() {
logger.info("InputThread for {} started", inputSource.getName());
try {
nextReadDeadlineNanos = System.nanoTime();
while (running.get()) {
long now = System.nanoTime();
long waitNanos = nextReadDeadlineNanos - now;
if (waitNanos > 0) {
long waitMillis = waitNanos / 1_000_000L;
int waitExtraNanos = (int)(waitNanos % 1_000_000L);
if (waitMillis > 0 || waitExtraNanos > 0) {
try {
Thread.sleep(waitMillis, waitExtraNanos);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
break;
}
}
}

int samplesRead = inputSource.read(readBuffer, 0, readBuffer.length);
if (samplesRead > 0) {
buffer.write(readBuffer, 0, samplesRead);

double secondsForChunk = (double) samplesRead / (double) (sampleRate * complexFactor);
long nanosForChunk = (long) (secondsForChunk * 1_000_000_000L);
nextReadDeadlineNanos = System.nanoTime() + nanosForChunk;
} else {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
nextReadDeadlineNanos = System.nanoTime() + 1_000_000L;
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (IOException e) {
e.printStackTrace();
} finally {
try { inputSource.close(); } catch (Exception ignored) {}
}
}

public void stop() {
running.set(false);
if (localInputThread != null) {
try {
localInputThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
inputSource.stop();
logger.info("InputThread for {} stopped", inputSource.getName());
}

public CircularFloatBuffer getBuffer() {
return buffer;
}
}


Подробнее здесь: https://stackoverflow.com/questions/798 ... devices-an
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»