or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdaudio.mdfiles.mdgraphics.mdindex.mdinput.mdnetworking.mdpreloader.mdwebaudio.mdwidgets.md

webaudio.mddocs/

0

# Web Audio API

1

2

The GWT backend provides advanced audio capabilities through Web Audio API integration, offering superior audio performance and features compared to basic HTML5 Audio. This system provides low-latency audio, advanced audio processing, and better mobile device support.

3

4

## Core Web Audio Classes

5

6

### WebAudioAPIManager { .api }

7

8

```java

9

public class WebAudioAPIManager implements LifecycleListener {

10

// Web Audio API availability and setup

11

public static boolean isSupported();

12

public static WebAudioAPIManager getInstance();

13

14

// Audio context management

15

public void createContext();

16

public void resumeContext();

17

public void suspendContext();

18

public boolean isContextRunning();

19

20

// Lifecycle management

21

public void pause();

22

public void resume();

23

public void dispose();

24

25

// Audio graph management

26

public AudioControlGraph createAudioGraph();

27

public void releaseAudioGraph(AudioControlGraph graph);

28

29

// Volume and settings

30

public void setMasterVolume(float volume);

31

public float getMasterVolume();

32

}

33

```

34

35

### WebAudioAPISound { .api }

36

37

```java

38

public class WebAudioAPISound implements Sound {

39

// Sound playback control

40

public long play();

41

public long play(float volume);

42

public long play(float volume, float pitch, float pan);

43

44

// Instance control

45

public void stop();

46

public void stop(long soundId);

47

public void pause();

48

public void pause(long soundId);

49

public void resume();

50

public void resume(long soundId);

51

52

// Sound properties

53

public void setVolume(long soundId, float volume);

54

public void setPitch(long soundId, float pitch);

55

public void setPan(long soundId, float pan, float volume);

56

57

// Looping control

58

public void setLooping(long soundId, boolean looping);

59

60

// Resource management

61

public void dispose();

62

}

63

```

64

65

### WebAudioAPIMusic { .api }

66

67

```java

68

public class WebAudioAPIMusic implements Music {

69

// Playback control

70

public void play();

71

public void pause();

72

public void stop();

73

74

// State queries

75

public boolean isPlaying();

76

public boolean isLooping();

77

78

// Music properties

79

public void setLooping(boolean isLooping);

80

public void setVolume(float volume);

81

public float getVolume();

82

public void setPan(float pan, float volume);

83

84

// Position control

85

public void setPosition(float position);

86

public float getPosition();

87

88

// Event handling

89

public void setOnCompletionListener(OnCompletionListener listener);

90

91

// Resource management

92

public void dispose();

93

}

94

```

95

96

### AudioControlGraph { .api }

97

98

```java

99

public class AudioControlGraph {

100

// Audio node management

101

public void connect(AudioNode source, AudioNode destination);

102

public void disconnect(AudioNode source);

103

public void disconnect(AudioNode source, AudioNode destination);

104

105

// Volume and gain control

106

public void setVolume(float volume);

107

public float getVolume();

108

public void setMasterGain(float gain);

109

110

// Audio effects

111

public void applyLowPassFilter(float frequency);

112

public void applyHighPassFilter(float frequency);

113

public void applyReverb(float roomSize, float damping);

114

public void applyDelay(float delayTime, float feedback);

115

116

// Spatial audio

117

public void setListenerPosition(float x, float y, float z);

118

public void setListenerOrientation(float forwardX, float forwardY, float forwardZ,

119

float upX, float upY, float upZ);

120

public void setSourcePosition(float x, float y, float z);

121

122

// Audio analysis

123

public float[] getFrequencyData();

124

public float[] getTimeData();

125

public float getAverageVolume();

126

127

// Resource management

128

public void dispose();

129

}

130

```

131

132

### AudioControlGraphPool { .api }

133

134

```java

135

public class AudioControlGraphPool extends Pool<AudioControlGraph> {

136

// Object pooling for audio graphs

137

public AudioControlGraphPool(int initialCapacity, int max);

138

139

// Pool management

140

protected AudioControlGraph newObject();

141

protected void reset(AudioControlGraph object);

142

143

// Pool operations

144

public AudioControlGraph obtain();

145

public void free(AudioControlGraph object);

146

public void clear();

147

}

148

```

149

150

## Usage Examples

151

152

### Basic Web Audio Setup

153

154

```java

155

public class WebAudioGame implements ApplicationListener {

156

private WebAudioAPIManager audioManager;

157

private WebAudioAPISound jumpSound;

158

private WebAudioAPIMusic backgroundMusic;

159

160

@Override

161

public void create() {

162

// Check Web Audio API support

163

if (WebAudioAPIManager.isSupported()) {

164

audioManager = WebAudioAPIManager.getInstance();

165

audioManager.createContext();

166

167

// Load audio assets

168

jumpSound = (WebAudioAPISound) Gdx.audio.newSound(Gdx.files.internal("audio/jump.ogg"));

169

backgroundMusic = (WebAudioAPIMusic) Gdx.audio.newMusic(Gdx.files.internal("music/background.ogg"));

170

171

// Configure background music

172

backgroundMusic.setLooping(true);

173

backgroundMusic.setVolume(0.7f);

174

175

System.out.println("Web Audio API initialized successfully");

176

} else {

177

System.out.println("Web Audio API not supported, using fallback");

178

// Fall back to regular HTML5 Audio

179

}

180

}

181

182

@Override

183

public void render() {

184

// Resume audio context on user interaction (required by browsers)

185

if (Gdx.input.justTouched() && audioManager != null) {

186

audioManager.resumeContext();

187

188

if (!backgroundMusic.isPlaying()) {

189

backgroundMusic.play();

190

}

191

}

192

}

193

194

public void playJumpSound() {

195

if (jumpSound != null) {

196

// Play with random pitch variation

197

float pitch = 0.8f + (float)Math.random() * 0.4f; // 0.8 to 1.2

198

jumpSound.play(1.0f, pitch, 0.0f);

199

}

200

}

201

202

@Override

203

public void dispose() {

204

if (jumpSound != null) jumpSound.dispose();

205

if (backgroundMusic != null) backgroundMusic.dispose();

206

if (audioManager != null) audioManager.dispose();

207

}

208

}

209

```

210

211

### Advanced Audio Effects

212

213

```java

214

public class AudioEffectsDemo implements ApplicationListener {

215

private AudioControlGraph audioGraph;

216

private WebAudioAPISound laserSound;

217

private WebAudioAPIMusic ambienceMusic;

218

219

@Override

220

public void create() {

221

if (WebAudioAPIManager.isSupported()) {

222

WebAudioAPIManager manager = WebAudioAPIManager.getInstance();

223

manager.createContext();

224

225

// Create audio processing graph

226

audioGraph = manager.createAudioGraph();

227

228

// Load sounds

229

laserSound = (WebAudioAPISound) Gdx.audio.newSound(Gdx.files.internal("sfx/laser.ogg"));

230

ambienceMusic = (WebAudioAPIMusic) Gdx.audio.newMusic(Gdx.files.internal("music/ambience.ogg"));

231

232

// Apply audio effects

233

setupAudioEffects();

234

}

235

}

236

237

private void setupAudioEffects() {

238

// Apply low-pass filter for underwater effect

239

audioGraph.applyLowPassFilter(800.0f);

240

241

// Add reverb for spacious environment

242

audioGraph.applyReverb(0.8f, 0.2f);

243

244

// Set up spatial audio

245

audioGraph.setListenerPosition(0, 0, 0);

246

audioGraph.setListenerOrientation(0, 0, -1, 0, 1, 0); // Looking forward, up is up

247

}

248

249

public void playLaserAt(float x, float y) {

250

if (laserSound != null) {

251

// Calculate pan based on position

252

float screenWidth = Gdx.graphics.getWidth();

253

float pan = (x - screenWidth / 2) / (screenWidth / 2); // -1 to 1

254

pan = Math.max(-1, Math.min(1, pan)); // Clamp to valid range

255

256

// Play with spatial positioning

257

audioGraph.setSourcePosition(x, y, 0);

258

laserSound.play(1.0f, 1.0f, pan);

259

}

260

}

261

262

public void startUnderwater​Mode() {

263

// Apply underwater audio effect

264

audioGraph.applyLowPassFilter(400.0f);

265

audioGraph.setMasterGain(0.6f);

266

267

// Reduce music volume

268

if (ambienceMusic != null) {

269

ambienceMusic.setVolume(0.3f);

270

}

271

}

272

273

public void endUnderwaterMode() {

274

// Remove underwater effect

275

audioGraph.applyLowPassFilter(20000.0f); // Remove filter

276

audioGraph.setMasterGain(1.0f);

277

278

// Restore music volume

279

if (ambienceMusic != null) {

280

ambienceMusic.setVolume(0.8f);

281

}

282

}

283

284

@Override

285

public void dispose() {

286

if (audioGraph != null) audioGraph.dispose();

287

if (laserSound != null) laserSound.dispose();

288

if (ambienceMusic != null) ambienceMusic.dispose();

289

}

290

}

291

```

292

293

### Audio Visualization

294

295

```java

296

public class AudioVisualizerDemo implements ApplicationListener {

297

private AudioControlGraph audioGraph;

298

private WebAudioAPIMusic music;

299

private float[] frequencyData;

300

private float[] timeData;

301

private ShapeRenderer shapeRenderer;

302

303

@Override

304

public void create() {

305

if (WebAudioAPIManager.isSupported()) {

306

WebAudioAPIManager manager = WebAudioAPIManager.getInstance();

307

manager.createContext();

308

309

audioGraph = manager.createAudioGraph();

310

music = (WebAudioAPIMusic) Gdx.audio.newMusic(Gdx.files.internal("music/electronic.ogg"));

311

music.setLooping(true);

312

313

// Initialize visualization data arrays

314

frequencyData = new float[128];

315

timeData = new float[128];

316

317

shapeRenderer = new ShapeRenderer();

318

}

319

}

320

321

@Override

322

public void render() {

323

// Update audio analysis data

324

if (audioGraph != null && music.isPlaying()) {

325

frequencyData = audioGraph.getFrequencyData();

326

timeData = audioGraph.getTimeData();

327

}

328

329

// Clear screen

330

Gdx.gl.glClearColor(0, 0, 0, 1);

331

Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

332

333

// Draw frequency spectrum

334

drawFrequencySpectrum();

335

336

// Draw waveform

337

drawWaveform();

338

339

// Start music on user input

340

if (Gdx.input.justTouched() && music != null && !music.isPlaying()) {

341

music.play();

342

}

343

}

344

345

private void drawFrequencySpectrum() {

346

if (frequencyData == null) return;

347

348

shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);

349

shapeRenderer.setColor(0, 1, 0, 0.8f); // Green bars

350

351

float barWidth = Gdx.graphics.getWidth() / (float)frequencyData.length;

352

353

for (int i = 0; i < frequencyData.length; i++) {

354

float height = frequencyData[i] * Gdx.graphics.getHeight() * 0.4f;

355

float x = i * barWidth;

356

float y = Gdx.graphics.getHeight() * 0.6f;

357

358

shapeRenderer.rect(x, y, barWidth - 1, height);

359

}

360

361

shapeRenderer.end();

362

}

363

364

private void drawWaveform() {

365

if (timeData == null) return;

366

367

shapeRenderer.begin(ShapeRenderer.ShapeType.Line);

368

shapeRenderer.setColor(1, 1, 0, 1); // Yellow waveform

369

370

float centerY = Gdx.graphics.getHeight() * 0.3f;

371

float amplitude = 100;

372

float stepX = Gdx.graphics.getWidth() / (float)(timeData.length - 1);

373

374

for (int i = 0; i < timeData.length - 1; i++) {

375

float x1 = i * stepX;

376

float y1 = centerY + timeData[i] * amplitude;

377

float x2 = (i + 1) * stepX;

378

float y2 = centerY + timeData[i + 1] * amplitude;

379

380

shapeRenderer.line(x1, y1, x2, y2);

381

}

382

383

shapeRenderer.end();

384

}

385

386

@Override

387

public void dispose() {

388

if (audioGraph != null) audioGraph.dispose();

389

if (music != null) music.dispose();

390

if (shapeRenderer != null) shapeRenderer.dispose();

391

}

392

}

393

```

394

395

### Dynamic Audio Loading

396

397

```java

398

public class DynamicAudioLoader {

399

private WebAudioAPIManager audioManager;

400

private Map<String, WebAudioAPISound> loadedSounds;

401

private Map<String, WebAudioAPIMusic> loadedMusic;

402

403

public DynamicAudioLoader() {

404

loadedSounds = new HashMap<>();

405

loadedMusic = new HashMap<>();

406

407

if (WebAudioAPIManager.isSupported()) {

408

audioManager = WebAudioAPIManager.getInstance();

409

audioManager.createContext();

410

}

411

}

412

413

public void loadSound(String name, String path, Runnable onComplete) {

414

if (loadedSounds.containsKey(name)) {

415

if (onComplete != null) onComplete.run();

416

return;

417

}

418

419

// Load sound asynchronously

420

Timer.schedule(new Timer.Task() {

421

@Override

422

public void run() {

423

try {

424

WebAudioAPISound sound = (WebAudioAPISound) Gdx.audio.newSound(Gdx.files.internal(path));

425

loadedSounds.put(name, sound);

426

System.out.println("Loaded sound: " + name);

427

if (onComplete != null) onComplete.run();

428

} catch (Exception e) {

429

System.err.println("Failed to load sound: " + name + " - " + e.getMessage());

430

}

431

}

432

}, 0.1f); // Small delay to simulate async loading

433

}

434

435

public void loadMusic(String name, String path, Runnable onComplete) {

436

if (loadedMusic.containsKey(name)) {

437

if (onComplete != null) onComplete.run();

438

return;

439

}

440

441

Timer.schedule(new Timer.Task() {

442

@Override

443

public void run() {

444

try {

445

WebAudioAPIMusic music = (WebAudioAPIMusic) Gdx.audio.newMusic(Gdx.files.internal(path));

446

loadedMusic.put(name, music);

447

System.out.println("Loaded music: " + name);

448

if (onComplete != null) onComplete.run();

449

} catch (Exception e) {

450

System.err.println("Failed to load music: " + name + " - " + e.getMessage());

451

}

452

}

453

}, 0.1f);

454

}

455

456

public WebAudioAPISound getSound(String name) {

457

return loadedSounds.get(name);

458

}

459

460

public WebAudioAPIMusic getMusic(String name) {

461

return loadedMusic.get(name);

462

}

463

464

public void playSound(String name) {

465

WebAudioAPISound sound = getSound(name);

466

if (sound != null) {

467

sound.play();

468

} else {

469

System.err.println("Sound not loaded: " + name);

470

}

471

}

472

473

public void playSound(String name, float volume, float pitch) {

474

WebAudioAPISound sound = getSound(name);

475

if (sound != null) {

476

sound.play(volume, pitch, 0);

477

} else {

478

System.err.println("Sound not loaded: " + name);

479

}

480

}

481

482

public void playMusic(String name) {

483

WebAudioAPIMusic music = getMusic(name);

484

if (music != null) {

485

music.play();

486

} else {

487

System.err.println("Music not loaded: " + name);

488

}

489

}

490

491

public void unloadSound(String name) {

492

WebAudioAPISound sound = loadedSounds.remove(name);

493

if (sound != null) {

494

sound.dispose();

495

System.out.println("Unloaded sound: " + name);

496

}

497

}

498

499

public void unloadMusic(String name) {

500

WebAudioAPIMusic music = loadedMusic.remove(name);

501

if (music != null) {

502

music.dispose();

503

System.out.println("Unloaded music: " + name);

504

}

505

}

506

507

public void dispose() {

508

// Dispose all loaded audio

509

for (WebAudioAPISound sound : loadedSounds.values()) {

510

sound.dispose();

511

}

512

loadedSounds.clear();

513

514

for (WebAudioAPIMusic music : loadedMusic.values()) {

515

music.dispose();

516

}

517

loadedMusic.clear();

518

519

if (audioManager != null) {

520

audioManager.dispose();

521

}

522

}

523

}

524

```

525

526

## Web Audio API Benefits

527

528

### Performance Advantages

529

530

```java

531

// Web Audio API provides several performance benefits over HTML5 Audio:

532

533

public class AudioPerformanceComparison {

534

535

public void demonstrateAdvantages() {

536

if (WebAudioAPIManager.isSupported()) {

537

// ✓ Lower latency audio playback

538

// ✓ Multiple simultaneous audio instances

539

// ✓ Precise timing control

540

// ✓ Audio processing and effects

541

// ✓ Better mobile device support

542

// ✓ No browser audio instance limits

543

544

System.out.println("Using Web Audio API for optimal performance");

545

} else {

546

// Fall back to HTML5 Audio

547

// ✗ Higher latency

548

// ✗ Limited simultaneous sounds

549

// ✗ No advanced audio processing

550

// ✗ Browser-dependent limitations

551

552

System.out.println("Falling back to HTML5 Audio");

553

}

554

}

555

556

public void testAudioLatency() {

557

WebAudioAPISound testSound = (WebAudioAPISound) Gdx.audio.newSound(Gdx.files.internal("test_click.wav"));

558

559

long startTime = System.currentTimeMillis();

560

testSound.play();

561

long endTime = System.currentTimeMillis();

562

563

System.out.println("Audio playback latency: " + (endTime - startTime) + "ms");

564

// Web Audio API typically shows <10ms latency

565

// HTML5 Audio often shows 50-200ms latency

566

}

567

}

568

```

569

570

### Browser Compatibility

571

572

```java

573

// Web Audio API support across browsers

574

public class BrowserCompatibility {

575

576

public static void checkAudioSupport() {

577

if (WebAudioAPIManager.isSupported()) {

578

System.out.println("Web Audio API supported - using advanced audio features");

579

580

// Available in:

581

// - Chrome 14+

582

// - Firefox 25+

583

// - Safari 6+

584

// - Edge 12+

585

// - Mobile Chrome/Safari

586

587

} else {

588

System.out.println("Web Audio API not supported - using HTML5 Audio fallback");

589

590

// Fallback for:

591

// - Internet Explorer

592

// - Very old browser versions

593

// - Browsers with Web Audio disabled

594

}

595

}

596

597

public static void handleAudioContext() {

598

// Modern browsers require user interaction before audio context can start

599

WebAudioAPIManager manager = WebAudioAPIManager.getInstance();

600

601

if (Gdx.input.justTouched()) {

602

// Resume context after user interaction

603

manager.resumeContext();

604

System.out.println("Audio context resumed");

605

}

606

}

607

}