# One Bin, One Thread

*Task 1 of 5 · [The DFT, Honestly](https://gpu.rocks/learn/the-dft-7b1e3f9b.md) · GPU.js Learn*

A *transform* sounds grand. One **bin** of it is not: pick a
frequency, build a test wave at that frequency, multiply it against the signal sample by
sample, and add the products up. One number falls out, and it answers exactly one
question — *how much of this frequency is in here?*

That is a dot product, and it is the same instinct Template Matching used on images:
slide a pattern over the data and let the sum of the products score the match. Here the
pattern is a cosine and the data is a row of samples.

Start with one bin and one thread. `output: [1]` gives you a single thread
that walks the whole signal — the conceptual atom. Task 3 hands every bin a thread of its
own, which is where this stops being a loop and starts being a GPU workload.

## Figures

- **a transform is a pile of dot products — this is one of them**

## Goal

**Goal:** correlate `signal` against a cosine at bin
`k` — sum `signal[i] × cos(2π·k·i/n)` over all 256 samples — and
report bins 8, 20 and 13.

## Requirements

- Keep `output: [1]`: one thread owns the one answer
- Loop `for (let i = 0; i < this.constants.n; i++)` — WebGL needs a compile-time bound
- Accumulate `signal[i] * Math.cos(2 * Math.PI * k * i / this.constants.n)`
- `console.log` bins 8, 20 and 13 — expect `128`, `64` and `0`

## Hint 1 — what the angle has to do

Over the whole signal, the test wave for bin `k` must complete
exactly `k` turns. Term `i` is therefore a fraction
`i / n` of the way through `k` turns, and one turn is
`2π` radians:

```js
const angle = 2 * Math.PI * k * i / this.constants.n;
```

## Hint 2 — the accumulator

Same shape as any other loop-and-total kernel: declare
`let acc = 0;` before the loop, add one product per iteration, and
`return acc;` after it.

```js
acc += signal[i] * Math.cos(angle);
```

## Hint 3 — asking for a bin

`k` is an ordinary kernel argument, so one kernel answers every
bin — call it again with a different number:

```js
console.log('bin 8:', bin(signal, 8)[0]);
console.log('bin 20:', bin(signal, 20)[0]);
```

## Same idea elsewhere

Correlating against a basis function is the move behind far more than audio:
it is what a matched filter does in radar, what a lock-in amplifier does in a lab, and
what a single row of a matrix–vector product does in linear algebra. On any platform the
kernel is the same — CUDA, WGSL and Metal all give you a thread, a loop and a fused
multiply-add, and that is the entire ingredient list.

## Starter code

```js
// One bin of a transform is one dot product: signal · test wave.
const gpu = new GPU({ mode });

const bin = gpu.createKernel(function (signal, k) {
  // TODO: loop i over all this.constants.n samples and accumulate
  // signal[i] * cos(2π · k · i / n) into a local total, then return it.
  return 0;
}, {
  output: [1],
  constants: { n: 256 },
});

console.log('bin 8  (the loud tone):', bin(signal, 8)[0]);
console.log('bin 20 (the quiet one):', bin(signal, 20)[0]);
console.log('bin 13 (nothing there):', bin(signal, 13)[0]);
```

---

Interactive version: https://gpu.rocks/learn/the-dft-7b1e3f9b/1

[Next task](https://gpu.rocks/learn/the-dft-7b1e3f9b/2.md)
