imagomat
about
     
 
The Making of VizKit
Set Up

VizKit is written in C/C++. It is built as a shared library. The product is a dll file on Windows and a Mach-O bundle on Mac OS X.

VizKit receives and processes messages by iTunes as described in the documentation by Apple: “tn 2016 Visual Plug-ins”.

Official sample code by Apple is available as “iTunes Visual Plug-ins SDK”.

Main Idea

VizKit consists of various functions and classes that are assembled together. The main functionality is centered around the VisualEnsemble and the VisualActor class. The VisualEnsemble is the group of all actors. It keeps track of the actors and calls each actor during the show. The VisualActor class is a lean abstract class that defines the interface for each concrete actor. Each specific actor inherits a method getName(), a method getState(), and a method show(). Show() must be overridden by each concrete actor, while getName() and getState() do not need to be implemented by the concrete subclass. By default getName() returns the value of the protected instance variable actorName – each specific VisualActor is responsible for setting its own inherited actorName variable to the appropriate value. By default getState() returns the value of the protected instance variable state; each specific VisualActor is responsible for setting its own inherited state variable to the appropriate value. The VisualEnsemble calls the show() method of each actor while displaying the visualizer. Show() is the main render and display routine of the VisualActor that gets called repeatedly to garantee a fast refresh rate.

Each run of the visualizer show is triggered by iTunes (by passing a kVisualPluginRenderMessage).

Logically situated above the VisualEnsemble and the VisualActors, the VisualStageControl coordinates the show on the screen. The VisualStageControl can manipulate the behaviour of individual VisualActors by evaluating each visual actor’s name.

diagram

Customization

To use the VizKit samplework, you have to subclass and implement the VisualActor interface. A sample VisualActor implementation is already included with the VizKit source code files: the TemplateActor.

The action performed by the TemplateActor is pure sample work. It can be changed at will.

The TemplateActor is a lightweight implementation of the VisualActor interface. It includes source code that draws dynamically created bitmap image data as part of an asset. It also fetches network data, names of musicians whose work is similar to the music which is currently playing (by means of the last.fm web service at ws.audioscrobbler.com). The artist names are used to create a bitmap image which is displayed at the right side of the screen.

To customize the VizKit samplework with the goal of ending up with an independent and individual iTunes visualizer, mainly three source code files have to be edited: VisualConfiguration.cpp, VisualStageControl.cpp, and VisualActorGraphics.cpp.

  • VisualConfiguration sets the name of the visualizer plug-in as it is presented in iTunes’ Visualizer menu. The part of the configuration source code to edit is marked with “INDIVIDUAL VISUALIZER IDENTIFICATION CONFIGURATION”.
  • VisualStageControl’s method init() initializes new actors and adds them to the VisualEnsemble.
  • VisualActorGraphics provides access to aggregated graphical operations for the VisualActors.
  • For further customization you also might want to edit VisualPreferences.h.
  • And you might want to customize the UI for the visualizer. An iTunes visualizer can be configured in runtime with an Options dialog.
Persistent Preferences

VizKit provides means for storing and retrieving preference values. Identifiers for preferences are declared and defined as enum values in the public section of VisualPreferences.h. Preferences can be of data type int (PreferenceKeyInt), of data type float (PreferenceKeyFloat), of data type char (PreferenceKeyChar), or of data type bool (PreferenceKeyBool). The values of the identifiers are initially set to their factory defaults with the function setDefaultValues(). A current preference value can be retrieved by calling getValue(). On runtime a preference value can be set by calling setValue(). The preference values are persistently stored after calling storeValues() method.

Each preference key added must be appended to the list of keys in the appropriate conversion function where the key is translated to the name and vice versa (VisualPreferences::convertPreferenceKey[Int|Float|Char|Bool]StringToKey() and VisualPreferences::convertPreferenceKeyToString()).

Persistent preferences retain their value across iTunes sessions (after quit and relaunch).

Mac OS X: The preferences are stored in the file "de.imagomat.vizkit.plist". The file is located inside the preferences folder of the user home directory ("~/Library/Preferences/").

Windows: The preferences are stored in the file "Preferences.txt". The file is located inside the "\Documents and Settings\{username}\Application Data\Imagomat\VizKit\" directory of the system volume. To see and access the file, “Show hidden files and folders” might need to be turned on (View settings of “Windows Explorer”’s Folder Options).

In case of problems with preferences, the preference file can always be deleted again. The visualizer will return to use its default preferences if it does not find a preference file.

By editing VisualNotificationKey.h, own notifications can be added to a custom visualizer.

The Notification is the Message

VizKit uses messaging to notify Actors about changes of data or occurences of events. Messages and events are passed to VisualActors by invoking VisualActor's interface method handleNotification() with a VisualNotification as parameter. Message keys are defined as VisualNotificationKey. Each VisualActor that wants to be notified about events has to register for them. The registration can be easily done in VisualActor's virtual init() method by calling VisualNotification::registerNotification() with the instance of the VisualActor and the VisualNotificationKey as argument.

VisualNotifications convey messages. Messages can be event information. They can also include additional message data. At minimum a VisualNotification contains a VisualNotificationKey. To send a notification, the post() method has to be invoked. VisualNotification’s static method post() allows the distribution of a VisualNotificationKey. To send a VisualNotification with additional data, the public method post() has to be invoked on the instance.

In a typical scenario a VisualNotification acts as a transmitter of a changed preference value.

All newly introduced notifications must be added to the main switch block in VisualMainAction::renderAction() and to the conversion function VisualNotification::convertNotificationKeyToString().

The Canvas is the Frame of the Action

iTunes visuals are drawn on the main window of the application or windowless in full screen mode. iTunes passes the dimensions of the drawable rectangle to the active visualizer (top-left being 0,0). The drawable rect is communicated to the visualizer with the kVisualPluginShowWindowMessage in the VisualPluginHandler function call as messageInfo->u.showWindowMessage.drawRect. VizKit memorizes the width and height of the drawable rectangle as width and height of the canvas.

By assigning kVisualDoesNotNeedResolutionSwitch to the options of the visualPluginMessageInfo->u.initMessage in the VisualPluginHandler, VizKit tells iTunes that it wants to use the currently set display resolution as the canvas of the visualizer show. Earlier versions of iTunes used to switch to a low screen resolution (640px x 480px or 800px x 600px) by default to reduce pixel data load.

Canvas dimensions are measured in pixels.

Although the UI controls to adjust the settings disappeared since iTunes 8, the visualizer communication with iTunes takes into account that the size of the drawable area of the visualizer can be changed. Menu item names in the iTunes UI were labelled “Small”, “Medium” or “Large”. Small, Medium, and Large were relative sizes related to the current size of the window or full screen resolution.

User Space is (Coord-)Place

The viewport of the OpenGL surface is set up with the two dimensions of the canvas (glViewport with width and height). Since OpenGL is designed for 3D graphics, the surface is further transformed to a frustum that can have an orthographic or perspective projection (glOrtho, gluPerspective, glFrustum).

The projection transformation is modelled with the VisualCamera. The user space is measured in coordinates. Coordinates are fictional units. They are not directly mapped to pixel values or distances in inches.

The center of the user space is 0.0, 0.0. If the canvas is a square the coordinates are -1.0 to 1.0 from left to right, and -1.0 to 1.0 from bottom to top. More often than not the canvas is a rectangle, so that the width and height values of the viewport are compared and the smallest border is laid out from -1.0 to 1.0. The wider border gets scaled according to the aspect ratio. Near and far values on the z-axis are set to 0.0 to 10.0 with orthographic projection. With the perspective projection the position of the near clipping plane can be set; the far clipping plane is positioned as far as the longest vertical or horizontal distance.

Basics

VizKit provides basic functionality for string, file and image operations.

Animated Properties

One of the main tasks of an audio visualizer is animation. VizKit aids in animating properties of graphical objects with the VisualAnimation and the VisualAsset class. An animation has a start value, an end value, and a duration. One animation can only animate one property (AnimatedProperty). So the type of animation (the property which is supposed to be animated, e.g. size, opacity, etc.) is set up when initializing an animation. To reduce complexity the animation is tied to an asset. Depending on the type of animation, the running animation calls a callback function of the visual asset. Within VisualAsset’s callback function the property of the asset is calculated according to the current value of the animation. When executing VisualAsset’s draw() method the animated value of the property is taken into account.

Tools and Utilities

The VizKit samplework is equipped with a number of tools. The VisualTiming class assists by taking time values. VisualErrorHandling’s writeLog() function prints strings to a log file for debugging and diagnostical purposes. When not printing into a log file on the desktop, on Mac OS X messages are printed to console.log while on Windows the messages are added to the event log.

The ProcessMonitor class is no tool but a VisualActor on its own. It prints strings on the canvas. The process monitor strings can be hidden or shown by pressing the <s> key on the keyboard. By calling the function setProcessInfo(), a label and a string can be passed to the ProcessMonitor. The function call is dispatched to the VisualStageControl which passes a notification to the VisualEnsemble. The notification is received by the ProcessMonitor and with each show() call the current values are presented on the screen. In addition to string values the VisualProcessMonitor shows a visual waveform representation of the current audio data and a spectral audio analyzer bar graph. The ProcessMonitor also shows a progress meter that displays the current play position of the currently playing audio track.

Track Info Display

The main task of the visualizer is the combination of the audio and the graphics domain. Audio data is processed and analyzed by the VisualAudioLab. Graphic operations are bundled with the VisualGraphics class.

Track title, lyrics and the cover artwork are essential metadata of an audio track. VizKit supplies functionality to display this data.

If the currently playing audio track contains cover artwork data, it is displayed on the canvas. The CoverArtActor imports the image data and applies custom transformations. The action of the CoverArtActor is only an example of what can be done with the image data of the cover artwork. The performance of the actor can be modified at will.

The Unicode-savvy title of the currently playing audio track is transformed into a texture memory image by the TrackTitleActor. The font rendering is done by loading a custom font which is bundled as a resource of the plug-in. VizKit uses the free OpenType font “Devroye” by Apostrophe; but any other free font can be used as a plug-in resource. System-wise available fonts can be used of course, too. And the content of the textured string also can be set at will.

A texture of the lyrics text is created by the TrackLyricsActor. Like TrackTitleActor it also uses VisualImage’s initWithStyledString() method to create the texture of the string.

Options dialog

VizKit implements a cross-platform options dialog with a tab layout. The first tab pane displays about information for the VizKit visualizer. The second pane allows to set the font face for the track title display. And the third pane sports a checkbox for activating and deactivating the automatic check for an available update online.

The cross-platform function VisualConfigurationDialog::show() hides the platform-specific implementation of the options dialog.

Building

The distributed files do not have prebuilt binaries with the Xcode project or the Visual Studio project.
The visualizer product has to be built with the provided resources and source files by means of the provided project files.

QuickTime

To build the VizKit dll on Windows, you have to use the QuickTime SDK for Windows.
Windows' dependency on QuickTime is limited to VisualQuickTime.cpp.
The header files (CIncludes) must be accessible by the IDE and the target must be linked against the static qtmlClient library.
VizKit code references a folder named “QuickTime” next to the topmost project directory.
If you are compiling on Windows and see an error like “..\..\source\Tools\VisualQuickTime.cpp(40) : fatal error C1083: Cannot open include file: 'QuickTime/CIncludes/QTML.h': No such file or directory”, the quicktime header files are not accessible for the IDE.
If you see an error like “fatal error LNK1181: cannot open input file 'qtmlClient.lib'”, the qtmlClient library is not accessible.
To make the header files accessible for the Visual Studio IDE, the path to the CIncludes directory must be entered in the appropriate Property Page: Configuration Properties: C/C++: General: Additonal Include Directories.
To make the qtmlClient library accessible for the IDE, the path to the library must be entered in the Property Page: Configuration Properties: Linker: General: Additional Library Directories.
Maybe Visual Studio will report an error in QuickTime’s Debugging.h file during compilation: fatal error C1017 (invalid integer constant expression). The problem seems to be that Windows defines the symbol DEBUG already. One solution can be found by changing QuickTime’s DEBUG symbol handling in Debugging.h; by changing #if DEBUG to #ifdef DEBUG, Visual Studio will compile again.

Project Options

On Windows the sources are compiled with these project options:

debug: /Od /I ".\..\..\..\\" /I ".\..\..\..\QuickTime\CIncludes" /I ".\..\..\source\\" /I ".\..\..\source\iTunesVisualAPI\\" /I ".\..\..\source\Actors\\" /I ".\..\..\source\Actions\\" /I ".\..\..\source\AudioLab\\" /I ".\..\..\source\Tools\\" /I ".\..\..\source\Tools\Timing\\" /I ".\..\..\source\win\\" /D "TARGET_OS_WIN" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "WINVER=0x0500" /D "_WIN32_WINNT=0x0500" /D "_CRT_SECURE_NO_DEPRECATE=1" /D "_VC80_UPGRADE=0x0710" /D "_WINDLL" /D "_MBCS" /FD /EHsc /RTC1 /MTd /Fo".\Debug/" /Fd".\Debug/" /W3 /nologo /c /Z7 /wd4996 /errorReport:prompt

release: /I ".\..\..\..\\" /I ".\..\..\..\QuickTime\CIncludes" /I ".\..\..\source\\" /I ".\..\..\source\iTunesVisualAPI\\" /I ".\..\..\source\Actors\\" /I ".\..\..\source\Actions\\" /I ".\..\..\source\AudioLab\\" /I ".\..\..\source\Tools\\" /I ".\..\..\source\Tools\Timing\\" /I ".\..\..\source\win\\" /D "TARGET_OS_WIN" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "WINVER=0x0500" /D "_WIN32_WINNT=0x0500" /D "_CRT_SECURE_NO_DEPRECATE=1" /D "_VC80_UPGRADE=0x0710" /D "_WINDLL" /D "_MBCS" /FD /EHsc /MT /Fo".\Release/" /Fd".\Release/" /W3 /nologo /c /wd4996 /errorReport:prompt

The library dependencies:

debug: Nafxcwd.lib, Libcmtd.lib, gdiplus.lib, opengl32.lib, glu32.lib, wininet.lib, qtmlClient.lib

release: Nafxcw.lib, Libcmt.lib, gdiplus.lib, opengl32.lib, glu32.lib, wininet.lib, qtmlClient.lib

The include directories with header files: .\..\..\..\; .\..\..\..\QuickTime\CIncludes; .\..\..\source\; .\..\..\source\iTunesVisualAPI\; .\..\..\source\Actors\; .\..\..\source\Actions\; .\..\..\source\AudioLab\; .\..\..\source\Tools\; .\..\..\source\Tools\Timing\; .\..\..\source\win\

These preprocessor definitions are used on Windows:

debug: TARGET_OS_WIN, WIN32, _DEBUG, _WINDOWS, _USRDLL, WINVER=0x0500, _WIN32_WINNT=0x0500, _CRT_SECURE_NO_DEPRECATE=1

release: TARGET_OS_WIN, WIN32, NDEBUG, _WINDOWS, _USRDLL, WINVER=0x0500, _WIN32_WINNT=0x0500, _CRT_SECURE_NO_DEPRECATE=1

On Mac OS X “TARGET_OS_MAC=1” is set as Preprocessor Macro.

On Mac OS X iTunes and the Finder need the PkgInfo file. Only when the PkgInfo file is accessible in the plug-in bundle directory (/Contents/PkgInfo), the bundle will be shown by the Finder as an iTunes plug-in file. The PkgInfo file identifies CFBundlePackageType (“hvpl”) and CFBundleSignature (“hook”) to the Finder so that the bundle can be presented as an iTunes plug-in file with the appropriate icon.
Since version 1.2 Xcode is able to generate PkgInfo file automatically. The build setting “Force Package Info Generation” has to be set (i.e. “GENERATE_PKGINFO_FILE=YES”). Prior to version 1.2 the PkgInfo file had to be copied manually or by script into the created bundle directory structure. If the bundle directory structure still does not present itself as a single file logging out and logging in again may force a refresh of the Finder view.

Warnings and Dependencies

The sample project VizKit is carefully written to diminish compiler warnings. But when building on Windows you may receive a warning saying that standard library “LIBCMT” is in conflict with other libraries. The warning refers to the fact that QuickTime has been compiled thread safe with the “LIBCMT” library while in debug configuration VizKit compiles with another c library (“LIBCMTD”).
(Apple has set up a Technical Q&A (QTW94) about the warning, called: “MSVC++ link error LNK4098 When Building QuickTime 3 for Windows Apps”.)

If you see a warning saying something like:

NOTE: WINVER has been defined as 0x0500 or greater which enables
Windows NT 5.0 and Windows 98 features. When these headers were released,
Windows NT 5.0 beta 1 and Windows 98 beta 2.1 were the current versions.
For this release when WINVER is defined as 0x0500 or greater, you can only
build beta or test applications. To build a retail application,
set WINVER to 0x0400 or visit http://www.microsoft.com/msdn/sdk
to see if retail Windows NT 5.0 or Windows 98 headers are available.

you have to install the new header files included with the developer SDK from Microsoft.

Dependency on OS technologies is kept small. Only implementation files are supposed to include more OS dependent files like <windows.h> on Windows or <Carbon/Carbon.h> or <CoreFoundation/CFString.h> on Mac OS. OS dependent UI technology is only used for the Options dialog which is abstracted by the VisualConfigurationDialog class. To insulate the Afx dependency on Windows the link order is explicitly set to Nafxcw(d).lib and Libcmt(d).lib in the project settings (Linker Input).

 

Documentation of classes and methods download chm file

 

changelog