├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── screenshots ├── 1-1.png ├── 1-2.png ├── 2-1.png ├── 2-2.png ├── 3-1.png ├── 3-2.png ├── 4-1.png └── 4-2.png ├── shaders ├── FragmentShader.frag ├── GeometryShader.geom └── VertexShader.vert └── source ├── audio_data ├── audio_data.cpp └── audio_data.hpp ├── common ├── controls.cpp ├── controls.hpp ├── load_shaders.cpp ├── load_shaders.hpp ├── objloader.cpp ├── objloader.hpp ├── quaternion_utils.cpp ├── quaternion_utils.hpp ├── shader.cpp ├── shader.hpp ├── tangentspace.cpp ├── tangentspace.hpp ├── text2D.cpp ├── text2D.hpp ├── texture.cpp ├── texture.hpp ├── vboindexer.cpp └── vboindexer.hpp ├── fft ├── fft.cpp └── fft.hpp ├── play_wav ├── play_wav.cpp └── play_wav.hpp └── waveform.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # Directory 31 | build/ 32 | 33 | # Target 34 | waveform 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GLFW = `pkg-config --cflags glfw3` `pkg-config --libs --static glfw3` 2 | GLEW = `pkg-config --cflags glew` `pkg-config --libs glew` 3 | LIBRARY = -lasound -lpthread 4 | INCLUDE = -I$(SOURCE_PATH) -I/usr/local/include/GLFW/ 5 | MACRO = -D_REENTRANT 6 | 7 | BINARY = waveform 8 | SOURCE_PATH = source/ 9 | BUILD_PATH = ./ 10 | HPP = \ 11 | $(SOURCE_PATH)common/shader.hpp \ 12 | $(SOURCE_PATH)common/objloader.hpp \ 13 | $(SOURCE_PATH)common/controls.hpp \ 14 | $(SOURCE_PATH)audio_data/audio_data.hpp \ 15 | $(SOURCE_PATH)play_wav/play_wav.hpp \ 16 | $(SOURCE_PATH)fft/fft.hpp 17 | CPP = \ 18 | $(SOURCE_PATH)common/shader.cpp \ 19 | $(SOURCE_PATH)common/objloader.cpp \ 20 | $(SOURCE_PATH)common/controls.cpp \ 21 | $(SOURCE_PATH)audio_data/audio_data.cpp \ 22 | $(SOURCE_PATH)play_wav/play_wav.cpp \ 23 | $(SOURCE_PATH)waveform.cpp \ 24 | $(SOURCE_PATH)fft/fft.cpp 25 | 26 | TARGET = $(BUILD_PATH)$(BINARY) 27 | 28 | all: $(TARGET) 29 | 30 | $(TARGET): $(CPP) $(HPP) 31 | clang++ $(CPP) -o $(TARGET) $(GLFW) $(GLEW) $(LIBRARY) $(INCLUDE) $(MACRO) 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Audio-Visualization---Waveform 2 | 3 | An audio visualizer. 4 | 5 | Repository: [Audio-Visualization---Waveform](https://github.com/chaosink/Audio-Visualization---Waveform) 6 | 7 | `WAV(16 bits, 2 channels)` files supported only for now. 8 | 9 | Visualized by `GLSL`. 10 | 11 | Video on Youtube: 12 | * [Audio-Visualization---Waveform, Spectrum, Level](https://youtu.be/7LfaSCFfXek) 13 | * [Audio-Visualization---Waveform, Spectrum, Sine](http://youtu.be/M1vgzOlViHw) 14 | * [Audio-Viusalization---Columned-Spectrum](https://youtu.be/Oxa4EXfW8GY) 15 | * [Audio-Visualization---Dot-Circle-Spectrum](https://youtu.be/zAzh2CJGibc) 16 | 17 | Video on Youku: 18 | * [Audio-Visualization---Waveform, Spectrum, Level](http://v.youku.com/v_show/id_XMTI5MjcxMDQwMA==.html) 19 | * [Audio-Visualization---Waveform, Spectrum, Sine](http://v.youku.com/v_show/id_XMTI5Mjc5MDg2NA==.html) 20 | * [Audio-Viusalization---Columned-Spectrumm](http://v.youku.com/v_show/id_XMTI5Mjg0MDkxNg==.html) 21 | * [Audio-Visualization---Dot-Circle-Spectrum](http://v.youku.com/v_show/id_XMTI5Mjg2Mjc2MA==.html) 22 | 23 | ## Compiling 24 | ```shell 25 | make 26 | ``` 27 | 28 | ## Usage 29 | ```shell 30 | ./waveform your_wav.wav 31 | ``` 32 | 33 | ## Dependencies 34 | [OpenGL - The Industry's Foundation for High Performance Graphics](https://www.opengl.org/) 35 | 36 | [GLFW - An OpenGL library](http://www.glfw.org/) 37 | 38 | [GLEW - The OpenGL Extension Wrangler Library](http://glew.sourceforge.net/) 39 | 40 | [GLM - OpenGL Mathematics](http://glm.g-truc.net/0.9.6/index.html) 41 | 42 | [ALSA - Advanced Linux Sound Architecture](http://www.alsa-project.org/main/index.php/Main_Page) 43 | 44 | ## Screenshots 45 | Spectrum, waveform, level 46 | ![1-1.png](./screenshots/1-1.png) 47 | 48 | ![1-2.png](./screenshots/1-2.png) 49 | 50 | Spectrum, waveform, sine 51 | ![2-1.png](./screenshots/2-1.png) 52 | 53 | ![2-2.png](./screenshots/2-2.png) 54 | 55 | Spectrum-circle 56 | ![3-1.png](./screenshots/3-1.png) 57 | 58 | ![3-2.png](./screenshots/3-2.png) 59 | 60 | Spectrum-column 61 | ![4-1.png](./screenshots/4-1.png) 62 | 63 | ![4-2.png](./screenshots/4-2.png) 64 | -------------------------------------------------------------------------------- /screenshots/1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaosink/Audio-Visualization---Waveform/b7a87786abd91551ebdca9c3f3ef2d385c6a2479/screenshots/1-1.png -------------------------------------------------------------------------------- /screenshots/1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaosink/Audio-Visualization---Waveform/b7a87786abd91551ebdca9c3f3ef2d385c6a2479/screenshots/1-2.png -------------------------------------------------------------------------------- /screenshots/2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaosink/Audio-Visualization---Waveform/b7a87786abd91551ebdca9c3f3ef2d385c6a2479/screenshots/2-1.png -------------------------------------------------------------------------------- /screenshots/2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaosink/Audio-Visualization---Waveform/b7a87786abd91551ebdca9c3f3ef2d385c6a2479/screenshots/2-2.png -------------------------------------------------------------------------------- /screenshots/3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaosink/Audio-Visualization---Waveform/b7a87786abd91551ebdca9c3f3ef2d385c6a2479/screenshots/3-1.png -------------------------------------------------------------------------------- /screenshots/3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaosink/Audio-Visualization---Waveform/b7a87786abd91551ebdca9c3f3ef2d385c6a2479/screenshots/3-2.png -------------------------------------------------------------------------------- /screenshots/4-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaosink/Audio-Visualization---Waveform/b7a87786abd91551ebdca9c3f3ef2d385c6a2479/screenshots/4-1.png -------------------------------------------------------------------------------- /screenshots/4-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaosink/Audio-Visualization---Waveform/b7a87786abd91551ebdca9c3f3ef2d385c6a2479/screenshots/4-2.png -------------------------------------------------------------------------------- /shaders/FragmentShader.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | in vec3 fragmentColor; 4 | 5 | out vec3 color; 6 | 7 | void main() { 8 | color = fragmentColor; 9 | } 10 | -------------------------------------------------------------------------------- /shaders/GeometryShader.geom: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | //layout(lines) in; 4 | //layout(line_strip, max_vertices = 2) out; 5 | layout(triangles) in; 6 | layout(triangle_strip, max_vertices = 300) out; 7 | 8 | uniform mat4 MVP; 9 | 10 | in vec3 fragmentColor[]; 11 | out vec3 Color; 12 | 13 | float size = 4.0; 14 | int num = 5; 15 | 16 | void main() { 17 | for(int k = -5; k < num; k++) 18 | for(int j = -5; j < num; j++) { 19 | for(int i = 0; i < gl_in.length(); ++i) { 20 | gl_Position = gl_in[i].gl_Position + vec4( size * j + size / 2, size * k + size / 2, 0.0, 0.0); 21 | Color = fragmentColor[i]; 22 | EmitVertex(); 23 | } 24 | EndPrimitive(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /shaders/VertexShader.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(location = 0) in vec3 vertexPosition_modelspace; 4 | layout(location = 1) in vec3 vertexColor; 5 | layout(location = 2) in float z; 6 | 7 | out vec3 fragmentColor; 8 | 9 | uniform mat4 MVP; 10 | uniform int object; 11 | uniform float top; 12 | 13 | int color_factor = 4; 14 | float size_factor = 0.01; 15 | float size_factor1 = 0.1; 16 | int wave_height = 5; 17 | 18 | bool zhuangbi = true; 19 | #define ZHUANGBI 20 | 21 | void main() { 22 | mat4 scale = mat4( 23 | size_factor, 0.0, 0.0, 0.0, 24 | 0.0, 1.0, 0.0, 0.0, 25 | 0.0, 0.0, size_factor, 0.0, 26 | 0.0, 0.0, 0.0, 1.0); 27 | mat4 scale1 = mat4( 28 | size_factor1, 0.0, 0.0, 0.0, 29 | 0.0, 1.0, 0.0, 0.0, 30 | 0.0, 0.0, size_factor1, 0.0, 31 | 0.0, 0.0, 0.0, 1.0); 32 | switch(object) { 33 | #ifdef ZHUANGBI 34 | case 0: //left column 35 | gl_Position = MVP * scale * vec4(vertexPosition_modelspace, 1); 36 | break; 37 | case 1: //right column 38 | gl_Position = MVP * scale * vec4(vertexPosition_modelspace, 1); 39 | break; 40 | #endif 41 | case 2: //left wave 42 | gl_Position = MVP * vec4(-5.0, vertexPosition_modelspace.x / 32768 * wave_height, z, 1); 43 | break; 44 | case 3: //right wave 45 | gl_Position = MVP * vec4( 5.0, vertexPosition_modelspace.x / 32768 * wave_height, z, 1); 46 | break; 47 | case 4: //left top 48 | gl_Position = MVP * vec4(vertexPosition_modelspace, 1); 49 | break; 50 | case 5: //right top 51 | gl_Position = MVP * vec4(vertexPosition_modelspace, 1); 52 | break; 53 | case 6: //spectrum 54 | gl_Position = MVP * vec4(0, vertexPosition_modelspace.x, z, 1); 55 | break; 56 | default: 57 | gl_Position = MVP * vec4(vertexPosition_modelspace, 1); 58 | break; 59 | } 60 | 61 | switch(object) { 62 | case 0: //left column 63 | fragmentColor = zhuangbi ? vec3(1.0, gl_Position.y / color_factor, gl_Position.y / color_factor) : vertexColor; 64 | break; 65 | case 1: //right column 66 | fragmentColor = zhuangbi ? vec3(gl_Position.y / color_factor, gl_Position.y / color_factor, 1.0) : vertexColor; 67 | break; 68 | case 2: //left wave 69 | fragmentColor = zhuangbi ? vec3(vertexPosition_modelspace.x / 32768 * 0.8 + 0.2, (z + 10.0) / 20.0, 0.5) : vec3(1.0, 0.5, 0.5); 70 | break; 71 | case 3: //right wave 72 | fragmentColor = zhuangbi ? vec3(0.5, (z + 10.0) / 20.0, vertexPosition_modelspace.x / 32768 * 0.8 + 0.2) : vec3(0.5, 0.5, 1.0); 73 | break; 74 | case 4: //left top (1.0 - pow(gl_Position.w, 2) / color_factor) * 0.7 + 0.3 75 | fragmentColor = vec3(1.0, top / 2, top / 2); 76 | break; 77 | case 5: //right top 78 | fragmentColor = vec3(top / 2, top / 2, 1.0); 79 | break; 80 | case 6: //spectrum log(vertexPosition_modelspace.x + 1) / 3 * 0.8 + 0.2 81 | fragmentColor = vec3(abs(z) / 10.0, (z + 10.0)/ 20.0, (log(vertexPosition_modelspace.x + 1) / 3 * 0.8) * (z + 10) / 5 + 0.2); 82 | break; 83 | default: 84 | fragmentColor = vec3(1.0, 1.0, 1.0); 85 | break; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /source/audio_data/audio_data.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "audio_data.hpp" 4 | 5 | struct WAV_HEADER 6 | { 7 | char rld[4]; //riff 标志符号 8 | int rLen; 9 | char wld[4]; //格式类型(wave) 10 | char fld[4]; //"fmt" 11 | int fLen; //sizeof(wave format matex) 12 | short wFormatTag; //编码格式 13 | short wChannels; //声道数 14 | int nSamplesPersec ; //采样频率 15 | int nAvgBitsPerSample;//WAVE文件采样大小 16 | short wBlockAlign; //块对齐 17 | short wBitsPerSample; //WAVE文件采样大小 18 | char dld[4]; //”data“ 19 | int wSampleLength; //音频数据的大小 20 | } wav_header; 21 | 22 | struct audio_data get_audio_data(char *file) { 23 | int nread; 24 | FILE *fp = fopen(file, "rb"); 25 | nread = fread(&wav_header, 1, sizeof(wav_header), fp); 26 | struct audio_data data; 27 | data.size = wav_header.rLen - 36; 28 | data.sampling_rate = wav_header.nSamplesPersec; 29 | data.data = malloc(data.size); 30 | fseek(fp, 44, SEEK_SET); 31 | nread = fread(data.data, data.size, 1, fp); 32 | fclose(fp); 33 | return data; 34 | } 35 | -------------------------------------------------------------------------------- /source/audio_data/audio_data.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __AUDIO_DATA__ 2 | #define __AUDIO_DATA__ 3 | 4 | struct audio_data { 5 | int size; 6 | int sampling_rate; 7 | void* data; 8 | }; 9 | 10 | struct audio_data get_audio_data(char *file); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /source/common/controls.cpp: -------------------------------------------------------------------------------- 1 | // Include GLFW 2 | #include 3 | extern GLFWwindow* window; // The "extern" keyword here is to access the variable "window" declared in tutorialXXX.cpp. This is a hack to keep the tutorials simple. Please avoid this. 4 | 5 | // Include GLM 6 | #include 7 | #include 8 | using namespace glm; 9 | 10 | #include "controls.hpp" 11 | 12 | glm::mat4 ViewMatrix; 13 | glm::mat4 ProjectionMatrix; 14 | 15 | glm::mat4 getViewMatrix(){ 16 | return ViewMatrix; 17 | } 18 | glm::mat4 getProjectionMatrix(){ 19 | return ProjectionMatrix; 20 | } 21 | 22 | 23 | // Initial position : on +Z 24 | glm::vec3 position = glm::vec3( 0, 0, 5 ); 25 | // Initial horizontal angle : toward -Z 26 | float horizontalAngle = 3.14f; 27 | // Initial vertical angle : none 28 | float verticalAngle = 0.0f; 29 | // Initial Field of View 30 | float initialFoV = 45.0f; 31 | 32 | float speed = 5.0f; // 3 units / second 33 | float mouseSpeed = 0.002f; 34 | 35 | double time = 0.0f; 36 | float radius = 20.0f; 37 | float height = 10.0f; 38 | float surround_speed = 0.2f; 39 | 40 | void computeMatricesFromInputs(){ 41 | 42 | // glfwGetTime is called only once, the first time this function is called 43 | static double lastTime = glfwGetTime(); 44 | 45 | // Compute time difference between current and last frame 46 | double currentTime = glfwGetTime(); 47 | float deltaTime = float(currentTime - lastTime); 48 | 49 | // Get mouse position 50 | double xpos, ypos; 51 | glfwGetCursorPos(window, &xpos, &ypos); 52 | 53 | // Reset mouse position for next frame 54 | // glfwSetCursorPos(window, 1024/2, 768/2); 55 | 56 | // Compute new orientation 57 | horizontalAngle += mouseSpeed * float(xpos - 1024/2); 58 | verticalAngle += mouseSpeed * float(768/2 - ypos); 59 | 60 | // Direction : Spherical coordinates to Cartesian coordinates conversion 61 | glm::vec3 direction( 62 | cos(verticalAngle) * sin(horizontalAngle), 63 | sin(verticalAngle), 64 | cos(verticalAngle) * cos(horizontalAngle) 65 | ); 66 | 67 | // Right vector 68 | glm::vec3 right = glm::vec3( 69 | sin(horizontalAngle - 3.14f/2.0f), 70 | 0, 71 | cos(horizontalAngle - 3.14f/2.0f) 72 | ); 73 | 74 | // Up vector 75 | glm::vec3 up = glm::cross( right, direction ); 76 | 77 | // Move forward 78 | if (glfwGetKey( window, GLFW_KEY_UP ) == GLFW_PRESS){ 79 | position += direction * deltaTime * speed; 80 | } 81 | // Move backward 82 | if (glfwGetKey( window, GLFW_KEY_DOWN ) == GLFW_PRESS){ 83 | position -= direction * deltaTime * speed; 84 | } 85 | // Strafe right 86 | if (glfwGetKey( window, GLFW_KEY_RIGHT ) == GLFW_PRESS){ 87 | position += right * deltaTime * speed; 88 | } 89 | // Strafe left 90 | if (glfwGetKey( window, GLFW_KEY_LEFT ) == GLFW_PRESS){ 91 | position -= right * deltaTime * speed; 92 | } 93 | 94 | float FoV = initialFoV;// - 5 * glfwGetMouseWheel(); // Now GLFW 3 requires setting up a callback for this. It's a bit too complicated for this beginner's tutorial, so it's disabled instead. 95 | 96 | // Projection matrix : 45° Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units 97 | ProjectionMatrix = glm::perspective(FoV, 4.0f / 3.0f, 0.1f, 100.0f); 98 | // Camera matrix 99 | time = glfwGetTime(); 100 | position = vec3(radius * cos(time * surround_speed ), height, radius * sin(time * surround_speed)); 101 | ViewMatrix = glm::lookAt( 102 | position, // Camera is here 103 | vec3(0,0,0),//position+direction, // and looks here : at the same position, plus "direction" 104 | vec3(0,1,0) //up // Head is up (set to 0,-1,0 to look upside-down) 105 | ); 106 | 107 | // For the next frame, the "last time" will be "now" 108 | lastTime = currentTime; 109 | } -------------------------------------------------------------------------------- /source/common/controls.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONTROLS_HPP 2 | #define CONTROLS_HPP 3 | 4 | void computeMatricesFromInputs(); 5 | glm::mat4 getViewMatrix(); 6 | glm::mat4 getProjectionMatrix(); 7 | 8 | #endif -------------------------------------------------------------------------------- /source/common/load_shaders.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // --- LoadShaders.cxx --- 4 | // 5 | ////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #define GLEW_STATIC 12 | #include 13 | #include "load_shaders.hpp" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif // __cplusplus 18 | 19 | //---------------------------------------------------------------------------- 20 | 21 | static const GLchar* 22 | ReadShader( const char* filename ) 23 | { 24 | #ifdef WIN32 25 | FILE* infile; 26 | fopen_s( &infile, filename, "rb" ); 27 | #else 28 | FILE* infile = fopen( filename, "rb" ); 29 | #endif // WIN32 30 | 31 | if ( !infile ) { 32 | #ifdef _DEBUG 33 | std::cerr << "Unable to open file '" << filename << "'" << std::endl; 34 | #endif /* DEBUG */ 35 | return NULL; 36 | } 37 | 38 | fseek( infile, 0, SEEK_END ); 39 | int len = ftell( infile ); 40 | fseek( infile, 0, SEEK_SET ); 41 | 42 | GLchar* source = new GLchar[len+1]; 43 | 44 | fread( source, 1, len, infile ); 45 | fclose( infile ); 46 | 47 | source[len] = 0; 48 | 49 | return const_cast(source); 50 | } 51 | 52 | //---------------------------------------------------------------------------- 53 | 54 | GLuint 55 | LoadShaders( ShaderInfo* shaders ) 56 | { 57 | if ( shaders == NULL ) { return 0; } 58 | 59 | GLuint program = glCreateProgram(); 60 | 61 | ShaderInfo* entry = shaders; 62 | while ( entry->type != GL_NONE ) { 63 | GLuint shader = glCreateShader( entry->type ); 64 | 65 | entry->shader = shader; 66 | 67 | const GLchar* source = ReadShader( entry->filename ); 68 | if ( source == NULL ) { 69 | for ( entry = shaders; entry->type != GL_NONE; ++entry ) { 70 | glDeleteShader( entry->shader ); 71 | entry->shader = 0; 72 | } 73 | 74 | return 0; 75 | } 76 | 77 | glShaderSource( shader, 1, &source, NULL ); 78 | delete [] source; 79 | 80 | glCompileShader( shader ); 81 | 82 | GLint compiled; 83 | glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled ); 84 | if ( !compiled ) { 85 | #ifdef _DEBUG 86 | GLsizei len; 87 | glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &len ); 88 | 89 | GLchar* log = new GLchar[len+1]; 90 | glGetShaderInfoLog( shader, len, &len, log ); 91 | std::cerr << "Shader compilation failed: " << log << std::endl; 92 | delete [] log; 93 | #endif /* DEBUG */ 94 | 95 | return 0; 96 | } 97 | 98 | glAttachShader( program, shader ); 99 | 100 | ++entry; 101 | } 102 | 103 | #ifdef GL_VERSION_4_1 104 | if ( GLEW_VERSION_4_1 ) { 105 | // glProgramParameteri( program, GL_PROGRAM_SEPARABLE, GL_TRUE ); 106 | } 107 | #endif /* GL_VERSION_4_1 */ 108 | 109 | glLinkProgram( program ); 110 | 111 | GLint linked; 112 | glGetProgramiv( program, GL_LINK_STATUS, &linked ); 113 | if ( !linked ) { 114 | #ifdef _DEBUG 115 | GLsizei len; 116 | glGetProgramiv( program, GL_INFO_LOG_LENGTH, &len ); 117 | 118 | GLchar* log = new GLchar[len+1]; 119 | glGetProgramInfoLog( program, len, &len, log ); 120 | std::cerr << "Shader linking failed: " << log << std::endl; 121 | delete [] log; 122 | #endif /* DEBUG */ 123 | 124 | for ( entry = shaders; entry->type != GL_NONE; ++entry ) { 125 | glDeleteShader( entry->shader ); 126 | entry->shader = 0; 127 | } 128 | 129 | return 0; 130 | } 131 | 132 | return program; 133 | } 134 | 135 | //---------------------------------------------------------------------------- 136 | #ifdef __cplusplus 137 | } 138 | #endif // __cplusplus 139 | 140 | 141 | -------------------------------------------------------------------------------- /source/common/load_shaders.hpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // --- LoadShaders.h --- 4 | // 5 | ////////////////////////////////////////////////////////////////////////////// 6 | 7 | #ifndef __LOAD_SHADERS_H__ 8 | #define __LOAD_SHADERS_H__ 9 | 10 | #include 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif // __cplusplus 15 | 16 | //---------------------------------------------------------------------------- 17 | // 18 | // LoadShaders() takes an array of ShaderFile structures, each of which 19 | // contains the type of the shader, and a pointer a C-style character 20 | // string (i.e., a NULL-terminated array of characters) containing the 21 | // entire shader source. 22 | // 23 | // The array of structures is terminated by a final Shader with the 24 | // "type" field set to GL_NONE. 25 | // 26 | // LoadShaders() returns the shader program value (as returned by 27 | // glCreateProgram()) on success, or zero on failure. 28 | // 29 | 30 | typedef struct { 31 | GLenum type; 32 | const char* filename; 33 | GLuint shader; 34 | } ShaderInfo; 35 | 36 | GLuint LoadShaders( ShaderInfo* ); 37 | 38 | //---------------------------------------------------------------------------- 39 | 40 | #ifdef __cplusplus 41 | }; 42 | #endif // __cplusplus 43 | 44 | #endif // __LOAD_SHADERS_H__ 45 | -------------------------------------------------------------------------------- /source/common/objloader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "objloader.hpp" 9 | 10 | // Very, VERY simple OBJ loader. 11 | // Here is a short list of features a real function would provide : 12 | // - Binary files. Reading a model should be just a few memcpy's away, not parsing a file at runtime. In short : OBJ is not very great. 13 | // - Animations & bones (includes bones weights) 14 | // - Multiple UVs 15 | // - All attributes should be optional, not "forced" 16 | // - More stable. Change a line in the OBJ file and it crashes. 17 | // - More secure. Change another line and you can inject code. 18 | // - Loading from memory, stream, etc 19 | 20 | bool loadOBJ( 21 | const char * path, 22 | std::vector & out_vertices, 23 | std::vector & out_uvs, 24 | std::vector & out_normals 25 | ){ 26 | printf("Loading OBJ file %s...\n", path); 27 | 28 | std::vector vertexIndices, uvIndices, normalIndices; 29 | std::vector temp_vertices; 30 | std::vector temp_uvs; 31 | std::vector temp_normals; 32 | 33 | 34 | FILE * file = fopen(path, "r"); 35 | if( file == NULL ){ 36 | printf("Impossible to open the file ! Are you in the right path ? See Tutorial 1 for details\n"); 37 | getchar(); 38 | return false; 39 | } 40 | 41 | while( 1 ){ 42 | 43 | char lineHeader[128]; 44 | // read the first word of the line 45 | int res = fscanf(file, "%s", lineHeader); 46 | if (res == EOF) 47 | break; // EOF = End Of File. Quit the loop. 48 | 49 | // else : parse lineHeader 50 | 51 | if ( strcmp( lineHeader, "v" ) == 0 ){ 52 | glm::vec3 vertex; 53 | fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z ); 54 | temp_vertices.push_back(vertex); 55 | }else if ( strcmp( lineHeader, "vt" ) == 0 ){ 56 | glm::vec2 uv; 57 | fscanf(file, "%f %f\n", &uv.x, &uv.y ); 58 | uv.y = -uv.y; // Invert V coordinate since we will only use DDS texture, which are inverted. Remove if you want to use TGA or BMP loaders. 59 | temp_uvs.push_back(uv); 60 | }else if ( strcmp( lineHeader, "vn" ) == 0 ){ 61 | glm::vec3 normal; 62 | fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z ); 63 | temp_normals.push_back(normal); 64 | }else if ( strcmp( lineHeader, "f" ) == 0 ){ 65 | std::string vertex1, vertex2, vertex3; 66 | unsigned int vertexIndex[3], uvIndex[3], normalIndex[3]; 67 | int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2] ); 68 | if (matches != 9){ 69 | printf("File can't be read by our simple parser :-( Try exporting with other options\n"); 70 | return false; 71 | } 72 | vertexIndices.push_back(vertexIndex[0]); 73 | vertexIndices.push_back(vertexIndex[1]); 74 | vertexIndices.push_back(vertexIndex[2]); 75 | uvIndices .push_back(uvIndex[0]); 76 | uvIndices .push_back(uvIndex[1]); 77 | uvIndices .push_back(uvIndex[2]); 78 | normalIndices.push_back(normalIndex[0]); 79 | normalIndices.push_back(normalIndex[1]); 80 | normalIndices.push_back(normalIndex[2]); 81 | }else{ 82 | // Probably a comment, eat up the rest of the line 83 | char stupidBuffer[1000]; 84 | fgets(stupidBuffer, 1000, file); 85 | } 86 | 87 | } 88 | 89 | // For each vertex of each triangle 90 | for( unsigned int i=0; i // C++ importer interface 117 | #include // Output data structure 118 | #include // Post processing flags 119 | 120 | bool loadAssImp( 121 | const char * path, 122 | std::vector & indices, 123 | std::vector & vertices, 124 | std::vector & uvs, 125 | std::vector & normals 126 | ){ 127 | 128 | Assimp::Importer importer; 129 | 130 | const aiScene* scene = importer.ReadFile(path, 0/*aiProcess_JoinIdenticalVertices | aiProcess_SortByPType*/); 131 | if( !scene) { 132 | fprintf( stderr, importer.GetErrorString()); 133 | getchar(); 134 | return false; 135 | } 136 | const aiMesh* mesh = scene->mMeshes[0]; // In this simple example code we always use the 1rst mesh (in OBJ files there is often only one anyway) 137 | 138 | // Fill vertices positions 139 | vertices.reserve(mesh->mNumVertices); 140 | for(unsigned int i=0; imNumVertices; i++){ 141 | aiVector3D pos = mesh->mVertices[i]; 142 | vertices.push_back(glm::vec3(pos.x, pos.y, pos.z)); 143 | } 144 | 145 | // Fill vertices texture coordinates 146 | uvs.reserve(mesh->mNumVertices); 147 | for(unsigned int i=0; imNumVertices; i++){ 148 | aiVector3D UVW = mesh->mTextureCoords[0][i]; // Assume only 1 set of UV coords; AssImp supports 8 UV sets. 149 | uvs.push_back(glm::vec2(UVW.x, UVW.y)); 150 | } 151 | 152 | // Fill vertices normals 153 | normals.reserve(mesh->mNumVertices); 154 | for(unsigned int i=0; imNumVertices; i++){ 155 | aiVector3D n = mesh->mNormals[i]; 156 | normals.push_back(glm::vec3(n.x, n.y, n.z)); 157 | } 158 | 159 | 160 | // Fill face indices 161 | indices.reserve(3*mesh->mNumFaces); 162 | for (unsigned int i=0; imNumFaces; i++){ 163 | // Assume the model has only triangles. 164 | indices.push_back(mesh->mFaces[i].mIndices[0]); 165 | indices.push_back(mesh->mFaces[i].mIndices[1]); 166 | indices.push_back(mesh->mFaces[i].mIndices[2]); 167 | } 168 | 169 | // The "scene" pointer will be deleted automatically by "importer" 170 | 171 | } 172 | 173 | #endif -------------------------------------------------------------------------------- /source/common/objloader.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OBJLOADER_H 2 | #define OBJLOADER_H 3 | 4 | bool loadOBJ( 5 | const char * path, 6 | std::vector & out_vertices, 7 | std::vector & out_uvs, 8 | std::vector & out_normals 9 | ); 10 | 11 | 12 | 13 | bool loadAssImp( 14 | const char * path, 15 | std::vector & indices, 16 | std::vector & vertices, 17 | std::vector & uvs, 18 | std::vector & normals 19 | ); 20 | 21 | #endif -------------------------------------------------------------------------------- /source/common/quaternion_utils.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaosink/Audio-Visualization---Waveform/b7a87786abd91551ebdca9c3f3ef2d385c6a2479/source/common/quaternion_utils.cpp -------------------------------------------------------------------------------- /source/common/quaternion_utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QUATERNION_UTILS_H 2 | #define QUATERNION_UTILS_H 3 | 4 | quat RotationBetweenVectors(vec3 start, vec3 dest); 5 | 6 | quat LookAt(vec3 direction, vec3 desiredUp); 7 | 8 | quat RotateTowards(quat q1, quat q2, float maxAngle); 9 | 10 | 11 | #endif // QUATERNION_UTILS_H -------------------------------------------------------------------------------- /source/common/shader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "shader.hpp" 15 | 16 | GLuint LoadShaders(const char *vertex_file_path, const char *fragment_file_path, const char *geometry_file_path) { 17 | 18 | // Create the shaders 19 | GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); 20 | GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); 21 | GLuint GeometryShaderID = glCreateShader(GL_GEOMETRY_SHADER); 22 | 23 | // Read the Vertex Shader code from the file 24 | std::string VertexShaderCode; 25 | std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); 26 | if(VertexShaderStream.is_open()) { 27 | std::string Line = ""; 28 | while(getline(VertexShaderStream, Line)) 29 | VertexShaderCode += "\n" + Line; 30 | VertexShaderStream.close(); 31 | } else { 32 | printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path); 33 | getchar(); 34 | return 0; 35 | } 36 | 37 | // Read the Fragment Shader code from the file 38 | std::string FragmentShaderCode; 39 | std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); 40 | if(FragmentShaderStream.is_open()){ 41 | std::string Line = ""; 42 | while(getline(FragmentShaderStream, Line)) 43 | FragmentShaderCode += "\n" + Line; 44 | FragmentShaderStream.close(); 45 | } 46 | 47 | 48 | // Read the Geometry Shader code from the file 49 | std::string GeometryShaderCode; 50 | std::ifstream GeometryShaderStream(geometry_file_path, std::ios::in); 51 | if(geometry_file_path) { 52 | if(GeometryShaderStream.is_open()){ 53 | std::string Line = ""; 54 | while(getline(GeometryShaderStream, Line)) 55 | GeometryShaderCode += "\n" + Line; 56 | GeometryShaderStream.close(); 57 | } 58 | } 59 | 60 | GLint Result = GL_FALSE; 61 | int InfoLogLength; 62 | 63 | // Compile Vertex Shader 64 | printf("Compiling shader : %s\n", vertex_file_path); 65 | char const * VertexSourcePointer = VertexShaderCode.c_str(); 66 | glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL); 67 | glCompileShader(VertexShaderID); 68 | // Check Vertex Shader 69 | glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); 70 | glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); 71 | if(InfoLogLength > 0) { 72 | std::vector VertexShaderErrorMessage(InfoLogLength+1); 73 | glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); 74 | printf("%s\n", &VertexShaderErrorMessage[0]); 75 | } 76 | 77 | // Compile Fragment Shader 78 | printf("Compiling shader : %s\n", fragment_file_path); 79 | char const * FragmentSourcePointer = FragmentShaderCode.c_str(); 80 | glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); 81 | glCompileShader(FragmentShaderID); 82 | // Check Fragment Shader 83 | glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); 84 | glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); 85 | if ( InfoLogLength > 0 ){ 86 | std::vector FragmentShaderErrorMessage(InfoLogLength+1); 87 | glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); 88 | printf("%s\n", &FragmentShaderErrorMessage[0]); 89 | } 90 | 91 | if(geometry_file_path) { 92 | // Compile Geometry Shader 93 | printf("Compiling shader : %s\n", geometry_file_path); 94 | char const * GeometrySourcePointer = GeometryShaderCode.c_str(); 95 | glShaderSource(GeometryShaderID, 1, &GeometrySourcePointer , NULL); 96 | glCompileShader(GeometryShaderID); 97 | // Check Geometry Shader 98 | glGetShaderiv(GeometryShaderID, GL_COMPILE_STATUS, &Result); 99 | glGetShaderiv(GeometryShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); 100 | if ( InfoLogLength > 0 ){ 101 | std::vector GeometryShaderErrorMessage(InfoLogLength+1); 102 | glGetShaderInfoLog(GeometryShaderID, InfoLogLength, NULL, &GeometryShaderErrorMessage[0]); 103 | printf("%s\n", &GeometryShaderErrorMessage[0]); 104 | } 105 | } 106 | 107 | // Link the program 108 | printf("Linking program\n"); 109 | GLuint ProgramID = glCreateProgram(); 110 | glAttachShader(ProgramID, VertexShaderID); 111 | glAttachShader(ProgramID, FragmentShaderID); 112 | if(geometry_file_path) 113 | glAttachShader(ProgramID, GeometryShaderID); 114 | glLinkProgram(ProgramID); 115 | 116 | // Check the program 117 | glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); 118 | glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); 119 | if ( InfoLogLength > 0 ){ 120 | std::vector ProgramErrorMessage(InfoLogLength+1); 121 | glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); 122 | printf("%s\n", &ProgramErrorMessage[0]); 123 | } 124 | 125 | glDeleteShader(VertexShaderID); 126 | glDeleteShader(FragmentShaderID); 127 | glDeleteShader(GeometryShaderID); 128 | 129 | return ProgramID; 130 | } 131 | 132 | 133 | -------------------------------------------------------------------------------- /source/common/shader.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SHADER_HPP 2 | #define SHADER_HPP 3 | 4 | GLuint LoadShaders(const char * vertex_file_path, const char * fragment_file_path, const char * geometry_file_path = NULL); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /source/common/tangentspace.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "tangentspace.hpp" 5 | 6 | void computeTangentBasis( 7 | // inputs 8 | std::vector & vertices, 9 | std::vector & uvs, 10 | std::vector & normals, 11 | // outputs 12 | std::vector & tangents, 13 | std::vector & bitangents 14 | ){ 15 | 16 | for (unsigned int i=0; i & vertices, 7 | std::vector & uvs, 8 | std::vector & normals, 9 | // outputs 10 | std::vector & tangents, 11 | std::vector & bitangents 12 | ); 13 | 14 | 15 | #endif -------------------------------------------------------------------------------- /source/common/text2D.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | using namespace glm; 9 | 10 | #include "shader.hpp" 11 | #include "texture.hpp" 12 | 13 | #include "text2D.hpp" 14 | 15 | unsigned int Text2DTextureID; // Texture containing the font 16 | unsigned int Text2DVertexBufferID; // Buffer containing the vertices 17 | unsigned int Text2DUVBufferID; // UVs 18 | unsigned int Text2DShaderID; // Program used to disaply the text 19 | unsigned int vertexPosition_screenspaceID; // Location of the program's "vertexPosition_screenspace" attribute 20 | unsigned int vertexUVID; // Location of the program's "vertexUV" attribute 21 | unsigned int Text2DUniformID; // Location of the program's texture attribute 22 | 23 | void initText2D(const char * texturePath){ 24 | 25 | // Initialize texture 26 | Text2DTextureID = loadDDS(texturePath); 27 | 28 | // Initialize VBO 29 | glGenBuffers(1, &Text2DVertexBufferID); 30 | glGenBuffers(1, &Text2DUVBufferID); 31 | 32 | // Initialize Shader 33 | Text2DShaderID = LoadShaders( "TextVertexShader.vertexshader", "TextVertexShader.fragmentshader" ); 34 | 35 | // Get a handle for our buffers 36 | vertexPosition_screenspaceID = glGetAttribLocation(Text2DShaderID, "vertexPosition_screenspace"); 37 | vertexUVID = glGetAttribLocation(Text2DShaderID, "vertexUV"); 38 | 39 | // Initialize uniforms' IDs 40 | Text2DUniformID = glGetUniformLocation( Text2DShaderID, "myTextureSampler" ); 41 | 42 | } 43 | 44 | void printText2D(const char * text, int x, int y, int size){ 45 | 46 | unsigned int length = strlen(text); 47 | 48 | // Fill buffers 49 | std::vector vertices; 50 | std::vector UVs; 51 | for ( unsigned int i=0 ; i 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | 10 | GLuint loadBMP_custom(const char * imagepath){ 11 | 12 | printf("Reading image %s\n", imagepath); 13 | 14 | // Data read from the header of the BMP file 15 | unsigned char header[54]; 16 | unsigned int dataPos; 17 | unsigned int imageSize; 18 | unsigned int width, height; 19 | // Actual RGB data 20 | unsigned char * data; 21 | 22 | // Open the file 23 | FILE * file = fopen(imagepath,"rb"); 24 | if (!file) { 25 | printf("%s could not be opened. Are you in the right directory ? Don't forget to read the FAQ !\n", imagepath); 26 | getchar(); 27 | return 0; 28 | } 29 | 30 | // Read the header, i.e. the 54 first bytes 31 | 32 | // If less than 54 bytes are read, problem 33 | if ( fread(header, 1, 54, file)!=54 ){ 34 | printf("Not a correct BMP file\n"); 35 | return 0; 36 | } 37 | // A BMP files always begins with "BM" 38 | if ( header[0]!='B' || header[1]!='M' ){ 39 | printf("Not a correct BMP file\n"); 40 | return 0; 41 | } 42 | // Make sure this is a 24bpp file 43 | if ( *(int*)&(header[0x1E])!=0 ) {printf("Not a correct BMP file\n"); return 0;} 44 | if ( *(int*)&(header[0x1C])!=24 ) {printf("Not a correct BMP file\n"); return 0;} 45 | 46 | // Read the information about the image 47 | dataPos = *(int*)&(header[0x0A]); 48 | imageSize = *(int*)&(header[0x22]); 49 | width = *(int*)&(header[0x12]); 50 | height = *(int*)&(header[0x16]); 51 | 52 | // Some BMP files are misformatted, guess missing information 53 | if (imageSize==0) imageSize=width*height*3; // 3 : one byte for each Red, Green and Blue component 54 | if (dataPos==0) dataPos=54; // The BMP header is done that way 55 | 56 | // Create a buffer 57 | data = new unsigned char [imageSize]; 58 | 59 | // Read the actual data from the file into the buffer 60 | fread(data,1,imageSize,file); 61 | 62 | // Everything is in memory now, the file wan be closed 63 | fclose (file); 64 | 65 | // Create one OpenGL texture 66 | GLuint textureID; 67 | glGenTextures(1, &textureID); 68 | 69 | // "Bind" the newly created texture : all future texture functions will modify this texture 70 | glBindTexture(GL_TEXTURE_2D, textureID); 71 | 72 | // Give the image to OpenGL 73 | glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data); 74 | 75 | // OpenGL has now copied the data. Free our own version 76 | delete [] data; 77 | 78 | // Poor filtering, or ... 79 | //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 80 | //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 81 | 82 | // ... nice trilinear filtering. 83 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 85 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 86 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 87 | glGenerateMipmap(GL_TEXTURE_2D); 88 | 89 | // Return the ID of the texture we just created 90 | return textureID; 91 | } 92 | 93 | // Since GLFW 3, glfwLoadTexture2D() has been removed. You have to use another texture loading library, 94 | // or do it yourself (just like loadBMP_custom and loadDDS) 95 | //GLuint loadTGA_glfw(const char * imagepath){ 96 | // 97 | // // Create one OpenGL texture 98 | // GLuint textureID; 99 | // glGenTextures(1, &textureID); 100 | // 101 | // // "Bind" the newly created texture : all future texture functions will modify this texture 102 | // glBindTexture(GL_TEXTURE_2D, textureID); 103 | // 104 | // // Read the file, call glTexImage2D with the right parameters 105 | // glfwLoadTexture2D(imagepath, 0); 106 | // 107 | // // Nice trilinear filtering. 108 | // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 109 | // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 110 | // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 111 | // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 112 | // glGenerateMipmap(GL_TEXTURE_2D); 113 | // 114 | // // Return the ID of the texture we just created 115 | // return textureID; 116 | //} 117 | 118 | 119 | 120 | #define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII 121 | #define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII 122 | #define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII 123 | 124 | GLuint loadDDS(const char * imagepath){ 125 | 126 | unsigned char header[124]; 127 | 128 | FILE *fp; 129 | 130 | /* try to open the file */ 131 | fp = fopen(imagepath, "rb"); 132 | if (fp == NULL){ 133 | printf("%s could not be opened. Are you in the right directory ? Don't forget to read the FAQ !\n", imagepath); 134 | getchar(); 135 | return 0; 136 | } 137 | 138 | /* verify the type of file */ 139 | char filecode[4]; 140 | fread(filecode, 1, 4, fp); 141 | if (strncmp(filecode, "DDS ", 4) != 0) { 142 | fclose(fp); 143 | return 0; 144 | } 145 | 146 | /* get the surface desc */ 147 | fread(&header, 124, 1, fp); 148 | 149 | unsigned int height = *(unsigned int*)&(header[8 ]); 150 | unsigned int width = *(unsigned int*)&(header[12]); 151 | unsigned int linearSize = *(unsigned int*)&(header[16]); 152 | unsigned int mipMapCount = *(unsigned int*)&(header[24]); 153 | unsigned int fourCC = *(unsigned int*)&(header[80]); 154 | 155 | 156 | unsigned char * buffer; 157 | unsigned int bufsize; 158 | /* how big is it going to be including all mipmaps? */ 159 | bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize; 160 | buffer = (unsigned char*)malloc(bufsize * sizeof(unsigned char)); 161 | fread(buffer, 1, bufsize, fp); 162 | /* close the file pointer */ 163 | fclose(fp); 164 | 165 | unsigned int components = (fourCC == FOURCC_DXT1) ? 3 : 4; 166 | unsigned int format; 167 | switch(fourCC) 168 | { 169 | case FOURCC_DXT1: 170 | format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; 171 | break; 172 | case FOURCC_DXT3: 173 | format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; 174 | break; 175 | case FOURCC_DXT5: 176 | format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; 177 | break; 178 | default: 179 | free(buffer); 180 | return 0; 181 | } 182 | 183 | // Create one OpenGL texture 184 | GLuint textureID; 185 | glGenTextures(1, &textureID); 186 | 187 | // "Bind" the newly created texture : all future texture functions will modify this texture 188 | glBindTexture(GL_TEXTURE_2D, textureID); 189 | glPixelStorei(GL_UNPACK_ALIGNMENT,1); 190 | 191 | unsigned int blockSize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16; 192 | unsigned int offset = 0; 193 | 194 | /* load the mipmaps */ 195 | for (unsigned int level = 0; level < mipMapCount && (width || height); ++level) 196 | { 197 | unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize; 198 | glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 199 | 0, size, buffer + offset); 200 | 201 | offset += size; 202 | width /= 2; 203 | height /= 2; 204 | 205 | // Deal with Non-Power-Of-Two textures. This code is not included in the webpage to reduce clutter. 206 | if(width < 1) width = 1; 207 | if(height < 1) height = 1; 208 | 209 | } 210 | 211 | free(buffer); 212 | 213 | return textureID; 214 | 215 | 216 | } 217 | -------------------------------------------------------------------------------- /source/common/texture.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TEXTURE_HPP 2 | #define TEXTURE_HPP 3 | 4 | // Load a .BMP file using our custom loader 5 | GLuint loadBMP_custom(const char * imagepath); 6 | 7 | //// Since GLFW 3, glfwLoadTexture2D() has been removed. You have to use another texture loading library, 8 | //// or do it yourself (just like loadBMP_custom and loadDDS) 9 | //// Load a .TGA file using GLFW's own loader 10 | //GLuint loadTGA_glfw(const char * imagepath); 11 | 12 | // Load a .DDS file using GLFW's own loader 13 | GLuint loadDDS(const char * imagepath); 14 | 15 | 16 | #endif -------------------------------------------------------------------------------- /source/common/vboindexer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "vboindexer.hpp" 7 | 8 | #include // for memcmp 9 | 10 | 11 | // Returns true iif v1 can be considered equal to v2 12 | bool is_near(float v1, float v2){ 13 | return fabs( v1-v2 ) < 0.01f; 14 | } 15 | 16 | // Searches through all already-exported vertices 17 | // for a similar one. 18 | // Similar = same position + same UVs + same normal 19 | bool getSimilarVertexIndex( 20 | glm::vec3 & in_vertex, 21 | glm::vec2 & in_uv, 22 | glm::vec3 & in_normal, 23 | std::vector & out_vertices, 24 | std::vector & out_uvs, 25 | std::vector & out_normals, 26 | unsigned short & result 27 | ){ 28 | // Lame linear search 29 | for ( unsigned int i=0; i & in_vertices, 51 | std::vector & in_uvs, 52 | std::vector & in_normals, 53 | 54 | std::vector & out_indices, 55 | std::vector & out_vertices, 56 | std::vector & out_uvs, 57 | std::vector & out_normals 58 | ){ 59 | // For each input vertex 60 | for ( unsigned int i=0; i0; 83 | }; 84 | }; 85 | 86 | bool getSimilarVertexIndex_fast( 87 | PackedVertex & packed, 88 | std::map & VertexToOutIndex, 89 | unsigned short & result 90 | ){ 91 | std::map::iterator it = VertexToOutIndex.find(packed); 92 | if ( it == VertexToOutIndex.end() ){ 93 | return false; 94 | }else{ 95 | result = it->second; 96 | return true; 97 | } 98 | } 99 | 100 | void indexVBO( 101 | std::vector & in_vertices, 102 | std::vector & in_uvs, 103 | std::vector & in_normals, 104 | 105 | std::vector & out_indices, 106 | std::vector & out_vertices, 107 | std::vector & out_uvs, 108 | std::vector & out_normals 109 | ){ 110 | std::map VertexToOutIndex; 111 | 112 | // For each input vertex 113 | for ( unsigned int i=0; i & in_vertices, 143 | std::vector & in_uvs, 144 | std::vector & in_normals, 145 | std::vector & in_tangents, 146 | std::vector & in_bitangents, 147 | 148 | std::vector & out_indices, 149 | std::vector & out_vertices, 150 | std::vector & out_uvs, 151 | std::vector & out_normals, 152 | std::vector & out_tangents, 153 | std::vector & out_bitangents 154 | ){ 155 | // For each input vertex 156 | for ( unsigned int i=0; i & in_vertices, 6 | std::vector & in_uvs, 7 | std::vector & in_normals, 8 | 9 | std::vector & out_indices, 10 | std::vector & out_vertices, 11 | std::vector & out_uvs, 12 | std::vector & out_normals 13 | ); 14 | 15 | 16 | void indexVBO_TBN( 17 | std::vector & in_vertices, 18 | std::vector & in_uvs, 19 | std::vector & in_normals, 20 | std::vector & in_tangents, 21 | std::vector & in_bitangents, 22 | 23 | std::vector & out_indices, 24 | std::vector & out_vertices, 25 | std::vector & out_uvs, 26 | std::vector & out_normals, 27 | std::vector & out_tangents, 28 | std::vector & out_bitangents 29 | ); 30 | 31 | #endif -------------------------------------------------------------------------------- /source/fft/fft.cpp: -------------------------------------------------------------------------------- 1 | #include "fft.hpp" 2 | 3 | FFT::FFT() { 4 | rawdata = NULL; 5 | FFTdata = NULL; 6 | } 7 | 8 | void FFT::setDataSize(int size) { 9 | datasize = size; 10 | } 11 | 12 | int FFT::getFFTSize() { 13 | return FFTsize; 14 | } 15 | 16 | void FFT::setSampleRate(int rate) { 17 | samplerate = rate; 18 | } 19 | 20 | int FFT::getSampleRate() { 21 | return samplerate; 22 | } 23 | 24 | float *FFT::getFFTData() { 25 | return FFTdata + 1; 26 | } 27 | 28 | float * FFT::calculateFFT(short *wave) { 29 | filldata(wave); 30 | FFTprocess(); 31 | scale(); 32 | FFTsize = samplerate / 2 - 1; 33 | return FFTdata + 1; 34 | } 35 | 36 | void FFT::filldata(short *wave) { 37 | Fdatasize = (int)pow(2.0, ceil(log((float)samplerate) / log(2.0))); 38 | 39 | if(rawdata == NULL) { 40 | rawdata = new complex[Fdatasize]; 41 | } 42 | if(FFTdata == NULL) { 43 | FFTdata = new float[Fdatasize]; 44 | } 45 | for(int i = 0; i < Fdatasize; i++) { 46 | if(i < samplerate) { 47 | int index = i % datasize; 48 | rawdata[i].real = wave[index * 2]; 49 | rawdata[i].img = 0; 50 | } else { 51 | rawdata[i].real = 0; 52 | rawdata[i].img = 0; 53 | } 54 | } 55 | } 56 | 57 | void FFT::FFTprocess() { 58 | int i, j = 0, k; 59 | complex t; 60 | for(i = 0; i < Fdatasize - 1; i++) { 61 | if(i < j) { 62 | t = rawdata[j]; 63 | rawdata[j] = rawdata[i]; 64 | rawdata[i] = t; 65 | } 66 | k = Fdatasize / 2; 67 | while(k <= j) { 68 | j -= k; 69 | k /= 2; 70 | } 71 | j += k; 72 | } 73 | int stage, le, lei, ip; 74 | complex u, w; 75 | j = Fdatasize; 76 | for(stage = 1; (j = j / 2) != 1; stage++); //caculate stage,which represents butterfly stages 77 | for(k = 1; k <= stage; k++) { 78 | le = 2 << (k - 1); 79 | lei = le / 2; 80 | u.real = 1.0; //u,butterfly factor initial value 81 | u.img = 0.0; 82 | w.real = cos(PI / lei); 83 | w.img = sin(PI / lei); 84 | for(j = 0; j <= lei - 1; j++) { 85 | for(i = j; i <= Fdatasize - 1; i += le) { 86 | ip = i + lei; 87 | t = EE(rawdata[ip], u); 88 | rawdata[ip].real = rawdata[i].real - t.real; 89 | rawdata[ip].img = rawdata[i].img - t.img; 90 | rawdata[i].real = rawdata[i].real + t.real; 91 | rawdata[i].img = rawdata[i].img + t.img; 92 | } 93 | u = EE(u, w); 94 | } 95 | } 96 | } 97 | 98 | complex FFT::EE(complex a, complex b) { 99 | complex c; 100 | c.real = a.real*b.real - a.img*b.img; 101 | c.img = a.real*b.img + a.img*b.real; 102 | return c; 103 | } 104 | 105 | void FFT::scale() { 106 | for(int i = 0; i < Fdatasize; i++){ 107 | FFTdata[i] = sqrt(rawdata[i].real * rawdata[i].real + rawdata[i].img * rawdata[i].img) * 2 / Fdatasize; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /source/fft/fft.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __FFT__ 2 | #define __FFT__ 3 | 4 | #include 5 | #include 6 | #define PI 3.141592653589793238462643383279 7 | 8 | class complex { 9 | public: 10 | float real; 11 | float img; 12 | }; 13 | 14 | class FFT { 15 | public: 16 | FFT(); 17 | void setDataSize(int size); 18 | int getFFTSize(); 19 | void setSampleRate(int rate); 20 | int getSampleRate(); 21 | float *getFFTData(); 22 | float *calculateFFT(short *wave); 23 | private: 24 | void filldata(short *wave); 25 | void FFTprocess(); 26 | void scale(); 27 | complex EE(complex a,complex b); 28 | complex *rawdata; 29 | int datasize; 30 | int Fdatasize; 31 | int FFTsize; 32 | int samplerate; 33 | float *FFTdata; 34 | }; 35 | 36 | #endif // FFT 37 | -------------------------------------------------------------------------------- /source/play_wav/play_wav.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "play_wav.hpp" 5 | 6 | int play_wav(char *file) 7 | { 8 | struct WAV_HEADER wav_header; 9 | int nread; 10 | FILE *fp; 11 | fp = fopen(file, "rb"); 12 | if(fp == NULL) { 13 | perror("open file failed:\n"); 14 | exit(1); 15 | } 16 | nread = fread(&wav_header, 1, sizeof(wav_header), fp); 17 | 18 | int rc; 19 | int ret; 20 | int size; 21 | snd_pcm_t* handle; //PCI设备句柄 22 | snd_pcm_hw_params_t* params; //硬件信息和PCM流配置 23 | unsigned int val; 24 | int dir = 0; 25 | snd_pcm_uframes_t frames; 26 | char *buffer; 27 | int channels = wav_header.wChannels; 28 | int frequency = wav_header.nSamplesPersec; 29 | int bit = wav_header.wBitsPerSample; 30 | int datablock = wav_header.wBlockAlign; 31 | unsigned char ch[100]; //用来存储wav文件的头信息 32 | 33 | rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); 34 | if(rc < 0) 35 | { 36 | perror("\nopen PCM device failed:"); 37 | exit(1); 38 | } 39 | snd_pcm_hw_params_alloca(¶ms); //分配params结构体 40 | if(rc < 0) 41 | { 42 | perror("\nsnd_pcm_hw_params_alloca:"); 43 | exit(1); 44 | } 45 | rc = snd_pcm_hw_params_any(handle, params); //初始化params 46 | if(rc<0) 47 | { 48 | perror("\nsnd_pcm_hw_params_any:"); 49 | exit(1); 50 | } 51 | rc = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); //初始化访问权限 52 | if(rc < 0) 53 | { 54 | perror("\nsed_pcm_hw_set_access:"); 55 | exit(1); 56 | } 57 | //采样位数 58 | switch(bit / 8) { 59 | case 1: 60 | snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8); 61 | break; 62 | case 2: 63 | snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); 64 | break; 65 | case 3: 66 | snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S24_LE); 67 | break; 68 | } 69 | rc = snd_pcm_hw_params_set_channels(handle, params, channels); //设置声道,1表示单声>道,2表示立体声 70 | if(rc < 0) { 71 | perror("\nsnd_pcm_hw_params_set_channels:"); 72 | exit(1); 73 | } 74 | val = frequency; 75 | rc = snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); //设置>频率 76 | if(rc < 0) { 77 | perror("\nsnd_pcm_hw_params_set_rate_near:"); 78 | exit(1); 79 | } 80 | rc = snd_pcm_hw_params(handle, params); 81 | if(rc < 0) { 82 | perror("\nsnd_pcm_hw_params: "); 83 | exit(1); 84 | } 85 | rc = snd_pcm_hw_params_get_period_size(params, &frames, &dir); //获取周期长度 86 | if(rc < 0) { 87 | perror("\nsnd_pcm_hw_params_get_period_size:"); 88 | exit(1); 89 | } 90 | size = frames * datablock; //4 代表数据快长度 91 | buffer = (char*)malloc(size); 92 | fseek(fp, 54, SEEK_SET); //定位歌曲到数据区 93 | 94 | while(1) { 95 | memset(buffer, 0, size); 96 | ret = fread(buffer, 1, size, fp); 97 | if(ret == 0) { 98 | printf("歌曲写入结束\n"); 99 | break; 100 | } else if (ret != size) {} 101 | // 写音频数据到PCM设备 102 | while((ret = snd_pcm_writei(handle, buffer, frames) < 0)) { 103 | usleep(2000); 104 | if(ret == -EPIPE) { 105 | // EPIPE means underrun 106 | fprintf(stderr, "underrun occurred\n"); 107 | //完成硬件参数设置,使设备准备好 108 | snd_pcm_prepare(handle); 109 | } else if(ret < 0) { 110 | fprintf(stderr, "error from writei: %s\n", snd_strerror(ret)); 111 | } 112 | } 113 | } 114 | snd_pcm_drain(handle); 115 | snd_pcm_close(handle); 116 | free(buffer); 117 | fclose(fp); 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /source/play_wav/play_wav.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __PLAY_WAV__ 2 | #define __PLAY_WAV__ 3 | 4 | #include 5 | struct WAV_HEADER { 6 | char rld[4]; //riff 标志符号 7 | int rLen; 8 | char wld[4]; //格式类型(wave) 9 | char fld[4]; //"fmt" 10 | int fLen; //sizeof(wave format matex) 11 | short wFormatTag; //编码格式 12 | short wChannels; //声道数 13 | int nSamplesPersec ; //采样频率 14 | int nAvgBitsPerSample;//WAVE文件采样大小 15 | short wBlockAlign; //块对齐 16 | short wBitsPerSample; //WAVE文件采样大小 17 | char dld[4]; //”data“ 18 | int wSampleLength; //音频数据的大小 19 | }; 20 | 21 | int play_wav(char *file); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /source/waveform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | GLFWwindow* window; 9 | #include 10 | #include 11 | //using namespace glm; 12 | 13 | //#include 14 | #include 15 | #include 16 | #include "audio_data/audio_data.hpp" 17 | #include "play_wav/play_wav.hpp" 18 | #include "fft/fft.hpp" 19 | 20 | #define max(a, b) ((a) > (b) ? (a) : (b)) 21 | 22 | const int fps = 40; 23 | const int column_height = 2; 24 | const int waveform_interval = 1; 25 | const float waveform_length = 20.0; 26 | const float top_height = 0.01; 27 | const float top_speed = 0.02; 28 | 29 | void *play_wav_d(void *file) { 30 | play_wav((char *)file); 31 | return NULL; 32 | } 33 | 34 | int main(int argc, char **argv) { 35 | if(argc != 2) exit(0); 36 | 37 | if(!glfwInit()) { 38 | fprintf(stderr, "Failed to initialize GLFW\n"); 39 | return -1; 40 | } 41 | 42 | glfwWindowHint(GLFW_SAMPLES, 4); 43 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 44 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 45 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 46 | 47 | window = glfwCreateWindow(1920, 1080, "Audio Visualization", glfwGetPrimaryMonitor(), NULL); 48 | if(window == NULL) { 49 | fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n"); 50 | glfwTerminate(); 51 | return -1; 52 | } 53 | glfwMakeContextCurrent(window); 54 | 55 | glewExperimental = true; //Needed for core profile 56 | if(glewInit() != GLEW_OK) { 57 | fprintf(stderr, "Failed to initialize GLEW\n"); 58 | return -1; 59 | } 60 | 61 | glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); 62 | glfwSetInputMode(window, GLFW_CURSOR_DISABLED, GL_TRUE); 63 | 64 | 65 | 66 | // glClearColor(0.f / 255.f, 63.f / 255.f, 0.f / 255.f, 1.0f); 67 | glClearColor(0.1, 0.1, 0.1, 1.0); 68 | glEnable(GL_DEPTH_TEST); 69 | glDepthFunc(GL_LESS); 70 | 71 | GLuint VertexArrayID; 72 | glGenVertexArrays(1, &VertexArrayID); 73 | glBindVertexArray(VertexArrayID); 74 | 75 | /* ShaderInfo shaders[] = { 76 | {GL_VERTEX_SHADER, "VertexShader.vert"}, 77 | {GL_FRAGMENT_SHADER, "FragmentShader.frag"}, 78 | {GL_GEOMETRY_SHADER, "GeometryShader.geom"}, 79 | {GL_NONE, NULL}}; 80 | GLuint programID = LoadShaders(shaders);*/ 81 | GLuint programID = LoadShaders("shaders/VertexShader.vert", "shaders/FragmentShader.frag", NULL);//"shaders/GeometryShader.geom"); 82 | 83 | GLuint MatrixID = glGetUniformLocation(programID, "MVP"); 84 | GLuint objectID = glGetUniformLocation(programID, "object"); 85 | GLuint topID = glGetUniformLocation(programID, "top"); 86 | 87 | glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f); 88 | glm::mat4 View = glm::lookAt( 89 | glm::vec3(10,15,20), //Camera is at (4,3,-3), in World Space 90 | glm::vec3(0,0,0), //and looks at the origin 91 | glm::vec3(0,1,0)); //Head is up (set to 0,-1,0 to look upside-down) 92 | glm::mat4 Model = glm::mat4(1.0f); 93 | glm::mat4 PV = Projection * View; 94 | glm::mat4 MVP = PV * Model; 95 | 96 | 97 | 98 | static const GLfloat g_vertex_buffer_data1[] = { 99 | -1.0f,-1.0f,-1.0f, //left 100 | -1.0f,-1.0f, 1.0f, 101 | -1.0f, 1.0f, 1.0f, 102 | -1.0f,-1.0f,-1.0f, 103 | -1.0f, 1.0f,-1.0f, 104 | -1.0f, 1.0f, 1.0f, 105 | 1.0f,-1.0f,-1.0f, //right 106 | 1.0f,-1.0f, 1.0f, 107 | 1.0f, 1.0f, 1.0f, 108 | 1.0f,-1.0f,-1.0f, 109 | 1.0f, 1.0f,-1.0f, 110 | 1.0f, 1.0f, 1.0f, 111 | -1.0f,-1.0f, 1.0f, //front 112 | 1.0f,-1.0f, 1.0f, 113 | 1.0f, 1.0f, 1.0f, 114 | -1.0f,-1.0f, 1.0f, 115 | -1.0f, 1.0f, 1.0f, 116 | 1.0f, 1.0f, 1.0f, 117 | -1.0f, 1.0f,-1.0f, //top 118 | 1.0f, 1.0f,-1.0f, 119 | 1.0f, 1.0f, 1.0f, 120 | -1.0f, 1.0f,-1.0f, 121 | -1.0f, 1.0f, 1.0f, 122 | 1.0f, 1.0f, 1.0f, 123 | -1.0f,-1.0f,-1.0f, //back 124 | 1.0f,-1.0f,-1.0f, 125 | 1.0f, 1.0f,-1.0f, 126 | -1.0f,-1.0f,-1.0f, 127 | -1.0f, 1.0f,-1.0f, 128 | 1.0f, 1.0f,-1.0f, 129 | -1.0f,-1.0f,-1.0f, //bottom 130 | 1.0f,-1.0f,-1.0f, 131 | 1.0f,-1.0f, 1.0f, 132 | -1.0f,-1.0f,-1.0f, 133 | -1.0f,-1.0f, 1.0f, 134 | 1.0f,-1.0f, 1.0f 135 | }; 136 | 137 | static const GLfloat g_vertex_buffer_data2[] = { 138 | -1.0f,-1.0f,-1.0f, //left 139 | -1.0f,-1.0f, 1.0f, 140 | -1.0f, 1.0f, 1.0f, 141 | -1.0f,-1.0f,-1.0f, 142 | -1.0f, 1.0f,-1.0f, 143 | -1.0f, 1.0f, 1.0f, 144 | 1.0f,-1.0f,-1.0f, //right 145 | 1.0f,-1.0f, 1.0f, 146 | 1.0f, 1.0f, 1.0f, 147 | 1.0f,-1.0f,-1.0f, 148 | 1.0f, 1.0f,-1.0f, 149 | 1.0f, 1.0f, 1.0f, 150 | -1.0f,-1.0f, 1.0f, //front 151 | 1.0f,-1.0f, 1.0f, 152 | 1.0f, 1.0f, 1.0f, 153 | -1.0f,-1.0f, 1.0f, 154 | -1.0f, 1.0f, 1.0f, 155 | 1.0f, 1.0f, 1.0f, 156 | -1.0f, 1.0f,-1.0f, //top 157 | 1.0f, 1.0f,-1.0f, 158 | 1.0f, 1.0f, 1.0f, 159 | -1.0f, 1.0f,-1.0f, 160 | -1.0f, 1.0f, 1.0f, 161 | 1.0f, 1.0f, 1.0f, 162 | -1.0f,-1.0f,-1.0f, //back 163 | 1.0f,-1.0f,-1.0f, 164 | 1.0f, 1.0f,-1.0f, 165 | -1.0f,-1.0f,-1.0f, 166 | -1.0f, 1.0f,-1.0f, 167 | 1.0f, 1.0f,-1.0f, 168 | -1.0f,-1.0f,-1.0f, //bottom 169 | 1.0f,-1.0f,-1.0f, 170 | 1.0f,-1.0f, 1.0f, 171 | -1.0f,-1.0f,-1.0f, 172 | -1.0f,-1.0f, 1.0f, 173 | 1.0f,-1.0f, 1.0f 174 | }; 175 | 176 | static const GLfloat g_color_buffer_data1[] = { 177 | 1.0f, 0.2f, 0.2f, //left 178 | 1.0f, 0.5f, 0.5f, 179 | 1.0f, 1.0f, 1.0f, 180 | 1.0f, 0.2f, 0.2f, 181 | 1.0f, 0.5f, 0.5f, 182 | 1.0f, 1.0f, 1.0f, 183 | 1.0f, 0.2f, 0.2f, //right 184 | 1.0f, 0.5f, 0.5f, 185 | 1.0f, 1.0f, 1.0f, 186 | 1.0f, 0.2f, 0.2f, 187 | 1.0f, 0.5f, 0.5f, 188 | 1.0f, 1.0f, 1.0f, 189 | 1.0f, 0.5f, 0.5f, //front 190 | 1.0f, 0.5f, 0.5f, 191 | 1.0f, 1.0f, 1.0f, 192 | 1.0f, 0.5f, 0.5f, 193 | 1.0f, 1.0f, 1.0f, 194 | 1.0f, 1.0f, 1.0f, 195 | 1.0f, 0.5f, 0.5f, //top 196 | 1.0f, 0.5f, 0.5f, 197 | 1.0f, 1.0f, 1.0f, 198 | 1.0f, 0.5f, 0.5f, 199 | 1.0f, 1.0f, 1.0f, 200 | 1.0f, 1.0f, 1.0f, 201 | 1.0f, 0.2f, 0.2f, //back 202 | 1.0f, 0.2f, 0.2f, 203 | 1.0f, 0.5f, 0.5f, 204 | 1.0f, 0.2f, 0.2f, 205 | 1.0f, 0.5f, 0.5f, 206 | 1.0f, 0.5f, 0.5f, 207 | 1.0f, 0.2f, 0.2f, //bottom 208 | 1.0f, 0.2f, 0.2f, 209 | 1.0f, 0.5f, 0.5f, 210 | 1.0f, 0.2f, 0.2f, 211 | 1.0f, 0.5f, 0.5f, 212 | 1.0f, 0.5f, 0.5f 213 | }; 214 | 215 | static const GLfloat g_color_buffer_data2[] = { 216 | 0.2f, 0.2f, 1.0f, //left 217 | 0.5f, 0.5f, 1.0f, 218 | 1.0f, 1.0f, 1.0f, 219 | 0.2f, 0.2f, 1.0f, 220 | 0.5f, 0.5f, 1.0f, 221 | 1.0f, 1.0f, 1.0f, 222 | 0.2f, 0.2f, 1.0f, //right 223 | 0.5f, 0.5f, 1.0f, 224 | 1.0f, 1.0f, 1.0f, 225 | 0.2f, 0.2f, 1.0f, 226 | 0.5f, 0.5f, 1.0f, 227 | 1.0f, 1.0f, 1.0f, 228 | 0.5f, 0.5f, 1.0f, //front 229 | 0.5f, 0.5f, 1.0f, 230 | 1.0f, 1.0f, 1.0f, 231 | 0.5f, 0.5f, 1.0f, 232 | 1.0f, 1.0f, 1.0f, 233 | 1.0f, 1.0f, 1.0f, 234 | 0.5f, 0.5f, 1.0f, //top 235 | 0.5f, 0.5f, 1.0f, 236 | 1.0f, 1.0f, 1.0f, 237 | 0.5f, 0.5f, 1.0f, 238 | 1.0f, 1.0f, 1.0f, 239 | 1.0f, 1.0f, 1.0f, 240 | 0.2f, 0.2f, 1.0f, //back 241 | 0.2f, 0.2f, 1.0f, 242 | 0.5f, 0.5f, 1.0f, 243 | 0.2f, 0.2f, 1.0f, 244 | 0.5f, 0.5f, 1.0f, 245 | 0.5f, 0.5f, 1.0f, 246 | 0.2f, 0.2f, 1.0f, //bottom 247 | 0.2f, 0.2f, 1.0f, 248 | 0.5f, 0.5f, 1.0f, 249 | 0.2f, 0.2f, 1.0f, 250 | 0.5f, 0.5f, 1.0f, 251 | 0.5f, 0.5f, 1.0f 252 | }; 253 | 254 | 255 | 256 | GLuint vertexbuffer1; //left column 257 | glGenBuffers(1, &vertexbuffer1); 258 | glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer1); 259 | glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data1), g_vertex_buffer_data1, GL_STATIC_DRAW); 260 | 261 | GLuint vertexbuffer2; //right column 262 | glGenBuffers(1, &vertexbuffer2); 263 | glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2); 264 | glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data2), g_vertex_buffer_data2, GL_STATIC_DRAW); 265 | 266 | GLuint vertexbuffer3; //waveform 267 | glGenBuffers(1, &vertexbuffer3); 268 | 269 | GLuint vertexbuffer4; //z 270 | glGenBuffers(1, &vertexbuffer4); 271 | 272 | GLuint vertexbuffer5; //spectrum 273 | glGenBuffers(1, &vertexbuffer5); 274 | 275 | GLuint colorbuffer1; 276 | glGenBuffers(1, &colorbuffer1); 277 | glBindBuffer(GL_ARRAY_BUFFER, colorbuffer1); 278 | glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data1), g_color_buffer_data1, GL_STATIC_DRAW); 279 | 280 | GLuint colorbuffer2; 281 | glGenBuffers(1, &colorbuffer2); 282 | glBindBuffer(GL_ARRAY_BUFFER, colorbuffer2); 283 | glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data2), g_color_buffer_data2, GL_STATIC_DRAW); 284 | 285 | 286 | 287 | audio_data data = get_audio_data(argv[1]); 288 | int bpf = data.sampling_rate / fps; 289 | int data_index = 0; 290 | double current_time; 291 | double last_time; 292 | double total_time = data.size / data.sampling_rate / 4; 293 | float z[bpf * 2]; 294 | for(int i = 0; i < bpf; i++) z[i * 2] = z[i * 2 + 1] = waveform_length / bpf * i - waveform_length / 2; 295 | glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer4); 296 | glBufferData(GL_ARRAY_BUFFER, bpf * 8, z, GL_STATIC_DRAW); 297 | 298 | int res; 299 | pthread_t a_thread; 300 | void *thread_result; 301 | res = pthread_create(&a_thread, NULL, play_wav_d, argv[1]); 302 | if(res != 0) { 303 | perror("Thread creation failed!"); 304 | exit(EXIT_FAILURE); 305 | } 306 | 307 | FFT fft; 308 | fft.setDataSize(bpf); 309 | fft.setSampleRate(data.sampling_rate); 310 | 311 | float max_l = 0, max_r = 0; 312 | glfwSetTime(0); 313 | do { 314 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 315 | glUseProgram(programID); 316 | 317 | glEnableVertexAttribArray(0); 318 | glEnableVertexAttribArray(1); 319 | glEnableVertexAttribArray(2); 320 | 321 | computeMatricesFromInputs(); 322 | glm::mat4 Projection = getProjectionMatrix(); 323 | glm::mat4 View = getViewMatrix(); 324 | glm::mat4 ModelMatrix = glm::mat4(1.0); 325 | PV = Projection * View; 326 | MVP = PV * ModelMatrix; 327 | glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); 328 | 329 | 330 | 331 | float *FFTdata = fft.calculateFFT((short *)data.data + data_index); 332 | int spectrum_interval = fps / 2; 333 | for(int i = 0; i < bpf; i++) { 334 | for(int j = 1; j < spectrum_interval; j++) 335 | FFTdata[i * spectrum_interval] += FFTdata[i * spectrum_interval + j]; 336 | FFTdata[i * spectrum_interval] /= spectrum_interval * 10; 337 | FFTdata[i * spectrum_interval + spectrum_interval / 2] = 0; 338 | } 339 | 340 | 341 | 342 | glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer4); //z 343 | glVertexAttribPointer( 344 | 2, //attribute. No particular reason for 0, but must match the layout in the shader. 345 | 1, //size 346 | GL_FLOAT, //type 347 | GL_FALSE, //normalized? 348 | 0, //stride 349 | (void *)0 //array buffer offset 350 | ); 351 | 352 | glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer5); //spectrum 353 | glBufferData(GL_ARRAY_BUFFER, spectrum_interval * bpf * 4, FFTdata, GL_STATIC_DRAW); 354 | glVertexAttribPointer( 355 | 0, //attribute. No particular reason for 0, but must match the layout in the shader. 356 | 1, //size 357 | GL_FLOAT, //type 358 | GL_FALSE, //normalized? 359 | spectrum_interval * 2, //stride 360 | (void *)0 //array buffer offset 361 | ); 362 | glUniform1i(objectID, 6); 363 | glDrawArrays(GL_LINES, 0, bpf * 2); //draw spectrum 364 | 365 | 366 | 367 | glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer4); //z 368 | glVertexAttribPointer( 369 | 2, //attribute. No particular reason for 0, but must match the layout in the shader. 370 | 1, //size 371 | GL_FLOAT, //type 372 | GL_FALSE, //normalized? 373 | (waveform_interval + 1) * 4, 374 | //stride 375 | (void *)0 //array buffer offset 376 | ); 377 | 378 | glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer3); //waveform 379 | glBufferData(GL_ARRAY_BUFFER, bpf * 4, (short *)data.data + data_index, GL_DYNAMIC_DRAW); 380 | 381 | glVertexAttribPointer( 382 | 0, //attribute. No particular reason for 0, but must match the layout in the shader. 383 | 1, //size 384 | GL_SHORT, //type 385 | GL_FALSE, //normalized? 386 | waveform_interval * 4, //stride 387 | (void *)0 //array buffer offset 388 | ); 389 | glUniform1i(objectID, 2); 390 | glDrawArrays(GL_LINE_STRIP, 0, bpf / waveform_interval); //draw left waveform 391 | 392 | glVertexAttribPointer( 393 | 0, //attribute. No particular reason for 0, but must match the layout in the shader. 394 | 1, //size 395 | GL_SHORT, //type 396 | GL_FALSE, //normalized? 397 | waveform_interval * 4, //stride 398 | (void *)2 //array buffer offset 399 | ); 400 | glUniform1i(objectID, 3); 401 | glDrawArrays(GL_LINE_STRIP, 0, bpf / waveform_interval); //draw right waveform 402 | 403 | 404 | 405 | float sum_l = 0, sum_r = 0; 406 | for(int i = 0; i < bpf; i++) { 407 | sum_l = max(sum_l, abs(((short*)data.data)[data_index])); //max 408 | data_index++; 409 | sum_r = max(sum_r, abs(((short*)data.data)[data_index])); 410 | data_index++; 411 | // sum_l += abs(((short*)data.data)[data_index++]); //avg 412 | // sum_r += abs(((short*)data.data)[data_index++]); 413 | } 414 | // sum_l /= bpf; //avg 415 | // sum_r /= bpf; 416 | 417 | 418 | 419 | float scale_l = sum_l / 32768 * column_height; 420 | Model = glm::mat4( 421 | 1.0, 0.0, 0.0, 0.0, 422 | 0.0, 1.0, 0.0, 0.0, 423 | 0.0, 0.0, 1.0, 0.0, 424 | -2.0, 1.0, 0.0, 1.0); 425 | glm::mat4 scale1 = glm::mat4( 426 | 1.0, 0.0, 0.0, 0.0, 427 | 0.0, scale_l, 0.0, 0.0, 428 | 0.0, 0.0, 1.0, 0.0, 429 | 0.0, 0.0, 0.0, 1.0); 430 | MVP = PV * scale1 * Model; 431 | glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); 432 | 433 | glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer1); //left column vertex 434 | glVertexAttribPointer( 435 | 0, // attribute. No particular reason for 0, but must match the layout in the shader. 436 | 3, // size 437 | GL_FLOAT, // type 438 | GL_FALSE, // normalized? 439 | 0, // stride 440 | (void *)0 // array buffer offset 441 | ); 442 | glBindBuffer(GL_ARRAY_BUFFER, colorbuffer1); //left column color 443 | glVertexAttribPointer( 444 | 1, // attribute. No particular reason for 1, but must match the layout in the shader. 445 | 3, // size 446 | GL_FLOAT, // type 447 | GL_FALSE, // normalized? 448 | 0, // stride 449 | (void *)0 // array buffer offset 450 | ); 451 | glUniform1i(objectID, 0); 452 | glDrawArrays(GL_TRIANGLES, 0, 12*3); //draw left column 453 | 454 | if(scale_l> max_l) max_l = scale_l; 455 | else max_l -= top_speed; 456 | glm::mat4 translate1 = glm::mat4( 457 | 1.0, 0.0, 0.0, 0.0, 458 | 0.0, 1.0, 0.0, 0.0, 459 | 0.0, 0.0, 1.0, 0.0, 460 | -2.0, max_l * 2, 0.0, 1.0); 461 | scale1 = glm::mat4( 462 | max_l / 2, 0.0, 0.0, 0.0, 463 | 0.0, max_l / 2 * top_height, 0.0, 0.0, 464 | 0.0, 0.0, max_l / 2, 0.0, 465 | 0.0, 0.0, 0.0, 1.0); 466 | MVP = PV * translate1 * scale1; 467 | glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); 468 | glUniform1i(objectID, 4); 469 | glUniform1f(topID, max_l); 470 | glDrawArrays(GL_TRIANGLES, 0, 12*3); //draw left upper top 471 | 472 | translate1 = glm::mat4( 473 | 1.0, 0.0, 0.0, 0.0, 474 | 0.0, 1.0, 0.0, 0.0, 475 | 0.0, 0.0, 1.0, 0.0, 476 | -2.0, scale_l * 2, 0.0, 1.0); 477 | scale1 = glm::mat4( 478 | scale_l / 2, 0.0, 0.0, 0.0, 479 | 0.0, scale_l / 2 * top_height, 0.0, 0.0, 480 | 0.0, 0.0, scale_l / 2, 0.0, 481 | 0.0, 0.0, 0.0, 1.0); 482 | MVP = PV * translate1 * scale1; 483 | glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); 484 | glUniform1i(objectID, 4); 485 | glUniform1f(topID, scale_l); 486 | glDrawArrays(GL_TRIANGLES, 0, 12*3); //draw left lower top 487 | 488 | 489 | 490 | float scale_r = sum_r / 32768 * column_height; 491 | Model = glm::mat4( 492 | 1.0, 0.0, 0.0, 0.0, 493 | 0.0, 1.0, 0.0, 0.0, 494 | 0.0, 0.0, 1.0, 0.0, 495 | 2.0, 1.0, 0.0, 1.0); 496 | glm::mat4 scale2 = glm::mat4( 497 | 1.0, 0.0, 0.0, 0.0, 498 | 0.0, scale_r, 0.0, 0.0, 499 | 0.0, 0.0, 1.0, 0.0, 500 | 0.0, 0.0, 0.0, 1.0); 501 | MVP = PV * scale2 * Model; 502 | glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); 503 | 504 | glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2); //right column vertex 505 | glVertexAttribPointer( 506 | 0, // attribute. No particular reason for 0, but must match the layout in the shader. 507 | 3, // size 508 | GL_FLOAT, // type 509 | GL_FALSE, // normalized? 510 | 0, // stride 511 | (void*)0 // array buffer offset 512 | ); 513 | glBindBuffer(GL_ARRAY_BUFFER, colorbuffer2); //right column vertex 514 | glVertexAttribPointer( 515 | 1, // attribute. No particular reason for 1, but must match the layout in the shader. 516 | 3, // size 517 | GL_FLOAT, // type 518 | GL_FALSE, // normalized? 519 | 0, // stride 520 | (void*)0 // array buffer offset 521 | ); 522 | glUniform1i(objectID, 1); 523 | glDrawArrays(GL_TRIANGLES, 0, 12*3); //draw right column 524 | 525 | if(scale_r > max_r) max_r = scale_r; 526 | else max_r -= top_speed; 527 | glm::mat4 translate2 = glm::mat4( 528 | 1.0, 0.0, 0.0, 0.0, 529 | 0.0, 1.0, 0.0, 0.0, 530 | 0.0, 0.0, 1.0, 0.0, 531 | 2.0, max_r * 2, 0.0, 1.0); 532 | scale2 = glm::mat4( 533 | max_r / 2, 0.0, 0.0, 0.0, 534 | 0.0, max_r / 2 * top_height, 0.0, 0.0, 535 | 0.0, 0.0, max_r / 2, 0.0, 536 | 0.0, 0.0, 0.0, 1.0);//0.25 / max_r);//(4.0 - max_r) * (4.0 - max_r)); 537 | MVP = PV * translate2 * scale2; 538 | glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); 539 | glUniform1i(objectID, 5); 540 | glUniform1f(topID, max_r); 541 | glDrawArrays(GL_TRIANGLES, 0, 12*3); //draw right upper top 542 | 543 | translate2 = glm::mat4( 544 | 1.0, 0.0, 0.0, 0.0, 545 | 0.0, 1.0, 0.0, 0.0, 546 | 0.0, 0.0, 1.0, 0.0, 547 | 2.0, scale_r * 2, 0.0, 1.0); 548 | scale2 = glm::mat4( 549 | scale_r / 2, 0.0, 0.0, 0.0, 550 | 0.0, scale_r / 2 * top_height, 0.0, 0.0, 551 | 0.0, 0.0, scale_r / 2, 0.0, 552 | 0.0, 0.0, 0.0, 1.0);//0.25 / max_r);//(4.0 - max_r) * (4.0 - max_r)); 553 | MVP = PV * translate2 * scale2; 554 | glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); 555 | glUniform1i(objectID, 5); 556 | glUniform1f(topID, scale_r); 557 | glDrawArrays(GL_TRIANGLES, 0, 12*3); //draw right lower top 558 | 559 | 560 | 561 | glDisableVertexAttribArray(0); 562 | glDisableVertexAttribArray(1); 563 | glDisableVertexAttribArray(2); 564 | 565 | if(data_index >= data.size / 2) break; 566 | current_time = glfwGetTime(); 567 | double left_time = total_time - current_time; 568 | if(left_time <= 0) break; 569 | double accurate_time = data_index / 2.0 / bpf / fps; 570 | double delta = accurate_time - current_time; 571 | printf("%lf %lf %lf %lf %lf\n", current_time - last_time, accurate_time, current_time, delta, left_time); 572 | delta = delta > 0 ? delta : 0; 573 | last_time = current_time; 574 | usleep(delta * 1000000); 575 | glfwSwapBuffers(window); 576 | glfwPollEvents(); 577 | } while(glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && !glfwWindowShouldClose(window)); 578 | 579 | pthread_cancel(a_thread); 580 | res = pthread_join(a_thread, &thread_result); 581 | if(res != 0) { 582 | perror("Thread join failed!"); 583 | exit(EXIT_FAILURE); 584 | } 585 | 586 | glDeleteBuffers(1, &vertexbuffer1); 587 | glDeleteBuffers(1, &vertexbuffer2); 588 | glDeleteBuffers(1, &vertexbuffer3); 589 | glDeleteBuffers(1, &vertexbuffer4); 590 | glDeleteBuffers(1, &vertexbuffer5); 591 | glDeleteBuffers(1, &colorbuffer1); 592 | glDeleteBuffers(1, &colorbuffer2); 593 | glDeleteProgram(programID); 594 | glDeleteVertexArrays(1, &VertexArrayID); 595 | 596 | glfwTerminate(); 597 | 598 | return 0; 599 | } 600 | --------------------------------------------------------------------------------