Skip to content

Commit e2d265f

Browse files
authored
Issue#130 (#546)
* Fixes issue #130 Adds functionality of writing a rendered frame to file as requested by the issue #130. Keyhandler.cpp has been updated to handle the keydown of 'd', which triggers writeNextFrameToFile to be set to true, which means at the end of Renderer::FinishPass1 we write the texture contents to file. Renderer::debugWriteMainTextureToFile() const contains the functionality of writing the contents of the main texture. * Addition to commit that fixes #130 Safe file write, making sure we don't overflow while creating the filename. If c++20 features was enabled, this could look so, so much better. * Added keybinding to README doc * Formatting Fixed snake_case to camelCase Changed delete to delete[] Turned magic constant to a named variable
1 parent 8446784 commit e2d265f

File tree

4 files changed

+131
-60
lines changed

4 files changed

+131
-60
lines changed

README.md

+78-55
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
[![Build Status](https://travis-ci.org/projectM-visualizer/projectm.svg?branch=master)](https://travis-ci.org/projectM-visualizer/projectm)
22

3-
43
![Logo](https://github.com/projectM-visualizer/projectm/raw/master/web/logo.png)
54

65
## projectM - The most advanced open-source music visualizer
@@ -12,54 +11,67 @@ projectM is an open-source project that reimplements the esteemed [Winamp Milkdr
1211
Its purpose in life is to read an audio input and to produce mesmerizing visuals, detecting tempo, and rendering advanced equations into a limitless array of user-contributed visualizations.
1312

1413
### Available For
14+
1515
##### Windows
16-
* [Standalone](https://github.com/projectM-visualizer/projectm/releases) ([latest build](https://ci.appveyor.com/project/revmischa/projectm/build/artifacts)) - (Requires the latest [Visual C++ redistributable](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads))
17-
* [Steam](https://store.steampowered.com/app/1358800/projectM_Music_Visualizer/)
18-
* [Windows Store](https://www.microsoft.com/store/apps/9NDCVH0VCWJN)
16+
17+
- [Standalone](https://github.com/projectM-visualizer/projectm/releases) ([latest build](https://ci.appveyor.com/project/revmischa/projectm/build/artifacts)) - (Requires the latest [Visual C++ redistributable](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads))
18+
- [Steam](https://store.steampowered.com/app/1358800/projectM_Music_Visualizer/)
19+
- [Windows Store](https://www.microsoft.com/store/apps/9NDCVH0VCWJN)
20+
1921
#### macOS
20-
* [Standalone](https://github.com/projectM-visualizer/projectm/releases)
21-
* [Steam](https://store.steampowered.com/app/1358800/projectM_Music_Visualizer/)
22-
* [Music.app Plugin](https://github.com/projectM-visualizer/projectm/releases/)
23-
* [Brew](https://formulae.brew.sh/formula/projectm)
22+
23+
- [Standalone](https://github.com/projectM-visualizer/projectm/releases)
24+
- [Steam](https://store.steampowered.com/app/1358800/projectM_Music_Visualizer/)
25+
- [Music.app Plugin](https://github.com/projectM-visualizer/projectm/releases/)
26+
- [Brew](https://formulae.brew.sh/formula/projectm)
27+
2428
#### Linux
25-
* [Steam](https://store.steampowered.com/app/1358800/projectM_Music_Visualizer/)
26-
* Check your repository for a binary release.
29+
30+
- [Steam](https://store.steampowered.com/app/1358800/projectM_Music_Visualizer/)
31+
- Check your repository for a binary release.
32+
2733
#### Android
28-
* [Google Play](https://play.google.com/store/apps/details?id=com.psperl.prjM)
34+
35+
- [Google Play](https://play.google.com/store/apps/details?id=com.psperl.prjM)
36+
2937
#### Xbox / Windows Phone
30-
* [Windows Store](https://www.microsoft.com/store/apps/9NDCVH0VCWJN)
38+
39+
- [Windows Store](https://www.microsoft.com/store/apps/9NDCVH0VCWJN)
40+
3141
#### Other
32-
* [Source code](https://github.com/projectM-visualizer/projectm/)
33-
* [Qt5](https://www.qt.io/)-based [PulseAudio](https://www.freedesktop.org/wiki/Software/PulseAudio/) and JACK desktop apps in [source code](https://github.com/projectM-visualizer/projectm/)
34-
* [ALSA, XMMS, Winamp, JACK](https://sourceforge.net/projects/projectm/files/) (source, unmaintained)
42+
43+
- [Source code](https://github.com/projectM-visualizer/projectm/)
44+
- [Qt5](https://www.qt.io/)-based [PulseAudio](https://www.freedesktop.org/wiki/Software/PulseAudio/) and JACK desktop apps in [source code](https://github.com/projectM-visualizer/projectm/)
45+
- [ALSA, XMMS, Winamp, JACK](https://sourceforge.net/projects/projectm/files/) (source, unmaintained)
3546

3647
### Discord chat
48+
3749
[Chat with us on Discord.](https://discord.gg/tpEuywB)
3850

3951
### Demo Video
40-
[![](http://img.youtube.com/vi/2dSam8zwSFw/0.jpg)](http://www.youtube.com/watch?v=2dSam8zwSFw "Demo")
4152

53+
[![](http://img.youtube.com/vi/2dSam8zwSFw/0.jpg)](http://www.youtube.com/watch?v=2dSam8zwSFw "Demo")
4254

4355
### Presets
56+
4457
The preset files define the visualizations via pixel shaders and Milkdrop-style equations and parameters. Included with projectM are the bltc201, Milkdrop 1 and 2, projectM, tryptonaut and yin collections. You can grab these presets [here](http://spiegelmc.com/pub/projectm_presets.zip).
4558

4659
You can also download an enormous 41,000 preset pack of presets [here](https://mischa.lol/projectM/presets_community.zip) (123MB zipped).
4760

48-
4961
### Also Featured In
62+
5063
[![Kodi](https://github.com/projectM-visualizer/projectm/raw/master/web/kodi.png) Kodi (formerly XBMC)](https://kodi.tv/)
5164

5265
[![Helix](https://github.com/projectM-visualizer/projectm/raw/master/web/helix.jpg) Helix](http://ghostfiregames.com/helixhome.html)
5366

54-
5567
[![Silverjuke](https://github.com/projectM-visualizer/projectm/raw/master/web/silverjuke.png) Silverjuke (FOSS Jukebox)](https://www.silverjuke.net)
5668

5769
[<img src="https://silentradiance.com/demos/projectM_vr/projectm_vr.png" width="200" > Silent Radiance Distance Disco](https://silentradiance.com)
5870

59-
60-
***
71+
---
6172

6273
## Screenshots
74+
6375
![Screenshot](https://github.com/projectM-visualizer/projectm/raw/master/src/projectM-MusicPlugin/projectM%20screenshots/Screen%20Shot%202014-08-25%20at%2012.31.20%20AM.png)
6476

6577
![Screenshot](https://github.com/projectM-visualizer/projectm/raw/master/src/projectM-MusicPlugin/projectM%20screenshots/Screen%20Shot%202014-08-25%20at%2012.33.50%20AM.png)
@@ -77,75 +89,86 @@ You can also download an enormous 41,000 preset pack of presets [here](https://m
7789
![Screenshot](https://github.com/projectM-visualizer/projectm/raw/master/src/projectM-MusicPlugin/projectM%20screenshots/Screen%20Shot%202014-08-25%20at%2012.31.07%20AM.png)
7890

7991
![Screenshot](https://silentradiance.com/demos/projectM_vr/projectm_vr.png)
80-
***
92+
93+
---
8194

8295
## Architecture
83-
* [Article](https://lwn.net/Articles/750152/)
96+
97+
- [Article](https://lwn.net/Articles/750152/)
8498

8599
# Building from source
100+
86101
See [BUILDING.md](BUILDING.md)
87102

88103
# Keyboard Controls:
89-
* Up: increase beat sensitivity (max 5)
90-
* Down: decrease beat sensitivity (min 0)
91-
* Y: toggle shuffle enabled
92-
* R: jump to random preset
93-
* N or P: next or previous preset (hard transition)
94-
* Shift-N or Shift-P: next or previous preset (soft transition)
95-
* L: lock current preset
96-
97-
* H or F1: show help (if supported)
98-
* M: Open preset navigation menu (if supported)
99-
* F3: show preset (if supported)
100-
* F4: show stats (if supported)
101-
* F5: show FPS (if supported)
104+
105+
- Up: increase beat sensitivity (max 5)
106+
- Down: decrease beat sensitivity (min 0)
107+
- Y: toggle shuffle enabled
108+
- R: jump to random preset
109+
- N or P: next or previous preset (hard transition)
110+
- Shift-N or Shift-P: next or previous preset (soft transition)
111+
- L: lock current preset
112+
- D: Save current frame to file
113+
114+
- H or F1: show help (if supported)
115+
- M: Open preset navigation menu (if supported)
116+
- F3: show preset (if supported)
117+
- F4: show stats (if supported)
118+
- F5: show FPS (if supported)
102119

103120
#### Only ProjectM SDL:
104-
* Cmd/Ctrl-Q: *q*uit
105-
* Cmd/Ctrl-I: select next audio *i*nput device
106-
* Cmd/Ctrl-S: *s*tretch monitors
107-
* Cmd/Ctrl-M: change *m*onitor
108-
* Cmd/Ctrl-F: toggle *f*ull screen
109-
* Mouse Scroll Up / Down: next or previous preset (hard transition)
110-
* Return: search for preset (RETURN or ESCAPE to exit search)
111-
* Space: lock current preset
112121

122+
- Cmd/Ctrl-Q: *q*uit
123+
- Cmd/Ctrl-I: select next audio *i*nput device
124+
- Cmd/Ctrl-S: *s*tretch monitors
125+
- Cmd/Ctrl-M: change *m*onitor
126+
- Cmd/Ctrl-F: toggle *f*ull screen
127+
- Mouse Scroll Up / Down: next or previous preset (hard transition)
128+
- Return: search for preset (RETURN or ESCAPE to exit search)
129+
- Space: lock current preset
113130

114131
# Using the library
132+
115133
At its core projectM is a library, [libprojectM](src/libprojectM). This library is responsible for parsing presets, analyzing audio PCM data with beat detection and FFT, applying the preset to the audio feature data and rendering the resulting output with openGL. It can render to an OpenGL context or a texture.
116134

117135
To look at a simple example way of using the library see the [libSDL2 sample code](src/projectM-sdl/projectM_SDL_main.cpp).
118136

119137
There are many other applications that make use of libprojectM and that can be found in the [src](src/) directory.
120138

121-
***
139+
---
122140

123141
# Todo
124-
* Steal cool stuff from the recently-released Milkdrop source.
125-
* Finish [emscripten support](https://github.com/projectM-visualizer/projectm/pull/307) for building to wasm/webGL for the web.
126-
* Update the [various implementations using libprojectM](src).
127-
* Update downstream projects with new versions.
128142

129-
***
143+
- Steal cool stuff from the recently-released Milkdrop source.
144+
- Finish [emscripten support](https://github.com/projectM-visualizer/projectm/pull/307) for building to wasm/webGL for the web.
145+
- Update the [various implementations using libprojectM](src).
146+
- Update downstream projects with new versions.
147+
148+
---
130149

131150
## Help
151+
132152
Report issues on [GitHub](https://github.com/projectM-visualizer/projectm/issues/new)
133153

134154
[Chat with us on Discord.](https://discord.gg/tpEuywB).
135155

136156
If you would like to help improve this project, either with documentation, code, porting, hardware or anything else please let us know! We gladly accept pull requests and issues.
137157

138158
## Maintainers
159+
139160
If you maintain packages of libprojectM, we are happy to work with you! Please note well:
140-
* The main focus of this project is libprojectM. It's a library that only really depends on OpenGL. The other applications are more like examples and demos.
141-
* Most of the applications (e.g. `src/projectM-*`) are likely outdated and of less utility than the core library. If you desire to use them or depend on them, please file an issue so we can help update them.
142-
* The "canonical" application for actually viewing the visualizations is now projectM-sdl, based on libSDL2 because it supports audio input and is completely cross-platform.
143-
* This is an open source project! If you don't like something, feel free to contribute improvements!
144-
* Yes, you are looking at the official version. This is not a fork.
161+
162+
- The main focus of this project is libprojectM. It's a library that only really depends on OpenGL. The other applications are more like examples and demos.
163+
- Most of the applications (e.g. `src/projectM-*`) are likely outdated and of less utility than the core library. If you desire to use them or depend on them, please file an issue so we can help update them.
164+
- The "canonical" application for actually viewing the visualizations is now projectM-sdl, based on libSDL2 because it supports audio input and is completely cross-platform.
165+
- This is an open source project! If you don't like something, feel free to contribute improvements!
166+
- Yes, you are looking at the official version. This is not a fork.
145167

146168
## Authors
147-
[Authors](https://github.com/projectM-visualizer/projectm/raw/master/AUTHORS.txt)
148169

170+
[Authors](https://github.com/projectM-visualizer/projectm/raw/master/AUTHORS.txt)
149171

150172
## License
173+
151174
[LGPL](https://github.com/projectM-visualizer/projectm/raw/master/LICENSE.txt)

src/libprojectM/KeyHandler.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ void projectM::default_key_handler( projectMEvent event, projectMKeycode keycode
311311
renderer->studio = !renderer->studio;
312312
case PROJECTM_K_i:
313313
break;
314+
case PROJECTM_K_d: // d stands for write DEBUG output.
315+
renderer->writeNextFrameToFile = true;
316+
break;
314317
case PROJECTM_K_RETURN:
315318
renderer->toggleSearchText();
316319
if (renderer->showsearch) {

src/libprojectM/Renderer/Renderer.cpp

+43
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#include "MilkdropWaveform.hpp"
88
#include <iostream>
99
#include <algorithm>
10+
#include <cstdio>
11+
#include <cstring>
12+
#include <sys/select.h>
1013
#include <sys/stat.h>
1114
#include <cassert>
1215
#include "omptl/omptl"
@@ -16,6 +19,7 @@
1619
#include <iostream>
1720
#include <chrono>
1821
#include <ctime>
22+
#include "stb_image_write.h"
1923

2024
using namespace std::chrono;
2125

@@ -411,6 +415,11 @@ void Renderer::FinishPass1()
411415
draw_title_to_texture();
412416

413417
textureManager->updateMainTexture();
418+
if(writeNextFrameToFile) {
419+
debugWriteMainTextureToFile();
420+
writeNextFrameToFile = false;
421+
}
422+
414423
}
415424

416425
void Renderer::Pass2(const Pipeline& pipeline, const PipelineContext& pipelineContext)
@@ -839,6 +848,40 @@ void Renderer::deleteSearchText()
839848
}
840849
}
841850

851+
852+
853+
void Renderer::debugWriteMainTextureToFile() const {
854+
GLuint fbo;
855+
auto mainTexture = textureManager->getMainTexture();
856+
857+
const auto safeWriteFile = [](const auto frameNumber, auto data, const auto width, const auto height) {
858+
static const std::string prefix{"frame_texture_contents-"};
859+
const auto prefixLen = prefix.size();
860+
constexpr auto fileNameMaxLength = 150;
861+
constexpr auto fileExtensionLength = 4;
862+
char fileNameBuffer[fileNameMaxLength];
863+
std::memcpy(fileNameBuffer, prefix.data(), prefixLen);
864+
auto t = std::time(nullptr);
865+
auto tm = *std::localtime(&t);
866+
const auto bytesWritten = std::strftime(fileNameBuffer + prefixLen, fileNameMaxLength - prefixLen, "%Y-%m-%d-%H:%M:%S", &tm);
867+
const auto offset = prefixLen + bytesWritten;
868+
const auto spaceLeft = fileNameMaxLength - offset;
869+
std::snprintf(fileNameBuffer + offset, spaceLeft - fileExtensionLength, "%d.bmp", frameNumber);
870+
stbi_write_bmp( fileNameBuffer, width, height, 4, data);
871+
};
872+
873+
glGenFramebuffers(1, &fbo);
874+
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
875+
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mainTexture->texID, 0);
876+
auto dataSize = mainTexture->width * mainTexture->height * 4;
877+
GLubyte* pixels = new GLubyte[dataSize];
878+
glReadPixels(0, 0, mainTexture->width, mainTexture->height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
879+
glBindFramebuffer(GL_FRAMEBUFFER, 0);
880+
glDeleteFramebuffers(1, &fbo);
881+
safeWriteFile(totalframes, pixels, mainTexture->width, mainTexture->height);
882+
delete[] pixels;
883+
}
884+
842885
void Renderer::setToastMessage(const std::string& theValue)
843886
{
844887
// Initialize counters

src/libprojectM/Renderer/Renderer.hpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class Renderer
8686
bool correction;
8787

8888
bool noSwitch;
89+
bool writeNextFrameToFile;
8990

9091
struct preset {
9192
int id;
@@ -123,7 +124,7 @@ class Renderer
123124

124125
Renderer(int width, int height, int gx, int gy, BeatDetect *_beatDetect, std::string presetURL, std::string title_fontURL, std::string menu_fontURL, const std::string& datadir = "");
125126
~Renderer();
126-
127+
127128
void RenderFrame(const Pipeline &pipeline, const PipelineContext &pipelineContext);
128129
void RenderFrameOnlyPass1(const Pipeline &pipeline, const PipelineContext &pipelineContext);
129130
void RenderFrameOnlyPass2(const Pipeline &pipeline, const PipelineContext &pipelineContext,int xoffset,int yoffset,int eye);
@@ -146,15 +147,15 @@ class Renderer
146147
}
147148

148149
void setHelpText(const std::string& theValue) {
149-
m_helpText = theValue;
150+
m_helpText = theValue;
150151
}
151152

152153
std::string helpText() const {
153154
return m_helpText;
154155
}
155156

156157
void setFPS(const int &theValue) {
157-
m_fps = std::to_string(theValue);
158+
m_fps = std::to_string(theValue);
158159
}
159160

160161
std::string fps() const {
@@ -172,13 +173,14 @@ class Renderer
172173
void touchDestroy(float x, float y);
173174
void touchDestroyAll();
174175
bool touchedWaveform(float x, float y, std::size_t i);
175-
176+
176177
void setToastMessage(const std::string& theValue);
177178
std::string getSearchText() const;
178179
void setSearchText(const std::string& theValue);
179180
void resetSearchText();
180181
void deleteSearchText();
181-
182+
/// Writes the contents of current mainTexture in TextureManager to a bmp file
183+
void debugWriteMainTextureToFile() const;
182184
std::string toastMessage() const {
183185
return m_toastMessage;
184186
}

0 commit comments

Comments
 (0)