Blog - PSP Tone Generator
I've just released the first version of my PSP Tone Generator (source included). It can create up till five simultaneous tones ranging from 20Hz to 10kHz. It also shows a visualization of the sound waves:
Technically the most interesting part was the mutual exclusion between writing to the sound buffer and reading from it. 43 times per second, the sound buffer has to be copied to the speakers, and while this happens, the sound buffer should not change.
The PSP has support for semaphores, but I found these worked too slowly, which produced an annoying rapid tick from the speakers. Instead I decided to go with a simple binary semaphore: int mutexFull = 0.
The producer of the sound waves waits while mutexFull = 1, because the buffer is already full. When mutexFull = 0, it stops waiting, it fills the buffer up again and sets mutexFull = 1.
The consumer of the sound waves waits while mutexFull = 0, because the buffer is still empty. When mutexFull = 1, it stops waiting, it reads it all out again and sets mutexFull = 0.
This fulfills the three basic requirements of mutual exclusion:
The only downside to this is "busy" waiting (each thread is paused for a millisecond at a time). The property of the above solution that the threads have to run interleaved absolutely one-to-one is not handy for a general mutual exclusion algorithm, but in this case that's exactly what I want: the producer writes, the consumer reads, and so on.
Have fun playing around with it :)
Technically the most interesting part was the mutual exclusion between writing to the sound buffer and reading from it. 43 times per second, the sound buffer has to be copied to the speakers, and while this happens, the sound buffer should not change.
The PSP has support for semaphores, but I found these worked too slowly, which produced an annoying rapid tick from the speakers. Instead I decided to go with a simple binary semaphore: int mutexFull = 0.
The producer of the sound waves waits while mutexFull = 1, because the buffer is already full. When mutexFull = 0, it stops waiting, it fills the buffer up again and sets mutexFull = 1.
The consumer of the sound waves waits while mutexFull = 0, because the buffer is still empty. When mutexFull = 1, it stops waiting, it reads it all out again and sets mutexFull = 0.
This fulfills the three basic requirements of mutual exclusion:
- Mutual exclusion: if mutexFull = 0, the consumer waits. If mutexFull = 1, the producer waits. They cannot both run at the same time;
- Progress and bounded waiting: whenever a critical section is finished, the mutexFull variable changes, allowing (only) the other critical section to be executed.
The only downside to this is "busy" waiting (each thread is paused for a millisecond at a time). The property of the above solution that the threads have to run interleaved absolutely one-to-one is not handy for a general mutual exclusion algorithm, but in this case that's exactly what I want: the producer writes, the consumer reads, and so on.
Have fun playing around with it :)