├── .gitignore ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── shaders ├── line.frag └── line.vert └── src ├── App.cpp ├── App.h ├── Audio.cpp ├── Audio.h ├── AudioBuffer.cpp ├── AudioBuffer.h ├── Line.cpp ├── Line.h ├── Renderer.cpp ├── Renderer.h ├── main.cpp └── miniaudio.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | CMakeSettings.json 7 | 8 | # User-specific files 9 | *.rsuser 10 | *.suo 11 | *.user 12 | *.userosscache 13 | *.sln.docstates 14 | 15 | # User-specific files (MonoDevelop/Xamarin Studio) 16 | *.userprefs 17 | 18 | # Mono auto generated files 19 | mono_crash.* 20 | 21 | # Build results 22 | [Dd]ebug/ 23 | [Dd]ebugPublic/ 24 | [Rr]elease/ 25 | [Rr]eleases/ 26 | x64/ 27 | x86/ 28 | [Aa][Rr][Mm]/ 29 | [Aa][Rr][Mm]64/ 30 | bld/ 31 | [Bb]in/ 32 | [Oo]bj/ 33 | [Ll]og/ 34 | [Bb]uild/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # StyleCop 67 | StyleCopReport.xml 68 | 69 | # Files built by Visual Studio 70 | *_i.c 71 | *_p.c 72 | *_h.h 73 | *.ilk 74 | *.meta 75 | *.obj 76 | *.iobj 77 | *.pch 78 | *.pdb 79 | *.ipdb 80 | *.pgc 81 | *.pgd 82 | *.rsp 83 | *.sbr 84 | *.tlb 85 | *.tli 86 | *.tlh 87 | *.tmp 88 | *.tmp_proj 89 | *_wpftmp.csproj 90 | *.log 91 | *.vspscc 92 | *.vssscc 93 | .builds 94 | *.pidb 95 | *.svclog 96 | *.scc 97 | 98 | # Chutzpah Test files 99 | _Chutzpah* 100 | 101 | # Visual C++ cache files 102 | ipch/ 103 | *.aps 104 | *.ncb 105 | *.opendb 106 | *.opensdf 107 | *.sdf 108 | *.cachefile 109 | *.VC.db 110 | *.VC.VC.opendb 111 | 112 | # Visual Studio profiler 113 | *.psess 114 | *.vsp 115 | *.vspx 116 | *.sap 117 | 118 | # Visual Studio Trace Files 119 | *.e2e 120 | 121 | # TFS 2012 Local Workspace 122 | $tf/ 123 | 124 | # Guidance Automation Toolkit 125 | *.gpState 126 | 127 | # ReSharper is a .NET coding add-in 128 | _ReSharper*/ 129 | *.[Rr]e[Ss]harper 130 | *.DotSettings.user 131 | 132 | # JustCode is a .NET coding add-in 133 | .JustCode 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Visual Studio code coverage results 146 | *.coverage 147 | *.coveragexml 148 | 149 | # NCrunch 150 | _NCrunch_* 151 | .*crunch*.local.xml 152 | nCrunchTemp_* 153 | 154 | # MightyMoose 155 | *.mm.* 156 | AutoTest.Net/ 157 | 158 | # Web workbench (sass) 159 | .sass-cache/ 160 | 161 | # Installshield output folder 162 | [Ee]xpress/ 163 | 164 | # DocProject is a documentation generator add-in 165 | DocProject/buildhelp/ 166 | DocProject/Help/*.HxT 167 | DocProject/Help/*.HxC 168 | DocProject/Help/*.hhc 169 | DocProject/Help/*.hhk 170 | DocProject/Help/*.hhp 171 | DocProject/Help/Html2 172 | DocProject/Help/html 173 | 174 | # Click-Once directory 175 | publish/ 176 | 177 | # Publish Web Output 178 | *.[Pp]ublish.xml 179 | *.azurePubxml 180 | # Note: Comment the next line if you want to checkin your web deploy settings, 181 | # but database connection strings (with potential passwords) will be unencrypted 182 | *.pubxml 183 | *.publishproj 184 | 185 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 186 | # checkin your Azure Web App publish settings, but sensitive information contained 187 | # in these scripts will be unencrypted 188 | PublishScripts/ 189 | 190 | # NuGet Packages 191 | *.nupkg 192 | # NuGet Symbol Packages 193 | *.snupkg 194 | # The packages folder can be ignored because of Package Restore 195 | **/[Pp]ackages/* 196 | # except build/, which is used as an MSBuild target. 197 | !**/[Pp]ackages/build/ 198 | # Uncomment if necessary however generally it will be regenerated when needed 199 | #!**/[Pp]ackages/repositories.config 200 | # NuGet v3's project.json files produces more ignorable files 201 | *.nuget.props 202 | *.nuget.targets 203 | 204 | # Microsoft Azure Build Output 205 | csx/ 206 | *.build.csdef 207 | 208 | # Microsoft Azure Emulator 209 | ecf/ 210 | rcf/ 211 | 212 | # Windows Store app package directories and files 213 | AppPackages/ 214 | BundleArtifacts/ 215 | Package.StoreAssociation.xml 216 | _pkginfo.txt 217 | *.appx 218 | *.appxbundle 219 | *.appxupload 220 | 221 | # Visual Studio cache files 222 | # files ending in .cache can be ignored 223 | *.[Cc]ache 224 | # but keep track of directories ending in .cache 225 | !?*.[Cc]ache/ 226 | 227 | # Others 228 | ClientBin/ 229 | ~$* 230 | *~ 231 | *.dbmdl 232 | *.dbproj.schemaview 233 | *.jfm 234 | *.pfx 235 | *.publishsettings 236 | orleans.codegen.cs 237 | 238 | # Including strong name files can present a security risk 239 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 240 | #*.snk 241 | 242 | # Since there are multiple workflows, uncomment next line to ignore bower_components 243 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 244 | #bower_components/ 245 | 246 | # RIA/Silverlight projects 247 | Generated_Code/ 248 | 249 | # Backup & report files from converting an old project file 250 | # to a newer Visual Studio version. Backup files are not needed, 251 | # because we have git ;-) 252 | _UpgradeReport_Files/ 253 | Backup*/ 254 | UpgradeLog*.XML 255 | UpgradeLog*.htm 256 | ServiceFabricBackup/ 257 | *.rptproj.bak 258 | 259 | # SQL Server files 260 | *.mdf 261 | *.ldf 262 | *.ndf 263 | 264 | # Business Intelligence projects 265 | *.rdl.data 266 | *.bim.layout 267 | *.bim_*.settings 268 | *.rptproj.rsuser 269 | *- [Bb]ackup.rdl 270 | *- [Bb]ackup ([0-9]).rdl 271 | *- [Bb]ackup ([0-9][0-9]).rdl 272 | 273 | # Microsoft Fakes 274 | FakesAssemblies/ 275 | 276 | # GhostDoc plugin setting file 277 | *.GhostDoc.xml 278 | 279 | # Node.js Tools for Visual Studio 280 | .ntvs_analysis.dat 281 | node_modules/ 282 | 283 | # Visual Studio 6 build log 284 | *.plg 285 | 286 | # Visual Studio 6 workspace options file 287 | *.opt 288 | 289 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 290 | *.vbw 291 | 292 | # Visual Studio LightSwitch build output 293 | **/*.HTMLClient/GeneratedArtifacts 294 | **/*.DesktopClient/GeneratedArtifacts 295 | **/*.DesktopClient/ModelManifest.xml 296 | **/*.Server/GeneratedArtifacts 297 | **/*.Server/ModelManifest.xml 298 | _Pvt_Extensions 299 | 300 | # Paket dependency manager 301 | .paket/paket.exe 302 | paket-files/ 303 | 304 | # FAKE - F# Make 305 | .fake/ 306 | 307 | # CodeRush personal settings 308 | .cr/personal 309 | 310 | # Python Tools for Visual Studio (PTVS) 311 | __pycache__/ 312 | *.pyc 313 | 314 | # Cake - Uncomment if you are using it 315 | # tools/** 316 | # !tools/packages.config 317 | 318 | # Tabs Studio 319 | *.tss 320 | 321 | # Telerik's JustMock configuration file 322 | *.jmconfig 323 | 324 | # BizTalk build output 325 | *.btp.cs 326 | *.btm.cs 327 | *.odx.cs 328 | *.xsd.cs 329 | 330 | # OpenCover UI analysis results 331 | OpenCover/ 332 | 333 | # Azure Stream Analytics local run output 334 | ASALocalRun/ 335 | 336 | # MSBuild Binary and Structured Log 337 | *.binlog 338 | 339 | # NVidia Nsight GPU debugger configuration file 340 | *.nvuser 341 | 342 | # MFractors (Xamarin productivity tool) working folder 343 | .mfractor/ 344 | 345 | # Local History for Visual Studio 346 | .localhistory/ 347 | 348 | # BeatPulse healthcheck temp database 349 | healthchecksdb 350 | 351 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 352 | MigrationBackup/ 353 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.8) 2 | 3 | project ("OscilloscopeMusic") 4 | 5 | set(GLFW_INCLUDE "" CACHE PATH "Path to GLFW include folder") 6 | set(GLFW_LIB "" CACHE FILEPATH "Path to GLFW binaries (must be Vulkan static)") 7 | set(VULKAN_INCLUDE "" CACHE PATH "Path to Vulkan include folder") 8 | set(VULKAN_LIB "" CACHE FILEPATH "Path to Vulkan binary") 9 | set(MINIAUDIO_PATH "" CACHE PATH "Path to miniaudio 0.10.35 root") 10 | set(VULKAN_WRAPPER_INCLUDE "" CACHE PATH "Path to Vulkan Wrapper (VKW) include folder") 11 | set(VULKAN_WRAPPER_LIB "" CACHE FILEPATH "Path to VKW binary") 12 | set(GLSL_COMPILER "" CACHE STRING "Command to execute Vulkan GLSL compiler") 13 | set(GLM_INCLUDE "" CACHE PATH "Path to GLM include folder") 14 | 15 | add_executable("OscilloscopeMusic" 16 | "src/main.cpp" 17 | "src/miniaudio.cpp" 18 | "src/App.h" 19 | "src/App.cpp" 20 | "src/Audio.h" 21 | "src/Audio.cpp" 22 | "src/Renderer.h" 23 | "src/Renderer.cpp" 24 | "src/Line.h" 25 | "src/Line.cpp" 26 | "src/AudioBuffer.h" 27 | "src/AudioBuffer.cpp" 28 | ) 29 | 30 | target_compile_features("OscilloscopeMusic" PRIVATE cxx_std_17) 31 | 32 | target_include_directories("OscilloscopeMusic" 33 | PUBLIC ${GLFW_INCLUDE} 34 | PUBLIC ${VULKAN_INCLUDE} 35 | PUBLIC ${MINIAUDIO_PATH} 36 | PUBLIC ${VULKAN_WRAPPER_INCLUDE} 37 | PUBLIC ${GLM_INCLUDE} 38 | ) 39 | 40 | target_link_libraries("OscilloscopeMusic" 41 | ${GLFW_LIB} 42 | ${VULKAN_LIB} 43 | ${VULKAN_WRAPPER_LIB} 44 | ) 45 | 46 | set(SHADER_SOURCES 47 | "shaders/line.vert" 48 | "shaders/line.frag" 49 | ) 50 | 51 | set(SHADER_BINARIES) 52 | 53 | foreach(SHADER_SOURCE ${SHADER_SOURCES}) 54 | get_filename_component(FILE_NAME ${SHADER_SOURCE} NAME) 55 | set(SPIRV "${PROJECT_BINARY_DIR}/shaders/${FILE_NAME}.spv") 56 | add_custom_command( 57 | OUTPUT ${SPIRV} 58 | COMMAND ${GLSL_COMPILER} "${PROJECT_SOURCE_DIR}/${SHADER_SOURCE}" -o ${SPIRV} 59 | DEPENDS ${SHADER_SOURCE}) 60 | list(APPEND SHADER_BINARIES ${SPIRV}) 61 | endforeach(SHADER_SOURCE) 62 | 63 | add_custom_target( 64 | CompileShaders 65 | DEPENDS ${SHADER_BINARIES} 66 | ) 67 | 68 | add_dependencies("OscilloscopeMusic" CompileShaders) -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Ryan Vazquez 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OscilloscopeMusic 2 | 3 | Oscilloscope music visualizer 4 | 5 | [Blog post describing how it works.](https://vazgriz.com/565/drawing-mushrooms-with-vulkan/) 6 | 7 | ![](https://i.imgur.com/8KQ9JNV.png) 8 | 9 | # Dependencies 10 | 11 | Library | Version | Link 12 | --------|---------|----- 13 | Vulkan SDK | 1.2 | https://vulkan.lunarg.com/ 14 | Vulkan Wrapper | Latest | https://github.com/vazgriz/VulkanWrapper 15 | GLFW | 3.2 | https://github.com/glfw/glfw 16 | Miniaudio | Latest | https://github.com/mackron/miniaudio 17 | GLM | 0.9.9.8 | https://github.com/g-truc/glm 18 | -------------------------------------------------------------------------------- /shaders/line.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | 4 | layout(location = 0) in vec2 fragLineCenter; 5 | layout(location = 1) in vec2 fragWidthAlpha; 6 | 7 | layout(location = 0) out vec4 outColor; 8 | 9 | layout(binding = 0) uniform UBO { 10 | mat4 proj; 11 | vec4 colorWidth; 12 | vec2 screenSize; 13 | } ubo; 14 | 15 | void main() { 16 | //calculate SDF value for pixel for anti aliasing 17 | float dist = length(fragLineCenter - gl_FragCoord.xy); 18 | float width = fragWidthAlpha.x * ubo.colorWidth.w; 19 | float alpha = clamp(width - dist, 0, 1); 20 | 21 | //output final color 22 | //alpha depends on SDF value, length, and persistence 23 | float lengthFactor = clamp(fragWidthAlpha.x, 0, 1); 24 | outColor = vec4(ubo.colorWidth.xyz, alpha * lengthFactor * fragWidthAlpha.y); 25 | } -------------------------------------------------------------------------------- /shaders/line.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | 4 | layout(location = 0) in vec4 inPosAlpha; 5 | layout(location = 1) in vec4 inNormalWidth; 6 | 7 | layout(location = 0) out vec2 fragLineCenter; 8 | layout(location = 1) out vec2 fragWidthAlpha; 9 | 10 | layout(binding = 0) uniform UBO { 11 | mat4 proj; 12 | vec4 colorWidth; 13 | vec2 screenSize; 14 | } ubo; 15 | 16 | void main() { 17 | //expand vertices along normals 18 | gl_Position = ubo.proj * vec4(inPosAlpha.xyz + inNormalWidth.xyz * ubo.colorWidth.w * inNormalWidth.w, 1.0); 19 | 20 | //calculate where the center of each line segment is (project without expanding) 21 | vec2 clip = (ubo.proj * vec4(inPosAlpha.xy, 0.0, 1.0)).xy; 22 | fragLineCenter = ((clip + vec2(1.0, 1.0)) / 2.0) * ubo.screenSize; 23 | 24 | //pass width and alpha 25 | fragWidthAlpha = vec2(inNormalWidth.w, inPosAlpha.w * inNormalWidth.w); 26 | } -------------------------------------------------------------------------------- /src/App.cpp: -------------------------------------------------------------------------------- 1 | #include "App.h" 2 | #include 3 | 4 | #define SAMPLES_PER_FRAME (SAMPLE_RATE / 60) 5 | #define PERSISTENCE 4 6 | 7 | App::App(GLFWwindow* window, const char* filename) : m_audioBuffer(SAMPLES_PER_FRAME * PERSISTENCE) { 8 | m_paused = false; 9 | m_iconified = false; 10 | m_persistentFrame = 0; 11 | 12 | glfwSetWindowUserPointer(window, this); 13 | 14 | auto result = ma_pcm_rb_init(ma_format_f32, 2, SAMPLES_PER_FRAME * 2, nullptr, nullptr, &m_rawBuffer); 15 | 16 | m_audio = std::make_unique