| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <cassert> | |
| 6 #include <cmath> | |
| 7 #include <limits> | |
| 8 #include <sstream> | |
| 9 #include "ppapi/cpp/audio.h" | |
| 10 #include "ppapi/cpp/instance.h" | |
| 11 #include "ppapi/cpp/module.h" | |
| 12 #include "ppapi/cpp/var.h" | |
| 13 | |
| 14 namespace { | |
| 15 const char* const kPlaySoundId = "playSound"; | |
| 16 const char* const kStopSoundId = "stopSound"; | |
| 17 const char* const kSetFrequencyId = "setFrequency"; | |
| 18 static const char kMessageArgumentSeparator = ':'; | |
| 19 | |
| 20 const double kDefaultFrequency = 440.0; | |
| 21 const double kPi = 3.141592653589; | |
| 22 const double kTwoPi = 2.0 * kPi; | |
| 23 // The sample count we will request. | |
| 24 const uint32_t kSampleFrameCount = 4096u; | |
| 25 // Only supporting stereo audio for now. | |
| 26 const uint32_t kChannels = 2u; | |
| 27 } // namespace | |
| 28 | |
| 29 namespace sine_synth { | |
| 30 // The Instance class. One of these exists for each instance of your NaCl | |
| 31 // module on the web page. The browser will ask the Module object to create | |
| 32 // a new Instance for each occurrence of the <embed> tag that has these | |
| 33 // attributes: | |
| 34 // type="application/x-nacl" | |
| 35 // src="sine_synth.nmf" | |
| 36 class SineSynthInstance : public pp::Instance { | |
| 37 public: | |
| 38 explicit SineSynthInstance(PP_Instance instance) | |
| 39 : pp::Instance(instance), | |
| 40 frequency_(kDefaultFrequency), | |
| 41 theta_(0), | |
| 42 sample_frame_count_(kSampleFrameCount) {} | |
| 43 virtual ~SineSynthInstance() {} | |
| 44 | |
| 45 // Called by the browser once the NaCl module is loaded and ready to | |
| 46 // initialize. Creates a Pepper audio context and initializes it. Returns | |
| 47 // true on success. Returning false causes the NaCl module to be deleted and | |
| 48 // no other functions to be called. | |
| 49 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]); | |
| 50 | |
| 51 // Called by the browser to handle the postMessage() call in Javascript. | |
| 52 // |var_message| is expected to be a string that contains the name of the | |
| 53 // method to call. Note that the setFrequency method takes a single | |
| 54 // parameter, the frequency. The frequency parameter is encoded as a string | |
| 55 // and appended to the 'setFrequency' method name after a ':'. Examples | |
| 56 // of possible message strings are: | |
| 57 // playSound | |
| 58 // stopSound | |
| 59 // setFrequency:880 | |
| 60 // If |var_message| is not a recognized method name, this method does nothing. | |
| 61 virtual void HandleMessage(const pp::Var& var_message); | |
| 62 | |
| 63 // Set the frequency of the sine wave to |frequency|. Posts a message back | |
| 64 // to the browser with the new frequency value. | |
| 65 void SetFrequency(double frequency); | |
| 66 | |
| 67 // The frequency property accessor. | |
| 68 double frequency() const { return frequency_; } | |
| 69 | |
| 70 private: | |
| 71 static void SineWaveCallback(void* samples, | |
| 72 uint32_t buffer_size, | |
| 73 void* data) { | |
| 74 SineSynthInstance* sine_synth_instance = | |
| 75 reinterpret_cast<SineSynthInstance*>(data); | |
| 76 const double frequency = sine_synth_instance->frequency(); | |
| 77 const double delta = kTwoPi * frequency / PP_AUDIOSAMPLERATE_44100; | |
| 78 const int16_t max_int16 = std::numeric_limits<int16_t>::max(); | |
| 79 | |
| 80 int16_t* buff = reinterpret_cast<int16_t*>(samples); | |
| 81 | |
| 82 // Make sure we can't write outside the buffer. | |
| 83 assert(buffer_size >= (sizeof(*buff) * kChannels * | |
| 84 sine_synth_instance->sample_frame_count_)); | |
| 85 | |
| 86 for (size_t sample_i = 0; | |
| 87 sample_i < sine_synth_instance->sample_frame_count_; | |
| 88 ++sample_i, sine_synth_instance->theta_ += delta) { | |
| 89 // Keep theta_ from going beyond 2*Pi. | |
| 90 if (sine_synth_instance->theta_ > kTwoPi) { | |
| 91 sine_synth_instance->theta_ -= kTwoPi; | |
| 92 } | |
| 93 double sin_value(std::sin(sine_synth_instance->theta_)); | |
| 94 int16_t scaled_value = static_cast<int16_t>(sin_value * max_int16); | |
| 95 for (size_t channel = 0; channel < kChannels; ++channel) { | |
| 96 *buff++ = scaled_value; | |
| 97 } | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 pp::Audio audio_; | |
| 102 double frequency_; | |
| 103 | |
| 104 // The last parameter sent to the sin function. Used to prevent sine wave | |
| 105 // skips on buffer boundaries. | |
| 106 double theta_; | |
| 107 | |
| 108 // The count of sample frames per channel in an audio buffer. | |
| 109 uint32_t sample_frame_count_; | |
| 110 }; | |
| 111 | |
| 112 bool SineSynthInstance::Init(uint32_t argc, | |
| 113 const char* argn[], | |
| 114 const char* argv[]) { | |
| 115 // Ask the device for an appropriate sample count size. | |
| 116 sample_frame_count_ = pp::AudioConfig::RecommendSampleFrameCount( | |
| 117 this, PP_AUDIOSAMPLERATE_44100, kSampleFrameCount); | |
| 118 audio_ = pp::Audio( | |
| 119 this, | |
| 120 pp::AudioConfig(this, PP_AUDIOSAMPLERATE_44100, sample_frame_count_), | |
| 121 SineWaveCallback, | |
| 122 this); | |
| 123 return true; | |
| 124 } | |
| 125 | |
| 126 void SineSynthInstance::HandleMessage(const pp::Var& var_message) { | |
| 127 if (!var_message.is_string()) { | |
| 128 return; | |
| 129 } | |
| 130 std::string message = var_message.AsString(); | |
| 131 if (message == kPlaySoundId) { | |
| 132 audio_.StartPlayback(); | |
| 133 } else if (message == kStopSoundId) { | |
| 134 audio_.StopPlayback(); | |
| 135 } else if (message.find(kSetFrequencyId) == 0) { | |
| 136 // The argument to setFrequency is everything after the first ':'. | |
| 137 size_t sep_pos = message.find_first_of(kMessageArgumentSeparator); | |
| 138 if (sep_pos != std::string::npos) { | |
| 139 std::string string_arg = message.substr(sep_pos + 1); | |
| 140 // Got the argument value as a string: try to convert it to a number. | |
| 141 std::istringstream stream(string_arg); | |
| 142 double double_value; | |
| 143 if (stream >> double_value) { | |
| 144 SetFrequency(double_value); | |
| 145 return; | |
| 146 } | |
| 147 } | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 void SineSynthInstance::SetFrequency(double frequency) { | |
| 152 frequency_ = frequency; | |
| 153 PostMessage(pp::Var(frequency_)); | |
| 154 } | |
| 155 | |
| 156 // The Module class. The browser calls the CreateInstance() method to create | |
| 157 // an instance of your NaCl module on the web page. The browser creates a new | |
| 158 // instance for each <embed> tag with type="application/x-nacl". | |
| 159 class SineSynthModule : public pp::Module { | |
| 160 public: | |
| 161 SineSynthModule() : pp::Module() {} | |
| 162 ~SineSynthModule() {} | |
| 163 | |
| 164 // Create and return a HelloWorldInstance object. | |
| 165 virtual pp::Instance* CreateInstance(PP_Instance instance) { | |
| 166 return new SineSynthInstance(instance); | |
| 167 } | |
| 168 }; | |
| 169 | |
| 170 } // namespace sine_synth | |
| 171 | |
| 172 // Factory function called by the browser when the module is first loaded. | |
| 173 // The browser keeps a singleton of this module. It calls the | |
| 174 // CreateInstance() method on the object you return to make instances. There | |
| 175 // is one instance per <embed> tag on the page. This is the main binding | |
| 176 // point for your NaCl module with the browser. | |
| 177 namespace pp { | |
| 178 Module* CreateModule() { return new sine_synth::SineSynthModule(); } | |
| 179 } // namespace pp | |
| OLD | NEW |