|
How to use the Waveform Analyzer |
![]() ![]()
|
After recording a sound (see the How to perform a recording session section for recording details) the embedded Waveform Analyzer, implemented through the WaveformAnalyzer object, allows performing a detailed analysis of the sound itself with the purpose of generating a graphical representation of the sound's waveform.
The first step is to perform the sound's analysis through a call to the WaveformAnalyzer.AnalyzeFullSound method: the analysis can be more or less accurate depending upon the resolution set into the nResolution property of the WAVEFORM_ANALYZER_SETTINGS_2 data structure: higher resolutions will allow a better quality because more peaks will be detected: as a side effect, higher resolutions will require more memory and will generate larger bitmaps. When the results of an analysis are no more needed, the involved memory can be released through a call to the WaveformAnalyzer.FreeMemory method. The analysis can be aborted at any time through a call to the WaveformAnalyzer.AnalyzeAbort method.
After calling this method, the control will allow the container application to stay up-to-date about the analysis advancement through the following events:
| • | WaveAnalysisStart: fired when the sound's analysis begins. |
| • | WaveAnalysisPerc: fired several times during the analysis in order to inform the container application about the percentage of advancement. |
| • | WaveAnalysisDone: fired when the sound's analysis is completed |
After completing the waveform analysis, you can request the level, expressed in percentage, of the highest and of the lowest peaks available inside a certain range of the waveform through the WaveformAnalyzer.GetMinMaxPeakLevelsForRange method.
At this point it's possible creating a graphical representation of analyzed sounds in one of the following modes:
Mode 2: Creation of bitmaps in various graphic formats
Mode 3: Rendering on a graphic Device Context (HDC)
In order to start the visual editing of the sound's waveform, we need to create the Waveform Analyzer user interface through a call to the WaveformAnalyzer.Create method. By default the Waveform Analyzer user interface will appear as in the picture below where the top waveform represents the left channel of a stereo sound while the bottom waveform represents the right channel of a stereo sound (sounds in mono are rendered using one single waveform):

Once the waveform analysis has been performed, you can immediately display the full waveform on the visible area of the analyzer through a call to the WaveformAnalyzer.SetDisplayRange method by passing 0 and -1 respectively to the nBeginPosInMs and nEndPosInMs parameters.
As most Windows controls with an user interface, the Waveform Analyzer can be:
| • | shown or hidden through the WaveformAnalyzer.Show method |
| • | moved or resized through the WaveformAnalyzer.Move method |
| • | refreshed through the WaveformAnalyzer.Refresh method |
| • | destroyed through the WaveformAnalyzer.Destroy method |
| • | scrolled through the WaveformAnalyzer.Scroll method: scrolling can be also performed panning the horizontal scrollbars with the mouse. |
| • | it's also possible replacing the standard cursors, used for scrolling and resizing, operations through the WaveformAnalyzer.SetTrackerCursors method |
The graphical appearance of this control is fully customizable and you can modify colors used to render the various elements and hide/show all of the elements surrounding the waveform representation: for this purpose you can retrieve the current graphical settings calling the WaveformAnalyzer.GetGraphicalSettings2 method and then modify them calling the WaveformAnalyzer.SetGraphicalSettings2 method: both methods receive a reference to the WAVEFORM_ANALYZER_SETTINGS_2 data structure.
When using the control inside a web page, where managing data structures is not an easy task, you can access single parameters of the WAVEFORM_ANALYZER_SETTINGS_2 data structure using the WaveformAnalyzer.GetGraphicalSettingsParam and WaveformAnalyzer.SetGraphicalSettingsParam methods.
The Waveform Analyzer allows selecting/deselecting portions of the displayed waveform in two different ways:
| • | through code using the WaveformAnalyzer.SetSelection method. |
| • | through mouse acting directly on the waveform area: simply press the left button, drag the mouse position keeping the left button pressed and then release the left button: the selected area will appear with its colors inverted and with two tracker handles that will allow further manual resizing of the selected range; this selection can be also moved performing a mouse panning. After these manual operations the control can obtain the selected area through the WaveformAnalyzer.GetSelection method. During a playback session the mouse interaction is automatically disabled and mouse clicks will be ignored. |

The Waveform Analyzer allows zooming the displayed waveform in two different ways:
| • | through code using one of the following methods: WaveformAnalyzer.SetDisplayRange, WaveformAnalyzer.ZoomIn, WaveformAnalzyer.ZoomOut, WaveformAnalyzer.ZoomToFullSound, WaveformAnalyzer.ZoomToSelection. After zooming in and out, you can obtain the current sound's range displayed on the Waveform Analyzer calling the WaveformAnalyzer.GetDisplayRange method and to obtain the length of this range in milliseconds and pixels using the WaveformAnalyzer.GetDisplayWidth method. |
| • | through mouse acting directly on the tracker handles of one of the available horizontal scrollbars as seen on the picture below: |

Whenever a change occurs on the user interface, the container application is notified through one of the following events:
| • | WaveAnalyzerSelectionChange: this event occurs when a selection/deselection is performed |
| • | WaveAnalyzerDisplayRangeChange: this event occurs when a new range within the sound is displayed |
| • | WaveAnalyzerDisplayWidthChange: this event occurs when the control is resized horizontally |
The Waveform Analyzer automatically manages two vertical lines, one for displaying the current position during a playback session and another one for displaying a selection point: the look of these two lines can be modified trough the colorWavePositionLine and the colorWavePlaybackLine members of the WAVEFORM_ANALYZER_SETTINGS_2 data structure.
You have the possibility to add further vertical custom lines through the WaveformAnalyzer.VerticalLineAdd and WaveformAnalyzer.VerticalLineAddWithName methods and to remove them at a later time through the WaveformAnalyzer.VerticalLineRemove method: each custom line is identified by a unique identifier; once added, you can move/retrieve the position of custom lines through the WaveformAnalyzer.VerticalLineSetPosition and the WaveformAnalyzer.VerticalLineGetPosition methods; as a further feature you can also hide/show custom lines through the WaveformAnalyzer.VerticalLineShow method.
Vertical custom lines can be manually moved through the mouse; this action will generate the combination of the following events:
| • | WaveAnalyzerLineMoveBegin raised when the movement begins |
| • | WaveAnalyzerLineMoving raised during the movement of the line: you could receive many of these events in order to be up to date with the current line position |
| • | WaveAnalyzerLineMoveEnd raised when the movement ends |
During playback you can be notified that the position of a custom vertical line has been reached through the WaveAnalyzerLineReached event.
Custom vertical lines can be saved into a file for later usage through the WaveformAnalyzer.VerticalLinesSave method and retrieved at a later time through the WaveformAnalyzer.VerticalLinesLoad method.
In order to ease management of custom vertical lines through mouse interaction, you can catch the WaveAnalyzerMouseNotification event which reports the exact position where the mouse was pressed on the waveform: accurate positioning is guaranteed also when the waveform is zoomed. Mouse interaction can be enabled/disabled through the WaveformAnalyzer.MouseSelectionEnable method. During a playback session the mouse interaction is automatically disabled and an eventual call to this method will be ignored.
Each graphical element composing the Waveform Analyzer visualization is referenced by a specific rectangle on the screen: coordinates and dimensions of this rectangle, expressed in pixels, can be obtained through the WaveformAnalyzer.GetRectangle method.
Each time the graphical rendering of the Waveform Analyzer is completed, the container application receives a WaveAnalyzerPaintDone event: this event will pass as parameter the HWND of the Waveform Analyzer window, allowing to perform further custom graphic rendering on the Waveform Analyzer surface; for this purpose you can obtain the handle to the device context (HDC) of the Waveform Analyzer through the GetDC Windows API.
Mode 2:Creation of bitmaps in various graphic formats
After catching the WaveAnalysisDone event, it will be possible requesting to the control the creation of the waveform's bitmap through a call to the WaveformAnalyzer.BitmapViewSaveToFile and WaveformAnalyzer.BitmapViewSaveToMemory methods. It's important to note that the WaveAnalysisDone event will report the exact number of peaks detected inside the loaded sound and the exact duration in milliseconds of each peak. When generating the bitmap for the full sound's waveform, the reported number of peaks will be exactly equal to the width in pixels of the bitmap. In case you should create a view of a given sound's range, you could obtain the number of pixels needed to display the waveform's view through a call to the WaveformAnalyzer.BitmapViewGetWidth method.
The generated waveform's bitmap will be rendered using colors set into the colorWaveLine and colorWaveBackground properties of the WAVEFORM_ANALYZER_SETTINGS_2 data structure.
Below you can see five bitmaps generated using the same sound (whose duration is around 2.4 seconds length) but with five different resolutions (just for your information the song used for generating these bitmaps is available on this link); all these bitmaps have been created using the same height of 100 pixels:
Resolution set into the nResolution property |
Generated bitmap |
|
|
WAVEANALYZER_RES_MAXIMUM |
|
WAVEANALYZER_RES_VERY_HIGH |
|
WAVEANALYZER_RES_HIGH |
|
WAVEANALYZER_RES_MIDDLE |
|
WAVEANALYZER_RES_LOW |
|
As mentioned before, you can also generate a "view" of a defined portion of the loaded sound: on the bitmap below you can see the original song in its full length (with WAVEFORM_RES_MAXIMUM resolution)

and below you can see the view of the same song for the range between 500 and 1500 milliseconds

On the samples above we have used a very small song limited to 2.4 seconds: in case you should be in need of displaying the full waveform of a longer song on a space much smaller than the total number of required pixels, the WaveformAnalyzer.BitmapViewSaveToFile and WaveformAnalyzer.BitmapViewSaveToMemory methods will shrink the waveform in order to fit exactly inside the available space; in the example below you can see a 3 minutes song fitting inside a 455 pixels wide bitmap: the original full length bitmap, using the WAVEFORM_RES_MAXIMUM resolution, would require a width of 243,683 pixels.

VERY IMPORTANT: When using high resolutions and big sound files, keep count that the Windows operating system has limits on the size of bitmaps creation; this means that it would be better avoiding the creation of very large bitmaps: in this case it would be a better approach splitting the total song's bitmap into several smaller bitmaps, for example creating bitmaps whose width in pixels doesn't exceed the current screen width.
Mode 3: Rendering on a graphic Device Context (HDC)
After catching the WaveAnalysisDone event, it will be possible requesting to the control to render the waveform directly inside a graphical device context (through its handle or HDC); this is quite useful if you need to perform real-time rendering of the waveform on the screen for example for creating a scrolling waveform during playback.
In case you should create a view of a given sound's range, you could obtain the number of pixels needed to display the waveform's view through a call to the WaveformAnalyzer.BitmapViewGetWidth method.
The generated waveform's bitmap will be rendered using colors set into the colorWaveLine and colorWaveBackground properties of the WAVEFORM_ANALYZER_SETTINGS_2 data structure.
The rendering of the needed portion of sound can be performed through a call to the WaveformAnalyzer.BitmapViewDrawToHdc method. Positions determining the visible sound range can assume negative values for start and values higher respect to the effective sound duration: This allows displaying the current playback position on the center of the device context.
On the screenshots below you can see two portions of the same sound; in the first case the vertical white line (rendered through custom GDI+ inside the container applications' code) represents the position 0 ms of the song ranging from -5000 ms to +5000 ms; as you can see, the negative portion on the left, where no sound exists, is rendered as absence of audible sound.

In this seconds case the vertical white line represents the position 5000 ms of the song ranging from 0 ms to +10000 ms

As a further feature, vertical lines can be added/removed at specific positions through the WaveformAnalyzer.BitmapViewVerticalLineAdd and WaveformAnalyzer.BitmapViewVerticalLineRemove methods. Below an example of two vertical lines, rendered in red color, when the current center position of the bitmap view is set to 5000 ms.

Below the same exact red lines when the current center position has been moved to 6000 ms.

As you may understand, all of the features described above could be used to perform a custom rendering of a scrolling waveform during playback: what you would have to do would be:
| • | define a range to display, for example 10 seconds (10000 ms) |
| • | set a timer object, initially disabled, with a tick raised every 15 ms |
| • | inside the timer tick function: |
| ► | request the current playback position through the RecordedSound.GetPlaybackPosition method |
| ► | determine the rendering start position by subtracting 5000 ms to the current playback position and store it inside a variable named (for example) nStart |
| ► | determine the rendering end position by adding 5000 ms to the current playback position and store it inside a variable named nEnd |
| ► | call the WaveformAnalyzer.BitmapViewDrawToHdc method and set its nStartPos parameter to nStart and its nEndPos parameter to nEnd |
| • | after performing the sound analysis and catching the WaveAnalysisDone event you may enable the timer: the visible effect will be the waveform representation scrolling from right to left on the screen. |
In order to be able scrolling the waveform while playback is still not started, it's recommended that you enable pre-loading of the sound stream through the EnableSoundPreloadForPlayback method.
An example of usage of the solution described above can be seen inside the Dictation sample.