Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2018 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <utils/logging.h> |
| 18 | #include <thread> |
| 19 | |
| 20 | #include "Game.h" |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 21 | |
| 22 | Game::Game(AAssetManager *assetManager): mAssetManager(assetManager) { |
| 23 | } |
| 24 | |
| 25 | void Game::start() { |
| 26 | |
Don Turner | f7923ae | 2018-04-03 22:43:27 +0100 | [diff] [blame] | 27 | // Load the RAW PCM data files for both the clap sound and backing track into memory. |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 28 | mClap = SoundRecording::loadFromAssets(mAssetManager, "CLAP.raw"); |
| 29 | mBackingTrack = SoundRecording::loadFromAssets(mAssetManager, "FUNKY_HOUSE.raw" ); |
| 30 | mBackingTrack->setPlaying(true); |
| 31 | mBackingTrack->setLooping(true); |
| 32 | |
Don Turner | f7923ae | 2018-04-03 22:43:27 +0100 | [diff] [blame] | 33 | // Add the clap and backing track sounds to a mixer so that they can be played together |
| 34 | // simultaneously using a single audio stream. |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 35 | mMixer.addTrack(mClap); |
| 36 | mMixer.addTrack(mBackingTrack); |
| 37 | |
Don Turner | f7923ae | 2018-04-03 22:43:27 +0100 | [diff] [blame] | 38 | // Add the audio frame numbers on which the clap sound should be played to the clap event queue. |
| 39 | // The backing track tempo is 120 beats per minute, which is 2 beats per second. At a sample |
| 40 | // rate of 48000 frames per second this means a beat occurs every 24000 frames, starting at |
| 41 | // zero. So the first 3 beats are: 0, 24000, 48000 |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 42 | mClapEvents.push(0); |
| 43 | mClapEvents.push(24000); |
| 44 | mClapEvents.push(48000); |
| 45 | |
Don Turner | f7923ae | 2018-04-03 22:43:27 +0100 | [diff] [blame] | 46 | // We want the user to tap on the screen exactly 4 beats after the first clap. 4 beats is |
| 47 | // 96000 frames, so we just add 96000 to the above frame numbers. |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 48 | mClapWindows.push(96000); |
| 49 | mClapWindows.push(120000); |
| 50 | mClapWindows.push(144000); |
| 51 | |
Don Turner | f7923ae | 2018-04-03 22:43:27 +0100 | [diff] [blame] | 52 | // Create a builder |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 53 | AudioStreamBuilder builder; |
| 54 | builder.setFormat(AudioFormat::I16); |
| 55 | builder.setChannelCount(2); |
Don Turner | 7e69661 | 2018-04-09 22:11:34 +0100 | [diff] [blame] | 56 | builder.setSampleRate(kSampleRateHz); |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 57 | builder.setCallback(this); |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 58 | builder.setPerformanceMode(PerformanceMode::LowLatency); |
| 59 | builder.setSharingMode(SharingMode::Exclusive); |
| 60 | |
Don Turner | f7923ae | 2018-04-03 22:43:27 +0100 | [diff] [blame] | 61 | Result result = builder.openStream(&mAudioStream); |
| 62 | if (result != Result::OK){ |
| 63 | LOGE("Failed to open stream. Error: %s", convertToText(result)); |
| 64 | } |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 65 | |
Don Turner | f7923ae | 2018-04-03 22:43:27 +0100 | [diff] [blame] | 66 | // Reduce stream latency by setting the buffer size to a multiple of the burst size |
Don Turner | b7495ad | 2018-06-07 16:07:32 +0100 | [diff] [blame] | 67 | auto setBufferSizeResult = mAudioStream->setBufferSizeInFrames( |
Don Turner | f7923ae | 2018-04-03 22:43:27 +0100 | [diff] [blame] | 68 | mAudioStream->getFramesPerBurst() * kBufferSizeInBursts); |
Don Turner | b7495ad | 2018-06-07 16:07:32 +0100 | [diff] [blame] | 69 | if (setBufferSizeResult != Result::OK){ |
Don Turner | 75241ba | 2018-05-07 20:03:40 -0700 | [diff] [blame] | 70 | LOGW("Failed to set buffer size. Error: %s", convertToText(setBufferSizeResult.error())); |
| 71 | } |
Don Turner | f7923ae | 2018-04-03 22:43:27 +0100 | [diff] [blame] | 72 | |
| 73 | result = mAudioStream->requestStart(); |
| 74 | if (result != Result::OK){ |
| 75 | LOGE("Failed to start stream. Error: %s", convertToText(result)); |
| 76 | } |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 77 | } |
| 78 | |
| 79 | void Game::tap(int64_t eventTimeAsUptime) { |
| 80 | mClap->setPlaying(true); |
| 81 | |
| 82 | int64_t nextClapWindowFrame; |
| 83 | if (mClapWindows.pop(nextClapWindowFrame)){ |
| 84 | |
| 85 | int64_t frameDelta = nextClapWindowFrame - mCurrentFrame; |
Don Turner | 7e69661 | 2018-04-09 22:11:34 +0100 | [diff] [blame] | 86 | int64_t timeDelta = convertFramesToMillis(frameDelta, kSampleRateHz); |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 87 | int64_t windowTime = mLastUpdateTime + timeDelta; |
| 88 | TapResult result = getTapResult(eventTimeAsUptime, windowTime); |
| 89 | mUiEvents.push(result); |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | void Game::tick(){ |
| 94 | |
| 95 | TapResult r; |
| 96 | if (mUiEvents.pop(r)) { |
| 97 | renderEvent(r); |
| 98 | } else { |
Don Turner | f7923ae | 2018-04-03 22:43:27 +0100 | [diff] [blame] | 99 | SetGLScreenColor(kScreenBackgroundColor); |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 100 | } |
| 101 | } |
| 102 | |
| 103 | void Game::onSurfaceCreated() { |
Don Turner | f7923ae | 2018-04-03 22:43:27 +0100 | [diff] [blame] | 104 | SetGLScreenColor(kScreenBackgroundColor); |
Don Turner | 0db81a4 | 2018-03-29 17:48:12 +0100 | [diff] [blame] | 105 | } |
| 106 | |
| 107 | void Game::onSurfaceChanged(int widthInPixels, int heightInPixels) { |
| 108 | } |
| 109 | |
| 110 | void Game::onSurfaceDestroyed() { |
| 111 | } |
| 112 | |
| 113 | DataCallbackResult Game::onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) { |
| 114 | |
| 115 | int64_t nextClapEvent; |
| 116 | |
| 117 | for (int i = 0; i < numFrames; ++i) { |
| 118 | |
| 119 | if (mClapEvents.peek(nextClapEvent) && mCurrentFrame == nextClapEvent){ |
| 120 | mClap->setPlaying(true); |
| 121 | mClapEvents.pop(nextClapEvent); |
| 122 | } |
| 123 | mMixer.renderAudio(static_cast<int16_t*>(audioData)+(kChannelCount*i), 1); |
| 124 | mCurrentFrame++; |
| 125 | } |
| 126 | |
| 127 | mLastUpdateTime = nowUptimeMillis(); |
| 128 | |
| 129 | return DataCallbackResult::Continue; |
| 130 | } |
| 131 | |