Music visualizers often look really cool, especially at first. But after a time they may seem too repetitive, even boring. Therefore, in our design, we'll build the ability to queue up a number of different visualizations, and then, after a period of time, transition from one to the next.
To begin our implementation, we'll define an architecture structure that will be expandable and let us develop new visualizations as we go along.
However, even before that, we must ensure that the app has permission to use the Android audio features we need. Add the following directives to AndroidManifest.xml
:
<!-- Visualizer permissions --> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
Remember that the RenderBox
library, first developed in Chapter 5, RenderBox Engine, allows MainActivity
to delegate much of the graphics and Cardboard VR work to the RenderBox
class and associated classes (Component
, Material
, and so on). We will follow a similar design pattern here, built on top of RenderBox
. MainActivity
can instantiate specific visualizations and then delegate the work to the VisualizerBox
class.
The VisualizerBox
class will provide the callback functions to the Android Visualizer
class. Let's define a skeletal implementation of this first. Create a VisualizerBox
Java class, as follows:
public class VisualizerBox { static final String TAG = "VisualizerBox"; public VisualizerBox(final CardboardView cardboardView){ } public void setup() { } public void preDraw() { } public void postDraw() { } }
Integrate VisualizerBox
into MainActivity
, adding a visualizerBox
variable at the top of the class. In MainActivity
, add the following line:
VisualizerBox visualizerBox;
Initialize it in onCreate
:
visualizerBox = new VisualizerBox(cardboardView);
Also, in MainActivity
, call the corresponding version of each of the IRenderBox
interface methods:
@Override public void setup() { visualizerBox.setup(); } @Override public void preDraw() { visualizerBox.preDraw(); } @Override public void postDraw() { visualizerBox.postDraw(); }
Good. Now we'll set up VisualizerBox
to let you build and use one or more visualizations. So, first let's define the abstract Visualization
class in the Visualization.java
file, as follows:
public abstract class Visualization { VisualizerBox visualizerBox; //owner public Visualization(VisualizerBox visualizerBox){ this.visualizerBox = visualizerBox; } public abstract void setup(); public abstract void preDraw(); public abstract void postDraw(); }
Now we have a mechanism to create a variety of visualization implementations for the app. Before we go ahead and start writing one of those, let's also provide the integration with VisualizerBox
. At the top of the VisualizerBox
class, add a variable to the current activeViz
object:
public Visualization activeViz;
Then, call it from the interface methods:
public void setup() { if(activeViz != null) activeViz.setup(); } public void preDraw() { if(activeViz != null) activeViz.preDraw(); } public void postDraw() { if(activeViz != null) activeViz.postDraw(); }
Of course, we're not even using the Android Visualizer
class yet and not rendering anything on the screen. That'll come next.
For now, let's create a placeholder for a visualization. Create a new folder in your project named visualizations
. Right-click on your Java code folder (for example, java/com/cardbookvr/visualizevr/
), go to New | Package, and name it visualizations
. Then, right click on the new visualizations
folder, go to New | Java Class, and name it BlankVisualization
. Then, define it as extends Visualization
as follows:
public class BlankVisualization extends Visualization { static final String TAG = "BlankVisualization"; public BlankVisualization(VisualizerBox visualizerBox) { super(visualizerBox); } @Override public void setup() { } @Override public void preDraw() { } @Override public void postDraw() { } }
We'll be able to use this as a template for specific visualizers. The purpose of each method is pretty self-explanatory:
Now let's add some meat to this skeleton.