TGraphDisplay3D is a Delphi component and DLL for use in Win32 and Win64 (Windows 7/8/10) software.
It's purpose is to provide display of graphs and audio samples, in the most powerful and efficient Direct3D display way. As it uses GPU 3D accelerated graphics it can easily display a couple of million values and still maintain real time interaction and high FPS. It provides functions like positive, mono, stereo or multiple display type of graphs, configureable colors, making a slection, adding markers, animated zoom in and out, automatic amplitude adjusting, customized axis text, etc.
TGraphDisplay3D also has the powerful ability to use it as an audio sample display. In addition to the functions mentioned before, there is support for displaying mono, stereo or multi-channel audio files (5.1. etc), playback position cursor, quick-playing from middle-mouse button click, etc.
A standalone DLL version for audio sample display is included in the package (waveform and sonogram modes) that can be used with any developer environment that supports using DLLs, Delphi and C++ header included.
If you are looking for a simple sample display creator component that just returns a HBitmap handle with a picture, take a look at Sample Display Library.
- Uses Direct3D 11 3D accelerated graphics
- Positive, Mono, Stereo and Multi display type
- Line or "gradient triangles" mode display
- Automatic or manual amplitude adjustment
- Real-time (eg. oscilloscope) mode
- Audio sample display support (functions to use the component as a sample display) with support for virtually unlimited audio channels
- 'Dynamic mode' that supports GB sized sample buffers and zooming-in to exact samples and still maintaning 60-100 fps
- Sonogram mode for audio sample display
- Selection capability (per channel for a multi graph)
- Add markers with custom color
- Component uses an array of graphs, that is you can switch between multiple displays with one line of code
- Cool animated display (zoom in and out, startup rotation effect etc.)
- Completely customizable (axis texts, colors, grids etc.)
- Rendering is performed in a separate thread so the UI thread is free for use
- Support for Win64 build mode
- Fully object oriented Delphi style design
TGraphDisplay3D in freeware, shareware and commercial software?
The component comes with full source code and can be evaluated freely. If you like it and decide to use it in a freeware, shareware or commercial (or any other money making - advertising, in app. selling, etc.) product one of the licenses is needed.
NOTE: The component has been completely re-written from DirectX 9 to DirectX 11. If TGraphDisplay3D DirectX 9 version of the component is already installed in Delphi, uninstall it first before installing the latest version.
If everything went smooth, you can access the TGraphDisplay3D component on 3delite's tab.
- In Delphi menu: File/New/Package Delphi
- In project manager (in the upper-right corner by default), right-click on "Package1.dproj" and select "Add..."
- Unit file name: click "Browse" and select "GraphDisplay3D.pas" and click "Ok"
- Save the package with a different name.
- In project manager (in the upper-right corner by default), right-click on "Package1.dproj" (the name as saved) and select "Install..."
The audio sample display tutorial supports audio file formats: MP3, MP2, MP1, OGG, WAV and music modules. Yes, it supports music modules too! MO3, IT, XM, S3M, MTM, MOD, UMX
If you want your application to handle many more audio file formats, check the great BASS add-ons on the BASS page: http://www.un4seen.com/bass.html#addons
- .ActiveIndex: Specifies which graph is displayed on the 3D panel.
- .AllowAmplitudeChangeWithKey: Turn on/off possibility to change the display sample amplitude with + and - keys.
- .AllowQuickPlay: Turn on/off middle-mouse button quick play and space-bar play/pause possibility.
- .AllowSelect: Turn on/off selection possibility.
- .AllowWheelZoom: Turn on/off mouse-wheel zoom in/out possibility.
- .Animate: Turn on/off animated startup rotation, zoom and show all possibility.
- .Antialiasing: 1 means no anti aliasing, default value is 4. Result slower display but better image quality.
- .AutoReInit: If set to True Direct3D is re-initialized every time when the panel is resized. Slow resize, but gives always precise 1:1 resolution.
- .FollowCursor: When zoomed in display will scroll to keep the cursor in the middle of the display.
- .MaximumVertexCount: Maximum vertex count for 1 sample's object. Default is 500 000. You may need to lower this to 100 000 or even 50 000 on some old graphic cards. The bigger the resolution the slower the rendering but the sample graphics is more detailed when zoomed. Modern graphics cards can display about 2-3 million vertexes in one go, an RTX 3080 can manage 8 000 000 vertexes in line mode and more than 16 000 000 vertexes in triangle mode.
- .Panel3DPicture: Specify a picture to display when 3D display is not active.
- .SampleInSeparateThread: Specifies wether to run the sampling (OnNeedSamplesInThread) in separate thread. False by default. Note that when not set use the OnNeedSamples event.
- gdsmFlush: After the 3D object has been created clear the Samples array. Results lower memory usage, but on panel resize you have to manually re-create the samples vertex buffer again.
- gdsmKeep: Default. Do not clear the Samples array after the 3D object has been created. Required for automatic panel resizing (to automatically re-create the vertex buffer), also usefull if you need the sample data afterwards.
- .ScrollBarHeight: Height of the scroll bar for scrolling the display. Set to 0 if you don't need the scroll bar.
- .ShowCursor: For audio sample display, show the current playback position cursor.
- .ShowMarkers: Turn on/off display of markers.
- .ShowSelection: Turn on/off display of selection. If you don't want selection possibility set it to False.
- .SolidCursor: When True audio current playback position cursor is a solid white line, else a gradient rectangle.
- .SuppressErrors: Do not raise exceptions.
- .AfterD3DRender: is called when the sample and all the graphics had been drawn on the surface. You can draw on the surface that will be on top of the sample graphics.
You can draw on the surface with .Items.Item[x].g_pd3dDevice
- .BeforeD3DRender: is called when the D3D surface is cleared and ready for drawing.
You can draw on the surface with .Items.Item[x].g_pd3dDevice that will be behind the sample graphics.
- .OnD3DDestroy: is called before freeing the Direct3D object.
- .OnMarkerChange: is called when a marker is added, hovered, moved or deleted.
- .OnNeedPlaybackPosition: is called when ShowCursor is True and the cursor needs a playback position. If you want playback position display you need to implement this event.
- .OnNeedPlayStatus: is called when AllowQuickPlay is True, and middle mouse button is clicked or space bar is pressed. Depending on the result of this event OnPause or OnPlay ievent is called.
- .OnNeedAxisXText: If you want to customize the X axis texts you have to implement this event. Is usefull for example for audio sample display to display time formatted values.
- .OnNeedAxisYText: If you want to customize the Y axis texts you have to implement this event.
- .OnNeedSamples: When calling Initialize() or manually CreateVertexesFromSamples() this event is called to fill up the graph sample values. If you manually fill up the values do not use this event.
- .OnNeedSamplesInThread: Same as above, if SampleInSeparateThread is set to True this event is called. Note that is event will run inside a thread so things that apply to threads apply here too. For example VCL access is not available.
- .OnPause: is called when the user presses the space bar and OnNeedPlayStatus reports psPlaying or psPaused.
- .OnPlay: is called when the user presses the space bar or middle mouse clicks on the display and OnNeedPlayStatus reports psStoped.
- .OnSampleThreadFinished: is called when the sampling thread has finished thus the display is ready. Only called when CacheSampleInSeparateThread is True.
- .OnSelection: is called when the user changes the selection on the sample display.
Functions and procedures
- .Initialize(Index: Cardinal): Boolean;
Initialize and display stream in slot "Index".
Result is True if successfull.
Draw a frame. The slot specified with 'ActiveIndex' is drawn.
This should be called about every 30th msec (or more often) if you want smooth 3D graphics. Another good idea is to call it in OnIdle().
NO NEED TO CALL THIS FUNCTION ANY MORE! Rendering is now performed in a separate thread, start the rendering with: .StartRendering;
Start rendering the graphics (with animations) that is start the rendering thread.
Stop rendering the graphics (terminate render thread).
Zoom to the selection. The slot specified with 'ActiveIndex' is zoomed.
Is animated if Animate is True and 'gdaZoomSelection' is specified in Animations.
Display the whole graph (zoom out). The slot specified with 'ActiveIndex' is showed all.
Is animated if Animate is True and 'gdaShowAll' is specified in Animations.
Axis text space length is specified by '.Items.Item[ActiveIndex].Axis.AxisY.MarginWidthChars' (Y axis).
Font and color is variable with '.Items.Item[ActiveIndex].Axis.AxisY.Font' (Y axis).
See the class for all the available parameters (X/Y).
Mouse hover focus
By default GraphDisplay3D component gets focus when the mouse is hovered above it. This will result that mouse wheel can be used to zoom in and out.
If you don't want this behavior, turn off mouse focus with "GraphDisplay3D.CaptureMouseOnHover := False;" and add a 'TApplicationEvents' component to the form and send mouse wheel messages from it.
See the Audio Display Tutorial on how to accomplish this.
To display the control panel set 'ShowControls' to 'True'. To add custom controls use (for example) 'PanelControls.ControlsCustom.Append('My control')' and assign the 'OnCustomControlClick()' event that is called with the index of the control that was clicked.
To add a hint for the custom control use 'PanelControls.ControlsCustomHints.Append('My control does this and that...')', the indexes need to be the same as in 'ControlsCustom'.
If the audio playback state changes call 'PanelControls.SetPlayPauseLabel;' to update the play/pause label.
Dynamic sample display
Set 'SamplesVertexBufferUsageType' field to 'gdsvbutDynamic': when using eg. as an audio sample display now it's possible to zoom-in and display samples in higher resolution as the sample vertex buffer is re-created for every frame if needed (on scroll or zoom change) and only the visible part is used. The advantage is that it's possible to zoom-in to exact individual samples, the cost is that the whole audio file (all audio sample data) needs to be in memory.
With this mode the 'MaximumVertexCount' now can be a low value (100 000 to 500 000 recommended) so creating the vertex buffer for every frame needed slows rendering down, but rendering much less samples is faster.
The advantage of 'gdsvbutStatic' is that it uses very little memory but it's not sample precise when zooming, the 'gdsvbutDynamic' is sample precise but the whole audio sample data needs to be in memory, so 64 bit build is recommended, 32 bit mode is limited to 2GB of memory. This 32 bit limitiation can be extended to 4 GB with some tweaking (although it's very unlikely that allocating more then 1 GB of memory will succeed), please Google for this for the details.
Note that 'gdsvbutDynamic' mode will only be used when the graph item's sample count is higher then 'MaximumVertexCount' else the vertex buffer is created first and re-used for rendering the frames as previously (as with 'gdsvbutStatic').
With 'gdsvbutDynamicAlways' the sample vertex buffer is created when the display changes regardless of the 'MaximumVertexCount' value.
When using 'gdsvbutDynamic' or 'gdsvbutDynamicAlways' the sample buffer and so the display can be manipulated in real-time, using 'CriticalSection.Enter' and 'Leave' might be needed. Call 'SetUpdateVertexBuffer' if there are changes to the sample buffer and the next frame rendered will display the changes immediately.
Notes for the DLL version
The native DLL audio loading functions use BASS for loading the audio files. So if you use these functions bass.dll is needed on the search path (eg. beside the .exe) and requires a BASS license too if your app is not free.
When using GraphDisplay3D_LoadBASSChannelWaveform() or GraphDisplay3D_LoadBASSChannelSonogram() functions if the BASS channel handle is a BASS mixer handle it's not possible for the component to seek to the 'StartSample' so make sure that the channel handle is currently at the given start position. For example use BASS_ChannelGetData() (with 'Buffer' = nil) to reach the start position before calling the load functions.
The BASS channel handle must be a "decoding channel" (BASS_STREAM_DECODE) and must be float (BASS_SAMPLE_FLOAT).
The supported DLL audio loading functions use BASS, if you use other audio library please contact me, it should be possible to add support of providing custom samples.
My application using TGraphDisplay3D uses too much CPU power and/or is very slow!
Note: The rendering is performed in 1 separate thread, so if the parameters are max'ed out 1 CPU core and the GPU is used maximally at most.
- Reduce the 'MaximumVertexCount' to a lower value (minimally recommended 100 000 - else should be around 500 000, for a modern GFX card set it to 8 million or more when using 'gdsvbutStatic', for 'gdsvbutDynamic' it should be below 500 000, note that in 'gdsvbutDynamic' mode higher values increase CPU usage very much as well).
- If you are using the built-in thread renderer ('StartRendering'/'StopRendering' methods), adjust 'SleepBetweenFrames' property (default is 10 ms) for the internal Sleep() call (please see WinAPI Sleep() documentation). Use value '1' for maximum FPS ('0' is also possible but not recommended, it has some side effects, zoom animation becomes slow etc.). Note that when using 'SamplesVertexBufferUsageType = gdsvbutDynamic' lower sleep values increase the CPU usage. Also the higher is the 'MaximumVertexCount' value the more CPU is used.