flutter3d
Showcase Changelog 38 packages API reference

A blended engine loop: the source

since 0.1.0 or earlier Simulation, audio and XR

Regions the guide quotes: bands (line 22), update (line 56), loudness (line 78).

1/// Several loops of the same engine, recorded at different revs, crossfaded
2/// by one number so the change from one recording to the next is not heard.
3///
4/// Quoted by `blended_engine_loop.md` and shown whole in the Source tab.
5library;
6
7import 'package:flutter3d/flutter3d.dart';
8import 'package:flutter3d_audio/flutter3d_audio.dart';
9import 'package:flutter3d_showcase/src/demo/demo.dart';
10import 'package:vector_math/vector_math.dart';
12final class BlendedEngineLoopDemo extends ShowcaseDemo {
13 double revs = 0.5;
15 late final AudioScene _scene;
16 late final BlendedLoop _engine;
18 @override
19 Scene build(DemoContext context) {
20 _scene = AudioScene(backend: SilentBackend());
22 _engine = BlendedLoop(
23 scene: _scene,
24 bands: <LoopBand>[
25 LoopBand(
26 sound: const SoundDef(name: 'idle', asset: 'idle.wav', loop: true),
27 centre: 0.2,
28 ),
29 LoopBand(
30 sound: const SoundDef(name: 'mid', asset: 'mid.wav', loop: true),
31 centre: 0.6,
32 ),
33 LoopBand(
34 sound: const SoundDef(name: 'high', asset: 'high.wav', loop: true),
35 centre: 1.0,
36 ),
37 ],
38 );
40 final material = Material(
41 name: 'engine',
42 baseColor: Vector4(0.8, 0.3, 0.2, 1.0),
43 );
44 final node = MeshNode(
45 DeviceMesh.upload(context.device, SphereShape(segments: 16).build()),
46 material,
47 );
48 return Scene()
49 ..add(node)
50 ..add(
51 LightNode(name: 'sun', intensity: 3.0)
52 ..setLocalForward(Vector3(-0.4, -1.0, -0.3)),
53 );
54 }
56 @override
57 void update(DemoContext context, double dt) {
58 _engine.update(revs);
59 _scene.update(AudioListener());
60 }
62 @override
63 List<DemoControl> controls(DemoContext context) => <DemoControl>[
64 SliderControl(
65 'Engine revs',
66 min: 0.0,
67 max: 1.2,
68 value: () => revs,
69 onChanged: (double v) => revs = v,
70 ),
71 ];
73 @override
74 void verify(Scene scene, FrameResult frame) {
75 if (frame.drawCalls < 1) {
76 throw StateError('the engine marker was not drawn');
77 }
78 // The bands are normalised, so the total weight is one wherever the
79 // revs sit, including exactly between two bands.
80 revs = 0.4;
81 _engine.update(revs);
82 var total = 0.0;
83 for (var i = 0; i < 3; i++) {
84 total += _engine.gainOf(i);
85 }
86 if ((total - 1.0).abs() > 1e-6) {
87 throw StateError(
88 'the bands should always sum to full loudness, '
89 'summed to $total',
90 );
91 }
92 }