Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RhythmGame sample #75

Merged
merged 5 commits into from
Apr 10, 2018
Merged

Add RhythmGame sample #75

merged 5 commits into from
Apr 10, 2018

Conversation

dturner
Copy link
Collaborator

@dturner dturner commented Mar 29, 2018

Adding a new sample which shows how to create a simple musical game. Please read the README before reviewing:

https://github.com/google/oboe/tree/rhythmgame/samples/RhythmGame

The main files which need reviewing are:

samples/RhythmGame/README.md
samples/RhythmGame/src/main/cpp/*

Copy link
Collaborator

@mnaganov mnaganov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for a delay. This is a big change.

mMixer.addTrack(mClap);
mMixer.addTrack(mBackingTrack);

mClapEvents.push(0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide a comment why we are doing this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

mClapWindows.push(144000);

AudioStreamBuilder builder;
builder.setFormat(AudioFormat::I16);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since setters of AudioStreamBuilder return a pointer to it, it's possible to chain these calls.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True but chaining the calls makes the code less maintainable because it's slightly more difficult to add and remove stream properties. Is there any advantage, other than not prefixing with builder.?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Omitting 'builder' removes clutter, so the code is easier to read. If you choose the first parameter to be something that is always needed to be set, and use a line per chained call, then adding / removing setters is no more difficult than in your version. Compare:

builder.setA();
builder.setB();
builder.setC();

builder.setA()
->setB()
->setC();

[Personally I would prefer setters that return "*this", so it's always "." prefix, but I guess we are stuck with what we have.]

But finally, up to you—there is no style guide for this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you add a setter you need to remove the trailing ; from the last line (in this case ->setC(); so there is some marginal extra overhead. Also, I find the difference between the initial . and subsequent ->s to be more visually cluttering (and slightly more confusing: "oh wait, a set method returns a pointer?") than the multiple instances of builder.. Not that bothered either way, but will probably leave as is.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I agree that returning a pointer from the setters hurts the looks of client code.


builder.openStream(&mAudioStream);

mAudioStream->setBufferSizeInFrames(mAudioStream->getFramesPerBurst() * 2);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you deliberately skipping checks for stream validity here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was deliberately skipping them when I live coded this example, however I shouldn't in this official sample. Fixed.

if (mClapWindows.pop(nextClapWindowFrame)){

int64_t frameDelta = nextClapWindowFrame - mCurrentFrame;
int64_t timeDelta = convertFramesToMillis(frameDelta, 48000);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

48000 should be some game-wide constant since you even mention it in the project description as the current limitation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if (mUiEvents.pop(r)) {
renderEvent(r);
} else {
SetGLScreenColor(GREY);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a constant in case anyone would like to customize the color scheme.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

#include <android/log.h>
#include <vector>

#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "rhythm_game", __VA_ARGS__))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a define for the tag name.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


@Override
public void surfaceDestroyed(SurfaceHolder holder) {
super.surfaceDestroyed(holder);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to run our code first, and then the base class code in this case?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it probably does. Changed.

super(context);

// Create an OpenGL ES context
/*if(BuildConfig.FLAVOR.equals("GL_3"))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove commented out code for clarity.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -0,0 +1,41 @@
/*
* Copyright 2017 Google Inc.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2018, AOSP?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

* - read/writes correct after wraparound (takes too long to run)
* - Constructing queue with non power of 2 capacity results in assert failure (needs death test)
* - Constructing queue with signed type results in assert failure (needs death test)
* - Multi-threaded read/writes (complicated to test)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MT is essential to test here, otherwise there is a big risk of running into very confusing problems at run time only.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Collaborator

@mnaganov mnaganov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just a few more comments.

Please decide what to do with your queue. It seems that you are planning to replace it with the one from Oboe.

// This defines the size of the tap window in milliseconds. For example, if defined at 100ms the
// player will have 100ms before and after the centre of the tap window to tap on the screen and
// be successful
constexpr int kWindowCenterOffset = 100;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add "Ms" suffix.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

#include "utils/LockFreeQueue.h"
#include "utils/UtilityFunctions.h"

constexpr int kSampleRate = 48000; // Fixed sample rate, see README
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add "Hz" suffix.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done



#include <cstdint>

class RenderableAudio {

public:
virtual ~RenderableAudio(){};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: It is recommended to put "= default" instead of using empty body.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. nits = better code 👍

mClapWindows.push(144000);

AudioStreamBuilder builder;
builder.setFormat(AudioFormat::I16);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I agree that returning a pointer from the setters hurts the looks of client code.

@dturner dturner merged commit 7e69661 into master Apr 10, 2018
@dturner dturner deleted the rhythmgame branch April 10, 2018 11:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants