Created
February 12, 2012 04:06
-
-
Save mgodave/1806160 to your computer and use it in GitHub Desktop.
portaudio paex_record.c java jna port
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by IntelliJ IDEA. | |
* User: drusek | |
* Date: 2/10/12 | |
* Time: 12:40 PM | |
* To change this template use File | Settings | File Templates. | |
*/ | |
import com.sun.jna.*; | |
import com.sun.jna.ptr.PointerByReference; | |
import java.io.DataOutputStream; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.nio.ByteBuffer; | |
import java.nio.FloatBuffer; | |
import java.util.Arrays; | |
import java.util.concurrent.*; | |
/** | |
* Simple example of JNA interface mapping and usage. | |
*/ | |
public class HelloWorld { | |
// This is the standard, stable way of mapping, which supports extensive | |
// customization and mapping of Java to native types. | |
public interface PortAudio extends Library { | |
PortAudio INSTANCE = (PortAudio) | |
Native.loadLibrary("portaudio", PortAudio.class); | |
public static final NativeLong paFloat32 = new NativeLong(0x00000001); | |
public static final NativeLong paInt16 = new NativeLong(0x00000008); | |
public static final NativeLong paClipOff = new NativeLong(0x00000001); | |
interface PaStreamCallback extends Callback { | |
public static enum PaStreamCallbackResult { | |
CONTINUE(0), | |
COMPLETE(1), | |
ABORT(2); | |
private final int value; | |
PaStreamCallbackResult(int value) { | |
this.value = value; | |
} | |
} | |
int invoke(Pointer inputBuffer, Pointer outputBuffer, | |
NativeLong frameCount, | |
Pointer timeInfo, | |
NativeLong statusFlags, | |
Pointer userData); | |
} | |
public static class PaStreamParameters extends Structure { | |
public int device; | |
public int channelCount; | |
public NativeLong paSampleFormat; | |
public double suggestedLatency; | |
public Pointer hostApiSpecificStreamInfo; | |
} | |
public static class PaDeviceInfo extends Structure { | |
public int structVersion; | |
public String name; | |
public int hostApi; | |
public int maxInputChannels; | |
public int maxOutputChannels; | |
double defaultLowInputLatency; | |
double defaultLowOutputLatency; | |
double defaultHighInputLatency; | |
double defaultHighOutputLatency; | |
double defauleSampleRate; | |
} | |
void Pa_Initialize(); | |
void Pa_Terminate(); | |
int Pa_OpenStream(PointerByReference stream, | |
PaStreamParameters inputParameters, | |
PaStreamParameters outputParameters, | |
double sampleRate, | |
NativeLong framesPerBuffer, | |
NativeLong streamFlags, | |
PaStreamCallback callback, | |
Pointer userData); | |
int Pa_StartStream(Pointer stream); | |
int Pa_CloseStream(Pointer stream); | |
int Pa_IsStreamActive(Pointer stream); | |
PaDeviceInfo Pa_GetDeviceInfo(int index); | |
String Pa_GetErrorText(int errorCode); | |
int Pa_GetDefaultInputDevice(); | |
int Pa_GetDefaultOutputDevice(); | |
void Pa_Sleep(int ms); | |
int Pa_WriteStream(Pointer stream, Pointer sampleBlock, NativeLong frames); | |
int Pa_ReadStream(Pointer stream, Pointer buffer, NativeLong frames); | |
} | |
public static class Capture implements Runnable { | |
public class RecordCallback implements PortAudio.PaStreamCallback { | |
private long frameIndex = 0; | |
private int maxFrameIndex = 0; | |
private FloatBuffer recordedSamples; | |
private final int numChannels; | |
public RecordCallback(int numSeconds, int sampleRate, int numChannels) { | |
maxFrameIndex = numSeconds * sampleRate; | |
recordedSamples = FloatBuffer.allocate(maxFrameIndex * numChannels); | |
this.numChannels = numChannels; | |
} | |
public FloatBuffer getRecordedSamples() { | |
return recordedSamples; | |
} | |
public int invoke(Pointer inputBuffer, Pointer outputBuffer, NativeLong frameCount, Pointer timeInfo, NativeLong statusFlags, Pointer userData) { | |
final long framesLeft = maxFrameIndex - frameIndex; | |
long framesToCalc; | |
PaStreamCallbackResult finished; | |
final FloatBuffer readBuffer = inputBuffer.getByteBuffer(0, frameCount.intValue() * numChannels * Float.SIZE).asFloatBuffer(); | |
System.out.println("framesLeft: " + framesLeft + " frameCount: " + frameCount.longValue()); | |
if (framesLeft < frameCount.longValue()) { | |
framesToCalc = framesLeft; | |
finished = PaStreamCallbackResult.COMPLETE; | |
} else { | |
framesToCalc = frameCount.longValue(); | |
finished = PaStreamCallbackResult.CONTINUE; | |
} | |
if (inputBuffer == Pointer.NULL) { | |
for (int i = 0; i < framesToCalc; ++i) { | |
recordedSamples.put(0.0f); | |
if (numChannels == 2) { | |
recordedSamples.put(0); | |
} | |
} | |
} else { | |
for (int i = 0; i < framesToCalc; ++i) { | |
recordedSamples.put(readBuffer.get()); | |
if (numChannels == 2) { | |
recordedSamples.put(readBuffer.get()); | |
} | |
} | |
} | |
frameIndex += framesToCalc; | |
return finished.value; | |
} | |
} | |
public class PlaybackCallback implements PortAudio.PaStreamCallback { | |
private long frameIndex = 0; | |
private int maxFrameIndex = 0; | |
private final FloatBuffer recordedSamples; | |
private final int numChannels; | |
public PlaybackCallback(int numSeconds, int sampleRate, int numChannels, FloatBuffer recordedSamples) { | |
this.recordedSamples = recordedSamples; | |
maxFrameIndex = numSeconds * sampleRate; | |
this.numChannels = numChannels; | |
} | |
public int invoke(Pointer inputBuffer, Pointer outputBuffer, NativeLong frameCount, Pointer timeInfo, NativeLong statusFlags, Pointer userData) { | |
final long framesLeft = maxFrameIndex - frameIndex; | |
final FloatBuffer writeBuffer = outputBuffer.getByteBuffer(0, frameCount.intValue() * numChannels * Float.SIZE).asFloatBuffer(); | |
PaStreamCallbackResult finished; | |
if (framesLeft < frameCount.longValue()) { | |
int i; | |
for (i = 0; i < framesLeft; ++i) { | |
writeBuffer.put(recordedSamples.get()); | |
if (numChannels == 2) { | |
writeBuffer.put(recordedSamples.get()); | |
} | |
} | |
for (; i < frameCount.longValue(); ++i) { | |
writeBuffer.put(0.0f); | |
if (numChannels == 2) { | |
writeBuffer.put(0.0f); | |
} | |
} | |
frameIndex += framesLeft; | |
finished = PaStreamCallbackResult.COMPLETE; | |
} else { | |
for (int i = 0; i < frameCount.longValue(); ++i) { | |
writeBuffer.put(recordedSamples.get()); | |
if (numChannels == 2) { | |
writeBuffer.put(recordedSamples.get()); | |
} | |
} | |
frameIndex += frameCount.longValue(); | |
finished = PaStreamCallbackResult.CONTINUE; | |
} | |
return finished.value; | |
} | |
} | |
public static final int SAMPLE_RATE = 44100; | |
public static final int NUM_CHANNELS = 2; | |
public static final int NUM_SECONDS = 5; | |
public static final NativeLong FRAMES_PER_BUFFER = new NativeLong(512); | |
public static final NativeLong SAMPLE_TYPE = PortAudio.paFloat32; | |
public void run() { | |
final PortAudio.PaStreamParameters inputParameters = new PortAudio.PaStreamParameters(); | |
inputParameters.device = PortAudio.INSTANCE.Pa_GetDefaultInputDevice(); | |
inputParameters.channelCount = NUM_CHANNELS; | |
inputParameters.paSampleFormat = SAMPLE_TYPE; | |
inputParameters.hostApiSpecificStreamInfo = Pointer.NULL; | |
inputParameters.suggestedLatency = PortAudio.INSTANCE.Pa_GetDeviceInfo(inputParameters.device).defaultLowInputLatency; | |
final RecordCallback recordCallback = new RecordCallback(NUM_SECONDS, SAMPLE_RATE, NUM_CHANNELS); | |
final PointerByReference inputStreamReference = new PointerByReference(); | |
int err = PortAudio.INSTANCE.Pa_OpenStream( | |
inputStreamReference, | |
inputParameters, | |
null, | |
SAMPLE_RATE, | |
FRAMES_PER_BUFFER, | |
PortAudio.paClipOff, | |
recordCallback, null); | |
System.out.println(PortAudio.INSTANCE.Pa_GetErrorText(err)); | |
err = PortAudio.INSTANCE.Pa_StartStream(inputStreamReference.getValue()); | |
System.out.println(PortAudio.INSTANCE.Pa_GetErrorText(err)); | |
while ((err = PortAudio.INSTANCE.Pa_IsStreamActive(inputStreamReference.getValue())) == 1) { | |
PortAudio.INSTANCE.Pa_Sleep(1000); | |
} | |
// try { | |
// final FileOutputStream outputStream = new FileOutputStream("/home/drusek/recorded.raw"); | |
// final DataOutputStream dataOutputStream = new DataOutputStream(outputStream); | |
// for (final float sample : recordCallback.getRecordedSamples().array()) { | |
// dataOutputStream.writeFloat(sample); | |
// } | |
// } catch (FileNotFoundException e) { | |
// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. | |
// } catch (IOException e) { | |
// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. | |
// } | |
err = PortAudio.INSTANCE.Pa_CloseStream(inputStreamReference.getValue()); | |
System.out.println(PortAudio.INSTANCE.Pa_GetErrorText(err)); | |
final PortAudio.PaStreamParameters outputParameters = new PortAudio.PaStreamParameters(); | |
outputParameters.device = PortAudio.INSTANCE.Pa_GetDefaultOutputDevice(); | |
outputParameters.channelCount = NUM_CHANNELS; | |
outputParameters.paSampleFormat = SAMPLE_TYPE; | |
outputParameters.hostApiSpecificStreamInfo = Pointer.NULL; | |
outputParameters.suggestedLatency = PortAudio.INSTANCE.Pa_GetDeviceInfo(outputParameters.device).defaultLowOutputLatency; | |
recordCallback.getRecordedSamples().rewind(); | |
final PlaybackCallback playbackCallback = new PlaybackCallback(NUM_SECONDS, SAMPLE_RATE, NUM_CHANNELS, recordCallback.getRecordedSamples()); | |
final PointerByReference outputStreamReference = new PointerByReference(); | |
err = PortAudio.INSTANCE.Pa_OpenStream( | |
outputStreamReference, | |
null, | |
outputParameters, | |
SAMPLE_RATE, | |
FRAMES_PER_BUFFER, | |
PortAudio.paClipOff, | |
playbackCallback, null); | |
System.out.println(PortAudio.INSTANCE.Pa_GetErrorText(err)); | |
err = PortAudio.INSTANCE.Pa_StartStream(outputStreamReference.getValue()); | |
System.out.println(PortAudio.INSTANCE.Pa_GetErrorText(err)); | |
while ((err = PortAudio.INSTANCE.Pa_IsStreamActive(outputStreamReference.getValue())) == 1) { | |
PortAudio.INSTANCE.Pa_Sleep(1000); | |
} | |
err = PortAudio.INSTANCE.Pa_CloseStream(outputStreamReference.getValue()); | |
System.out.println(PortAudio.INSTANCE.Pa_GetErrorText(err)); | |
} | |
} | |
public static void main(String[] args) throws ExecutionException { | |
PortAudio.INSTANCE.Pa_Initialize(); | |
try { | |
final ExecutorService threadPool = Executors.newCachedThreadPool(); | |
final Future captureFuture = threadPool.submit(new Capture()); | |
captureFuture.get(); | |
threadPool.shutdown(); | |
threadPool.awaitTermination(10, TimeUnit.MINUTES); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} finally { | |
PortAudio.INSTANCE.Pa_Terminate(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment