|
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.
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.
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.
QuickTime
To build the VizKit dll on Windows, you have to use the QuickTime SDK for Windows.
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.libThe 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.
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”). If you see a warning saying something like:
NOTE: WINVER has been defined as 0x0500 or greater which enables 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
|
||||