// Writes Todo's chime of a task done (decided by the developer, 10 Nov // 2026), played on desktops: two soft bell tones a fifth apart, A5 then E6, // each fading away, quiet, a quarter of a second in all. Synthesized here, so // it is ours and needs no licence of anyone's; run from apps/todo: // // dart run tool/completion_sound.dart // // It writes halkyon_todo_flutter/assets/sounds/task_done.wav, a mono 16-bit // WAV at 44.1 kHz; the same every run. import 'dart:io'; import 'dart:math' as math; import 'dart:typed_data'; const _rate = 44100; /// The loudest the chime gets, of full scale. const _peak = 0.3; /// Each tone: when it starts and how long it rings, in seconds. const _tones = [ (hertz: 880.0, start: 0.0, length: 0.16), (hertz: 1318.51, start: 0.07, length: 0.18), ]; void main() { final length = _tones .map((tone) => tone.start + tone.length) .reduce(math.max); final count = (length * _rate).ceil(); final samples = Float64List(count); for (final tone in _tones) { final first = (tone.start * _rate).round(); final last = math.min(count, first + (tone.length * _rate).round()); for (var index = first; index < last; index++) { final t = (index - first) / _rate; // A few milliseconds rising, so it doesn't click, then fading as a // bell does; a quiet octave above for its shimmer. final attack = math.min(1, t / 0.004); final fade = math.exp(-t * 28); final end = math.min(1, (last - index) / (_rate * 0.01)); final wave = math.sin(2 * math.pi * tone.hertz * t) + 0.2 * math.sin(4 * math.pi * tone.hertz * t); samples[index] += wave * attack * fade * end; } } final loudest = samples.map((sample) => sample.abs()).reduce(math.max); final pcm = ByteData(count * 2); for (var index = 0; index < count; index++) { pcm.setInt16( index * 2, (samples[index] / loudest * _peak * 32767).round(), Endian.little, ); } final file = File('halkyon_todo_flutter/assets/sounds/task_done.wav') ..createSync(recursive: true) ..writeAsBytesSync(_wav(pcm.buffer.asUint8List())); stdout.writeln('Wrote ${file.path} (${file.lengthSync()} bytes).'); } /// [pcm] in a WAV file's RIFF header: one channel, 16 bits at [_rate]. Uint8List _wav(Uint8List pcm) { final header = ByteData(44); void text(int offset, String value) { for (var index = 0; index < value.length; index++) { header.setUint8(offset + index, value.codeUnitAt(index)); } } text(0, 'RIFF'); header.setUint32(4, 36 + pcm.length, Endian.little); text(8, 'WAVE'); text(12, 'fmt '); header ..setUint32(16, 16, Endian.little) ..setUint16(20, 1, Endian.little) // PCM ..setUint16(22, 1, Endian.little) // one channel ..setUint32(24, _rate, Endian.little) ..setUint32(28, _rate * 2, Endian.little) // bytes a second ..setUint16(32, 2, Endian.little) // bytes a frame ..setUint16(34, 16, Endian.little); // bits a sample text(36, 'data'); header.setUint32(40, pcm.length, Endian.little); return Uint8List.fromList([...header.buffer.asUint8List(), ...pcm]); }