Skip to content

Micro Blog

mhroth edited this page Sep 13, 2010 · 32 revisions

Transparent Thread Registration

Friday, May 15, 2009 by mhroth

This whole silliness about thread registration is a burden to programmers. Sorry about exposing it (via registerThread()) yesterday, but at least there was a solution that worked. Based on feedback from Almer Thie (see his modular synth project here), I have removed the requirement to manually register threads. Because I don’t have the ability to test with multiple drivers, I am not entirely sure that the automatic thread registration works perfectly. I look forward to your feedback.


Javadocs!

Thursday, May 14, 2009 by mhroth

Finally I figured out how to post javadocs. Find them here. They are also in the repository here. They aren’t complete, but it is a start and will hopefully provide you with a clearer overview of the package.


Towards a beta Tag

Thursday, May 14, 2009 by mhroth

The beginnings of a new version of JAsioHost have been pushed today. See Tags for a more complete description. This release should make the library smaller and easier to understand. All known bugs have also been fixed. The ExampleHost has been given a GUI allowing the easy selection and testing of registered ASIO drivers.


alpha Tag

Tuesday, May 12, 2009 by mhroth

There is now an alpha release which designates the current state of things. As long as only one driver is ever loaded and only accessed from one thread, then everything works great ;-) A beta release is imminent and will fix these issues, as well as introducing some refactorings designed to simplify the API and be conceptually easier to understand.


Driver Access from Multiple Threads

Friday, April 24, 2009 by mhroth

There is a known issue of loading and accessing the AsioDriver from multiple threads. Several people have tried (as might be typically expected) to create a GUI for loading the driver (Thread 1), and then starting the driver in another thread (e.g., the audio thread, Thread 2). The second thread might then complain (i.e., crash) about the driver no longer being found. The reason for this is (this explanation may not be correct because I am fuzzy on how/if threads maintain separate memory spaces in native code) that there is a critical global variable in the native code (bad programming practice I know, but the issue is not a clear as it may seem) which seems to not be accessible to all threads. The workaround for this issue at the moment is simply to do all manipulations of the JAsioHost library from the same thread. I will work on a most robust solution to this problem. Sorry about the pain in the ass.


AsioChannelInfo.read()/write() Added

Wednesday, April 22, 2009 by mhroth

Two methods, AsioChannelInfo.read(float[]) and AsioChannelInfo.write(float[]), have been added in order to allow hosts to conveniently read from and write to buffers using float arrays. The sample type of the channel is accounted for and the host does not need to take this into account. The methods were added because most hosts use float as the internal sample representation. If you are using some other format, get a reference to the base ByteBuffer and manipulate it directly.


asReadOnlyBuffer() order Bug Fixed

Tuesday, April 21, 2009 by mhroth

All input ByteBuffer are read-only buffers, as generated by ByteBuffer.asReadyOnlyBuffer(). You shouldn’t be writing to an input buffer anyway. JAsioHost attempts to abstract the endian-ness of the buffer from the user by setting the byte order according to the sample type of the channel. However, as it turns out, calling asReadOnlyBuffer() resets the ByteOrder on the buffer to the default of ByteOrder.BIG_ENDIAN. If the channel is actually little-endian, then this mismatch causes the inputs to sound like noise. The issue was resolved simply by creating the read-only buffer first, and then setting the byte order on it, instead of the other way around, which was being done originally.

Thanks to Steve Taylor of toot.org for identifying this issue.


Updates and More Stability

Saturday, April 18, 2009 by mhroth

A number of updates were integrated yesterday, including:

  • Add support for systemTime and samplePosition to bufferSwitch()
  • Add support for kAsioBufferSizeChange to asioMessage() in native code
  • Remove synchronization requirement from bufferSwitch(). Should allow openControlPanel() to open, while running, without preventing bufferSwitch() from executing
  • Refactor AsioChannelInfo architecture such that objects referring to the same channel return consistent and current information
  • Get rid of sampleTypes native array in global variable
  • Make AsioDriverInfo available through AsioDriver
  • Reduce AsioChannelInfo.toString() to one line

And what does this buy you? To quote a power user, “occasional glitches are gone.” Sounds like a win to me! ;-)

Currently there are issues with the input buffers. They don’t seem to properly report the input. “I’m on it!Update: Inputs seem to work fine with ASIO4ALL, but maybe not with other drivers.


M-Audio Delta Driver Working

Wednesday, April 15, 2009 by mhroth

With many thanks to Steve Taylor of toot.org, ASIOOutputReady has been integrated into bufferSwitch, and now the M-Audio Delta ASIO driver is now working as well. There is still plenty of refactoring work to be done, as experience with the current API has shown. But strong progress is being made in supporting more drivers.

M-Audio Delta Control Panel Screenshot


Configuring ASIO4ALL

Tuesday, April 7, 2009 by mhroth

Here is a screenshot of the ASIO4ALL configuration panel which I use during development. Of course, your underlying audio hardware may be different and this could affect your performance. It may be necessary to play around with the settings in order to find those that work best for you. For the record, I develop on a current generation (unibody) MacBook, bootcamped to Windows XP, SP 3.

ASIO4ALL Configuration Screenshot


Switch to NIO

Monday, April 6, 2009 by mhroth

I have switched over to the use of NIO ByteBuffer. I wasn’t familiar with them before, and thus did not start with them. However, after stumbling across them in the JNI documentation (e.g., NewDirectByteBuffer), I realised that I could use them to create a Java array from a native one, with the bonus of not having to copy between a Java temporary array and the native buffers. Furthermore, using ByteBuffer allows for endian-ness to be abstracted. This allows them to be manipulated in Java without having to worry what the sample endian-ness is, or what the endian-ness of the native system is. Finally, ByteBuffers can be written to “per sample”, or updated in bulk.

The upshot of all of this is that the AsioDriverListener.bufferSwtich() has a new signature of void bufferSwitch(Set<AsioChannelInfo> activeChannels). The current buffer for each channel can then be retrieved with getByteBuffer(), which has the current position already reset to zero. If desired, the ByteBuffer can be viewed AsIntBuffer(), for instance, allowing integers (i.e., samples represented as integers in 32 bits) to be written or read in bulk.


Quite Stable…

Friday, April 3, 2009 by mhroth

JAsioHost is becoming more usable! It works wonderfully with ASIO4ALL, though I have yet to hear of it working with other ASIO drivers. I’m working on this with the help of beta testers. I am also happy to report that stability problems in the past have been mitigated and as long as the usage guidelines are followed, there is nothing to worry about.


A Working Example!

Monday, March 30, 2009 by mhroth

Well! ASIO is working! All of my testing is done with ASIO4ALL v2.9 and I am shocked (no, really) to report that the minimum latency (64 samples @ 44100 samples per second) is possible! I was convinced that a lower latency than the Java Sound API would be possible (> 1024 samples, in my experience), but 64 samples seems none other than impressive, considering the JNI barrier! Granted, the test case only outputs a sine wave, but at 64 samples you have to be quick.

As always, get the latest versions of JAsioHost.jar and jasiohost.dll. There is an com.synthbot.jasiohost.ExampleHost which loads the first driver reported by the system, and outputs a 440Hz sine wave for two seconds. While at the moment is it probably still necessary to understand the Java source in order to use the library, try it out! ASIO access from Java is a reality! (Remember, API changes are likely.)


The State of Things

Friday, March 27, 2009 by mhroth

The current state of the code is as follows. Much of the work has been already done (at least conceptually), except that there is one annoying problem. When running, ASIO drivers notify the host that new input and output buffers are available via a callback, running in a thread owned by the driver. This is all well and good, and it means that this native thread must interact with the JVM and call Java methods. For whatever reason this doesn’t seem to be working at the moment (i.e., it will crash your machine, not just the JVM), and I am in the process of debugging it. I thought that I had solved the problem when I switched from AttachCurrentThread (which was blocking) to AttachCurrentThreadAsDaemon, which seems to work fine. But even though the latter function returns a seemingly valid JNIEnv *, which which I can FindClass or GetMethodID, calling, for instance, CallStaticVoidMethod has horrible effects. Maybe I am missing an exception somewhere…


Sort of Usable

Friday, March 27, 2009 by mhroth

A somewhat useful library is now available. There are no guarantees of how well it will work for you, and the API will probably change as well. As usual, you will need to place JAsioHost.jar into your Java classpath. jasiohost.dll should be placed in C:\WINDOWS\system32, or any other location where Java can find it. After that you, can do one of several interesting things. import com.synthbot.JAsioHost, which has only static methods.

  • List<String> getDriverNames() returns a list of the names of all ASIO drivers registered with the system.
  • String getCurrentDriverName() returns the name of the currently loaded driver.A zero-length string is returns if no driver is loaded.
  • int getCurrentDriverIndex() returns the index in the getDriverNames List corresponding to the currently loaded driver. Returns -1 if no driver is loaded.
  • AsioDriver getAsioDriver(String name) returns a loaded and instantiated AsioDriver object, representing the selected driver.

The last, and certainly not least, method is shutdownAndUnloadDriver(). WARNING: No matter what you do, call this method before ending your program. If the JVM terminates (for whatever reason), and the driver is still loaded or running, you run a significant risk of enjoying a BSOD and possibly corrupted files. You have been warned.