1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Needed on Windows to get |M_PI| from math.h.
#ifdef _WIN32
#define _USE_MATH_DEFINES
#endif
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <limits>
#include "ppapi/c/pp_errors.h"
#include "ppapi/cpp/audio.h"
#include "ppapi/cpp/audio_config.h"
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/view.h"
// Separate left and right frequency to make sure we didn't swap L & R.
// Sounds pretty horrible, though...
const double kLeftFrequency = 400;
const double kRightFrequency = 1000;
// This sample frequency is guaranteed to work.
const PP_AudioSampleRate kDefaultSampleRate = PP_AUDIOSAMPLERATE_44100;
const uint32_t kDefaultSampleCount = 4096;
const char kSampleRateAttributeName[] = "samplerate";
class MyInstance : public pp::Instance {
public:
explicit MyInstance(PP_Instance instance)
: pp::Instance(instance),
visible_(false),
sample_rate_(kDefaultSampleRate),
sample_count_(0),
audio_wave_l_(0.0),
audio_wave_r_(0.0) {
}
virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
for (uint32_t i = 0; i < argc; i++) {
if (strcmp(kSampleRateAttributeName, argn[i]) == 0) {
int value = atoi(argv[i]);
if (value > 0 && value <= 1000000)
sample_rate_ = static_cast<PP_AudioSampleRate>(value);
else
return false;
}
}
pp::AudioConfig config;
sample_count_ = pp::AudioConfig::RecommendSampleFrameCount(
this, sample_rate_, kDefaultSampleCount);
config = pp::AudioConfig(this, sample_rate_, sample_count_);
audio_ = pp::Audio(this, config, SineWaveCallbackTrampoline, this);
return audio_.StartPlayback();
}
virtual void DidChangeView(const pp::View& view) {
// The frequency will change depending on whether the page is in the
// foreground or background.
visible_ = view.IsPageVisible();
}
private:
static void SineWaveCallbackTrampoline(void* samples,
uint32_t num_bytes,
void* thiz) {
static_cast<MyInstance*>(thiz)->SineWaveCallback(samples, num_bytes);
}
void SineWaveCallback(void* samples, uint32_t num_bytes) {
double delta_l = 2.0 * M_PI * kLeftFrequency / sample_rate_ /
(visible_ ? 1 : 2);
double delta_r = 2.0 * M_PI * kRightFrequency / sample_rate_ /
(visible_ ? 1 : 2);
// Use per channel audio wave value to avoid clicks on buffer boundries.
double wave_l = audio_wave_l_;
double wave_r = audio_wave_r_;
const int16_t max_int16 = std::numeric_limits<int16_t>::max();
int16_t* buf = reinterpret_cast<int16_t*>(samples);
for (size_t sample = 0; sample < sample_count_; ++sample) {
*buf++ = static_cast<int16_t>(sin(wave_l) * max_int16);
*buf++ = static_cast<int16_t>(sin(wave_r) * max_int16);
// Add delta, keep within -2 * M_PI .. 2 * M_PI to preserve precision.
wave_l += delta_l;
if (wave_l > 2.0 * M_PI)
wave_l -= 2.0 * M_PI;
wave_r += delta_r;
if (wave_r > 2.0 * M_PI)
wave_r -= 2.0 * M_PI;
}
// Store current value to use as starting point for next callback.
audio_wave_l_ = wave_l;
audio_wave_r_ = wave_r;
}
bool visible_;
PP_AudioSampleRate sample_rate_;
uint32_t sample_count_;
pp::Audio audio_;
// Current audio wave position, used to prevent sine wave skips
// on buffer boundaries.
double audio_wave_l_;
double audio_wave_r_;
};
class MyModule : public pp::Module {
public:
// Override CreateInstance to create your customized Instance object.
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new MyInstance(instance);
}
};
namespace pp {
// Factory function for your specialization of the Module object.
Module* CreateModule() {
return new MyModule();
}
} // namespace pp
|