JACK on OS X
JACK is a low-latency audio server, written for POSIX conformant operating systems such as GNU/Linux and Apple's OS X.
If you're doing serious audio work, JACK is a beautiful thing indeed. I had a problem getting it going on the MacBook. I didn't have any trouble with it on the iBook, so either JACK changed, or a recent OS X update changed things, or just the fact that the MacBook has both a line in and a microphone canged things.
This is the error I was getting:
$ jackd -d coreaudio
jackd 0.102.20
Copyright 2001-2005 Paul Davis and others.
jackd comes with ABSOLUTELY NO WARRANTY
This is free software, and you are welcome to redistribute it
under certain conditions; see the file COPYING for details
JACK compiled with POSIX SHM support.
loading driver ..
Default input and output devices are not the same !!
Cannot open default device
Cannot open the coreaudio driver
cannot load driver module coreaudio
no message buffer overruns
You can see the thread on LAU for more details, but the short answer is you need to create an aggregate device in the Audio MIDI Setup panel. Open it up and go to the Audio Devices tab. Then go to the Audio menu and choose Open Aggregate Device Editor. Add ye an aggregate device with all the inputs/outputs, and JACK will just work. Not only that, but it will have access to all the available inputs and outputs.
Posted in audio | no comments |
On Sequencers
I get the impression that most users of MIDI sequencers step record. At least, the writers of the sequencers pay little attention to live recording. For evidence, I cite the abundance of tracker sequencers available for Linux, and the three major sequencers for Linux (IMHO) which all fall short in the relatively simple task of accomodating people like me who prefer to record things live: Rosegarden, Muse, and Seq24.
Live recording is not complicated. You need a few basic features, and you need to make them accessible from the keyboard without touching the mouse. Here's an excellent UI model (that makes me drool):
And here's a list of those basic features:
- FF, REW, Stop, Play, Record
- Replace and overdub modes.
- Punch
- Loop
- Metronome
- Lead-in of 2, 1, or 0 measures. My old Roland JW-50 from 1992 did a great job with this. You had the option of no lead-in but you also had the option of key-triggered recording. That is, you press record, and the thing starts recording the moment you start playing. This is extremely useful.
- Track muting and solo
- 16 tracks
- Variable speed (percent of tempo) for slow and fast recording.
- Undo
That's it. Most sequencers have some or perhaps even most of these features, but leave out essential aspects such as no mousing, replace recording, no lead-in, and not crashing. Rosegarden goes a step further and makes the simple things that you take for granted difficult as well (but it does everything else under the sun and it's hard to justify not using it).
Seq24 is unique in its failure because it is oriented at realtime performance. Note that word, "performance". It could perhaps just as easily be good at realtime recording if it tried, and then in spite of its loop and pattern-based approach it would still be an excellent sequencer for us non-pattern junkies. (Sequence a Bach organ fugue in a tracker, I dare you.)
If I have the honor of speaking to someone who is writing or improving a sequencer, please consider the keyboardists and take my thoughts into consideration. Believe it or not, the lack of these basics will drive a keyboardist crazy just as fast as mousing will drive a CLI junkie crazy. Which is quite ironic as most step-recording Linux sequencer developers are probably CLI junkies.
VST 2.4 with Cygwin+MinGW32
I have been negligent in the Haas effect plugin that dilvie commissioned from me (ok, he didn't exactly commision it, it was more like a vague promise to make me almost famous). I got the thing working (mostly) but delivery fell flat on its face when my first attempt at compiling it on Windows with Visual Studio 6 apparently failed.
Well now that I have VMware I ran out of excuses to figure it out. I spent a couple hours trying to figure it out today and learned more than I wanted to know about DLLs, Cygwin, MinGW32, Visual Studio products, and VST.
A VST plugin is a DLL. I've learned that "DLL hell" refers not only to the user's point of view but the developer's as well.
I learned that Microsoft offers a limited "Visual C++ Express" that you can use to compile VSTs, but it involves tedious tweaking of a Visual C++ "solution". Even the solutions (project files) that come in the VST SDK don't work without tweaking on their own examples. No fun. Rather than doing that I decided to take the more intelligent (if longer) road and figure out how to do it with gcc.
I stumbled across Code::Blocks Studio which you can download bundled with MinGW (and thus skip the nightmare that is the MinGW download page), and which also can use your Microsoft compiler. I gave it a try for awhile, and although I was impressed I wasn't able to get it to make a VST DLL without major tweaks, and since IDE tweaking is not my thing I decided to fall back on vim+make in Cygwin.
By this time I had gleaned enough from Google to know two things: people have had success compiling VST plugins with mingw32 and they were terrible at explaining it. I hope to do a bit better. Let the explanation begin!
If you haven't already, then install Cygwin and be sure to select the various development packages, including gcc, anything that says mingw, and make.
First off, we need a project. I copied the files from the again sample source directory (again.cpp and again.h) into my fresh new again directory. Then with the help of various web sites I composed the following Makefile:
# Substitute your values here
VST=../vstsdk2.4
PLUGIN=again
#
CXXFLAGS=-I$(VST) -I$(VST)/public.sdk/source/vst2.x -DBUILDING_DLL -mno-cygwin
LDFLAGS=
DLLWRAP=dllwrap --target=i386-mingw32 -mno-cygwin
DLL=$(PLUGIN).dll
$(DLL): $(PLUGIN).o audioeffect.o audioeffectx.o vstplugmain.o
$(DLLWRAP) --driver-name c++ --def $(PLUGIN).def $^ -o $@
audioeffect.o: $(VST)/public.sdk/source/vst2.x/audioeffect.cpp
$(CXX) $(CXXFLAGS) -c $<
audioeffectx.o: $(VST)/public.sdk/source/vst2.x/audioeffectx.cpp
$(CXX) $(CXXFLAGS) -c $<
vstplugmain.o: $(VST)/public.sdk/source/vst2.x/vstplugmain.cpp
$(CXX) $(CXXFLAGS) -c $<
clean:
rm -f *.o $(DLL) lib$(PLUGIN).*
.PHONY: clean
If you dissect and study the makefile you will see that we are compiling things to object files then using the dllwrap tool to create the DLL. The magic flags are -mno-cygwin which tells cygwin's gcc to use the mingw headers and libraries, and the --target=i386-mingw32 flag to dllwrap which does the same for dllwrap. You also have to make a .def file for the plugin, which seems to be the case for Visual Studio as well so you will find plenty of info about it online, but here's mine:
LIBRARY again DESCRIPTION 'Sample VST plugin' EXPORTS main=VSTPluginMain
Now if you try to compile that, it will give you warnings about failed #pragma statements. I have a patch to the VST 2.4 SDK to fix that:
diff -ur vstsdk2.4.orig/pluginterfaces/vst2.x/aeffect.h vstsdk2.4/pluginterfaces/vst2.x/aeffect.h
--- vstsdk2.4.orig/pluginterfaces/vst2.x/aeffect.h 2006-02-13 14:11:16.000000000 -0800
+++ vstsdk2.4/pluginterfaces/vst2.x/aeffect.h 2006-07-29 17:19:02.957125000 -0800
@@ -34,6 +34,9 @@
#endif
#if defined __BORLANDC__
#pragma -a8
+#elif defined(__GNUC__) && defined(WIN32)
+ #pragma pack(push,8)
+ #define VSTCALLBACK __cdecl
#elif defined(WIN32) || defined(__FLAT__) || defined CBUILDER
#pragma pack(push)
#pragma pack(8)
diff -ur vstsdk2.4.orig/pluginterfaces/vst2.x/aeffectx.h vstsdk2.4/pluginterfaces/vst2.x/aeffectx.h
--- vstsdk2.4.orig/pluginterfaces/vst2.x/aeffectx.h 2006-02-13 14:11:16.000000000 -0800
+++ vstsdk2.4/pluginterfaces/vst2.x/aeffectx.h 2006-07-29 17:19:43.910250000 -0800
@@ -26,6 +26,8 @@
#endif
#elif defined __BORLANDC__
#pragma -a8
+#elif defined(__GNUC__) && defined(WIN32)
+ #pragma pack(push,8)
#elif defined(WIN32) || defined(__FLAT__)
#pragma pack(push)
#pragma pack(8)
Apply it with patch -p1 < vstsdk2.4.patch in your vstsdk2.4 subdirectory and you're good to go (don't worry, it won't break anything with Visual Studio).
I was able to compile the again plugin and it seems to be working. Now I'll just get everything else for my plugin figured out and deliver it to master dilvie.
Posted in audio |
Thingamagoop
The Thingamagoop (as featured on Music Thing) is a work of art. It's ingenious. It's hilarious. If it could it would eat chunky bacon. Be sure to watch the video.

Posted in audio | no comments |
MIDI Stupidity
I love my little M-Audio Radium 61 MIDI Controller (keyboard for you uninitiated). I just (re)learned a disturbing truth about it though: it has two MIDI outputs and zero MIDI inputs. This is just plain silly. One MIDI out is the keyboard's output, and the other passes through what's coming from the USB.
I suppose two MIDI outs is better than one, and it looks like no controllers in this class ($100-$300) have MIDI in. This completely changes my ideas for laying out my studio. Now I'm going to have to have the Yamaha P-70 connect directly to the computer which means getting an adapter to go in through the sound card or one of those MIDI channel boxes for multiplexing MIDI.
Oh well, what's another $20 when I need a $1000 pedalboard to complete The Organ?
Posted in audio | no comments |
RTDX OLE API
And now, ladies and gentlemen, I will answer the questions you have been dying to have answered! Right before your very eyes I will demystify The Texas Instruments TMS320C6416DSK RTDX OLE API!
Ok, so most of you don't care. I'm putting it on the web for posterity's sake, because it's dreadfully impossible to find. I'm no OLE expert and maybe everyone that wants to do OLE just uses some OLE browser built into Visual Studio or something, but I'm too lazy to install the copy of Visual Studio I won in a programming contest (hey, getting me to use Windows at all is a feat).
I wrote a nifty little ruby script to dump what I believe is probably the relevant info:
require 'win32ole'
rtdx = WIN32OLE.new('RTDX')
rtdx.ole_methods.each do |m|
print "#{m.return_type}\t#{m}("
print m.params.collect{|p|
"#{p.ole_type} #{p}" +
if p.default
"=#{p.default}"
else
""
end
}.join(", ")
puts ")"
endAnd here is the result:
VOID QueryInterface(GUID riid, VOID,VOID ppvObj)
UI4 AddRef()
UI4 Release()
VOID GetTypeInfoCount(UINT pctinfo)
VOID GetTypeInfo(UINT itinfo, UI4 lcid, VOID,VOID pptinfo)
VOID GetIDsOfNames(GUID riid, I1,I1 rgszNames, UINT cNames, UI4 lcid, I4 rgdispid)
VOID Invoke(I4 dispidMember, GUID riid, UI4 lcid, UI2 wFlags, DISPPARAMS pdispparams, VARIANT pvarResult, EXCEPINFO pexcepinfo, UINT puArgErr)
I4 Open(BSTR Channel_String, BSTR Read_Write)
I4 Close()
I4 Read(VARIANT pArr, I4 dataType, I4 numBytes)
I4 ReadI1(UI1 pData)
I4 ReadI2(I2 pData)
I4 ReadI4(I4 pData)
I4 ReadF4(R4 pData)
I4 ReadF8(R8 pData)
I4 ReadSAI1(VARIANT pArr)
I4 ReadSAI2(VARIANT pArr)
I4 ReadSAI4(VARIANT pArr)
I4 ReadSAF4(VARIANT pArr)
I4 ReadSAF8(VARIANT pArr)
VARIANT ReadSAI2V(I4 pStatus)
VARIANT ReadSAI4V(I4 pStatus)
I4 WriteI1(UI1 Data, I4 numBytes)
I4 WriteI2(I2 Data, I4 numBytes)
I4 WriteI4(I4 Data, I4 numBytes)
I4 WriteF4(R4 Data, I4 numBytes)
I4 WriteF8(R8 Data, I4 numBytes)
I4 Write(VARIANT Arr, I4 numBytes)
I4 Rewind()
I4 Flush()
I4 Seek(I4 MsgNum)
I4 SeekData(I4 numBytes)
I4 StatusOfWrite(I4 numBytes)
I4 GetNumMsgs(I4 pNum)
I4 GetChannelID(BSTR Channel_String, I4 chanId)
I4 GotoNextMsg()
I4 GetMsgID(I4 pMsgId)
I4 GetMsgNumber(I4 pMsgNum)
I4 GetMsgLength(I4 pLength)
I4 EnableRtdx()
I4 DisableRtdx()
I4 EnableChannel(BSTR ChannelName)
I4 DisableChannel(BSTR ChannelName)
I4 GetChannelStatus(BSTR ChannelName, I4 pChannelStatus)
I4 ConfigureRtdx(I2 Mode, I4 MainBufferSize, I4 NumOfMainBuffers)
I4 ConfigureLogFile(BSTR FileName, I4 FileSize, I2 FileFullMode, I2 FileOpenMode)
I4 GetRTDXRev(I4 RevNum)
I4 GetStatusString(BSTR StatusString)
I4 GetCapability(I4 Capability)
I4 RunDiagnostics(I2 TestType, I4 TestMode, I4 TestInfo)
BSTR GetDiagFilePath(I2 TestType)
I4 SetProcessor(BSTR Board, BSTR Cpu)
HRESULT GetTypeInfoCount(UINT pctinfo)
HRESULT GetTypeInfo(UINT itinfo, UI4 lcid, VOID,VOID pptinfo)
HRESULT GetIDsOfNames(GUID riid, I1,I1 rgszNames, UINT cNames, UI4 lcid, I4 rgdispid)
HRESULT Invoke(I4 dispidMember, GUID riid, UI4 lcid, UI2 wFlags, DISPPARAMS pdispparams, VARIANT pvarResult, EXCEPINFO pexcepinfo, UINT puArgErr)
Posted in audio, cs, ruby | no comments |
PortAudio for OS X
PortAudio is a portable cross-platform API. But it seems like none of the developers has access to a mac because the docs for getting started with PortAudio on OS X are a sorry joke.
I took the liberty of figuring it all out in XCode and creating a
PortAudio.framework which is a piece
of cake to use. Download it, move the resulting PortAudio.framework folder to
/Library/Frameworks, include as #include <PortAudio/portaudio.h>, and link
with -framework PortAudio. If you use XCode, include the same way and just
add the framework to your project and it takes care of the linking.
If you want the XCode project that I used, contact me. I don't have any qualms about sharing it, I'm just too lazy. I didn't change any code, I just made an XCode project to build the framework. Incidentally, all the documentation and READMEs and license files are still in the framework, which is just a folder which you can browse in the finder.
Enjoy!
Posted in audio, mac | 2 comments |
Knobtweakers Best of 2005 Compilation
dilvie got me to add knobtweakers.net to my RSS feeds a while ago. Admittedly I usually don't listen to it (I need some good podcast software but that's another post). But the other day I did listen to the Enicma song Lost in an Unfriendly World, and I loved it. So I decided to see what else I might have missed and started digging around the site.
I downloaded the Knobtweakers Best of 2005 Compilation and listened to it today. There's some great stuff in there. Here's what I particularly liked.
- Goof by Binaerpilot is absolutely delightful. This is the epitome of what makes electronic music cool. This is the kind of music I dream of making.
- Count to Six by I Am Robot and Proud is cute and fun. Hippity Hop!
- Nerds, Inc. by Bliss is both enjoyable and hilarious.
- The Young Punx' remix of Madonna's Dance with Someone Else makes me laugh.
- Clear Light by K-Oscillate is a neat synth world sound that holds my interest and exhibits some very interesting synth as well as very analog vocals.
- The Young Punx do it again with an fascinating and fun remix of 60's bossa nova by John B: Drum and Bacharach.
Also deserving of honorable mention:
Almost all of the songs are right up my alley, but those are the ones that really stuck out at me after the first listen.
Oh, and while I'm on the subject, you ought to check out Computerville by Lunar Shuttle Disaster which is an excellent and fun piece made in Linux. Enjoy!
Posted in audio | 2 comments |
Convergent Rounding
The rounding they taught you in elementary school has an eventual bias. i.e. over time you find that you've rounded up more often than you've rounded down. Bias is a bad thing, especially in DSP and other numerically-intensive computing.
Convergent rounding is one good way to eliminate this bias. It works the same as regular rounding except that instead of rounding 0.5 up, you round 0.5 to the nearest even number. So 1.5 goes to 2.0, 2.5 goes to 2.0, etc.
A quick tutorial on short fixed-point programming in C. The decimal point is between bits 15 and 14, and bit 15 is your sign bit. So, you have a range of 1-2^-15 to -1. So 0.5 is 0x4000, and -0.5 is 0xC000 (two's complement). Now, when you multiply two numbers together you get twice as many bits of precision, so multiplying two shorts gives you an int, and in that int the decimal point is between bits 30 and 29, and bits 30 and 31 are sign bits. We want to round at bit 15 so we can fit the result back into a short. Clear as mud?
The point of this post is to get this C code out there, because as simple as it seems it was a devil to debug:
int cround(int a)
{
if (a & 0x3fff)
a += 0x4000; // normal rounding
else
a += (a>>1) & 0x4000; // convergent rounding
return a & 0xffff8000;
}
If you don't see why this works (I didn't when I first read the "add half of the lsb uf the upper part" algorithm), then fill out this truth table as an excercise:
0.00
0.01
0.10
0.11
1.00
1.01
1.10
1.11
Here's an example of the function in use:
short x,y;
int a;
x = 0x7ffd; // x = almost 1
y = 0x4000; // y = 1/2
a = x*y; // a = 0x1fff4000
a = cround(a); // a = 0x1fff0000
x = a>>15; // x = 0x3ffe
Posted in audio, cs | no comments |
Juk
I've been giving Juk a try, and here's my somewhat brutal assessment. First let me say I love taglib, which seems to be by the same guy that wrote Juk. So I'm sure Juk will catch up with its features and become a great program. I don't really have any major gripes with the UI, which is high praise coming from me. I just don't find it to be stable enough for normal use. I'm looking at version 2.2.2.
The first thing you notice is that you have to pretty much install all of KDE to get Juk. This is an oft-debated issue that I'm not going to address further at this juncture.
The second thing I noticed is that it kept crashing on me. All. The. Time. Maybe it's just my karma; I tend to bring out the worst in software. Some of the bugs are reproducible, others seemed to be random, but for awhile I was crashing the thing every couple of minutes, literally. Once I learned what not to do, we started getting along better.
The complete instability is the primary reason I won't be using Juk in the near future, but the second reason is almost as compelling - it tends to skip. Ok, maybe it's not a skip, but a jump or a underrun, but the old terminology dies hard. Incidentally, I wasn't too keen about having to use artsd, I have no idea what akode is but I bet it's a bad idea, and gstreamer seems to underrun on OGGs for some reason. So basically, Juk isn't able to play music smoothly and that's not good enough for me. (Hint: a nice fat buffer is not a problem for music players!)
Now for what I liked. I already told you I like taglib, and Juk's tagger didn't disappoint me (aside from its being one of the more crashable aspects of the program). Its MusicBrainz support means this is the only program I've found so far that I can get to run that supports MusicBrainz, and it does so well. I wish there was more information about just how it made the matches though. In some cases I don't know which of the 10 versions of a song I've got, so I don't dare tag it with one of the versions, but if I knew the acoustic fingerprint was almost a perfect match, (much more so relatively speaking than the others) that might give me more confidence. I also like the automatic tree of Artist, Genre, and Albums, and the playlist stuff. I like random album mode. I dislike that turning random on and off is so hard. I found that it wasn't obvious which set of music was being considered for play at any time, but I like the history and queue interfaces.
In short, I like Juk but I won't be using it because of stability issues. I did use it to organize my tags, though. For renaming files, I think I'm going to write my own script as I have very strange (but simple) ideas about how the filestructure should be. I think Juk's renaming comes close to the ease and power of EasyTag though. Incidentally, if EasyTag did MusicBrainz, I probably never would have looked at Juk, in spite of EasyTag's odd interface. That would have been a loss, because I trust Juk (or rather, taglib) much more than I do EasyTag not to mess my files up, in spite of the lack of any experience that would cause me to distrust EasyTag.
Posted in audio | no comments |
Older posts: 1 2
