Qt 3D: Audio Visualizer Example

Demonstrates combining Qt 3D rendering and Qt Quick 2 elements.

Audio Visualizer demonstrates how to implement an application that combines the use of Qt 3D rendering with Qt Quick 2D elements. The example uses media player to play music and it visualizes the magnitude of the music as animated bars.

Running the Example

To run the example from Qt Creator, open the Welcome mode and select the example from Examples. For more information, visit Building and Running an Example.

Qt Quick 2D Implementation

The Qt Quick Implementation in audio-visualizer-qml/main.qml of the example uses MediaPlayer to play audio content.

 MediaPlayer {
     id: mediaPlayer
     autoPlay: true
     volume: 0.5
     source: "qrc:/music/tiltshifted_lost_neon_sun.mp3"

The player is controlled with the playButton and c{stopButton}. Based on the clicked buttons the state of the mainview changes.

The 3D content is rendered using the Scene3D type. The state of the Audio Visualizer is maintained in the mainview. It's passed on to the visualizer as it's needed for the bar animations.

 Scene3D {
     anchors.fill: parent

     Visualizer {
         id: visualizer
         animationState: mainview.state
         numberOfBars: 120
         barRotationTimeMs: 8160 // 68 ms per bar
     }
 }

Qt 3D Implementation

The 3D elements of the example are created in audio-visualizer-qml/Visualizer.qml. The camera is set to a fixed position to show the visualized bars from a correct angle.

 Camera {
     id: camera
     projectionType: CameraLens.PerspectiveProjection
     fieldOfView: 45
     aspectRatio: 1820 / 1080
     nearPlane: 0.1
     farPlane: 1000.0
     position: Qt.vector3d(0.014, 0.956, 2.178)
     upVector: Qt.vector3d(0.0, 1.0, 0.0)
     viewCenter: Qt.vector3d(0.0, 0.7, 0.0)
 }

A NodeInstantiator is used to create the bars that visualize the magnitude of the music.

 // Bars
 CuboidMesh {
     id: barMesh
     xExtent: 0.1
     yExtent: 0.1
     zExtent: 0.1
 }

 NodeInstantiator {
     id: collection
     property int maxCount: parent.numberOfBars
     model: maxCount

     delegate: BarEntity {
         id: cubicEntity
         entityMesh: barMesh
         rotationTimeMs: sceneRoot.barRotationTimeMs
         entityIndex: index
         entityCount: sceneRoot.numberOfBars
         entityAnimationsState: animationState
         magnitude: 0
     }
 }

The visualizer also contains an Entity to show the progress. This element has a curve shaped mesh and it's rotated on a level to show the progress based on the duration of the played track.

 // Progress
 Mesh {
     id: progressMesh
     source: "qrc:/meshes/progressbar.obj"
 }

 Transform {
     id: progressTransform
     property real defaultStartAngle: -90
     property real progressAngle: defaultStartAngle
     rotationY: progressAngle
 }

 Entity {
     property Material progressMaterial: PhongMaterial {
         ambient: "#80C342"
         diffuse: "black"
     }

     components: [progressMesh, progressMaterial, progressTransform]
 }

In audio-visualizer-qml/BarEntity.qml there are animations for rotating the bars and changing the bar color. The bars are rotated on a level following a ring form. At the same time the color of the bars is animated.

 QQ2.NumberAnimation {
     id: angleAnimation
     target: angleTransform
     property: "barAngle"
     duration: rotationTimeMs
     loops: QQ2.Animation.Infinite
     running: true
     from: startAngle
     to: 360 + startAngle
 }
 QQ2.SequentialAnimation on barColor {
     id: barColorAnimations
     running: false

     QQ2.ColorAnimation {
         from: lowColor
         to: highColor
         duration: animationDuration
     }

     QQ2.PauseAnimation {
         duration: animationDuration
     }

     QQ2.ColorAnimation {
         from: highColor
         to: lowColor
         duration: animationDuration
     }
 }

The magnitude of each bar is read from a separate .raw file that is based on the track being played. As the bars rotate around the ring the height is scaled to highlight currently played position. After a full round of rotation, a new value is fetched for the bar.

Example project @ code.qt.io