I just got an idea that would be awesome for NES development. Basically it would allow an undefined number of extra sine audio channels, probably 1, 2 or 4 channels, with volume control, and that using $4011. I probably won't ever be able to put this idea to good use (as to, make a decent game using music that uses this), so I prefer to share the idea and hope someone else use it. If they give me credit, even better
The main idea is to use a mapper that supports timed IRQs that are fired at a programmable arbitrary rate. I think VRC mappers, and the FME-7 supports this, and the Famicom Disk System. Perhaps other more obscure mappers as well, I don't know. The rate can be anything really.
Now, if we can generate IRQs periodically, it's possible to write to $4011 periodically without monopolizing the CPU for this task alone, and thus get an extra sound channel, that doesn't sound terrible like DMC does. The problem is that doing it the "trivial" way is just copying data from ROM to $4011, but it wastes tremendous amount of ROM to replay samples, so this is not practical for a NES game - only for tech demoes.
Another idea would be to synthesize sound, but this requires CPU power, and the NES bascially doesn't have that. But I think I found a way to synthesize sound using very low CPU. The idea is to generate sine waves, and take values from a sine table which is stored in 256 bytes of ROM. Sine waves have no harmonics, and no harmonics aliasing, so it's very easy to resample them to any rate with a fixed sample rate, and it will continue to sound good, unlike any other waveform such as square or saw waves.
So the IRQ mixing code looks like something like that:
The mixing code is thus relatively simple and fax, and executes in constant time. But that's not all, get a bunch of sine waves is not very exciting in itself. What is exciting is that you can control their volume, and that without touching the code above, by pairing two dephased sines of the same frequency. In the sound code, something like that:
Will combine Chan1 and Chan2 sines to produce a sine wave of controllable volume, and that without using any multiplication anywhere. I just tought this idea was very cool, so I wished to share it. I have no idea how much "channels" would be feasible in practice, it's a tradeoff between amount of channels, CPU usage and sampling frequency (and thus, maximum sine pitch). I think expecting 4 sine channels without volume control, or 2 sine channels with volume control, could already greatly expand what is possible to do for NES music !
I didn't mention it, but of course the sine table is pre-shifted so that it doesn't overflow, so maybe it's range will be -64..64 or something like that instead of -256..256.
The main idea is to use a mapper that supports timed IRQs that are fired at a programmable arbitrary rate. I think VRC mappers, and the FME-7 supports this, and the Famicom Disk System. Perhaps other more obscure mappers as well, I don't know. The rate can be anything really.
Now, if we can generate IRQs periodically, it's possible to write to $4011 periodically without monopolizing the CPU for this task alone, and thus get an extra sound channel, that doesn't sound terrible like DMC does. The problem is that doing it the "trivial" way is just copying data from ROM to $4011, but it wastes tremendous amount of ROM to replay samples, so this is not practical for a NES game - only for tech demoes.
Another idea would be to synthesize sound, but this requires CPU power, and the NES bascially doesn't have that. But I think I found a way to synthesize sound using very low CPU. The idea is to generate sine waves, and take values from a sine table which is stored in 256 bytes of ROM. Sine waves have no harmonics, and no harmonics aliasing, so it's very easy to resample them to any rate with a fixed sample rate, and it will continue to sound good, unlike any other waveform such as square or saw waves.
So the IRQ mixing code looks like something like that:
Code:
IRQ:
pha
txa
pha
tya
pha
lda #$00
sta Temp
ldy #nchans
- lda PhaseL,Y
clc
adc FreqL,Y
sta PhaseL,Y
lda PhaseH,Y
adc FreqH,Y
sta PhaseH,Y
tax
lda SineTable,X
clc
adc Temp
sta Temp
dey
bne -
lda Temp
lsr A ; Optional - convert 8-bit to 7 bit unsigned
sta $4011
pla
tay
pla
tax
pla
rti
pha
txa
pha
tya
pha
lda #$00
sta Temp
ldy #nchans
- lda PhaseL,Y
clc
adc FreqL,Y
sta PhaseL,Y
lda PhaseH,Y
adc FreqH,Y
sta PhaseH,Y
tax
lda SineTable,X
clc
adc Temp
sta Temp
dey
bne -
lda Temp
lsr A ; Optional - convert 8-bit to 7 bit unsigned
sta $4011
pla
tay
pla
tax
pla
rti
The mixing code is thus relatively simple and fax, and executes in constant time. But that's not all, get a bunch of sine waves is not very exciting in itself. What is exciting is that you can control their volume, and that without touching the code above, by pairing two dephased sines of the same frequency. In the sound code, something like that:
Code:
ldx #Chan1
ldy #Chan2
lda FreqL,X
sta FreqL,Y
lda FreqH,X
sta FreqH,Y
lda PhaseL,X
sta PhaseL,Y
lda PhaseH,X
clc
adc Volume
sta PhaseH,Y
ldy #Chan2
lda FreqL,X
sta FreqL,Y
lda FreqH,X
sta FreqH,Y
lda PhaseL,X
sta PhaseL,Y
lda PhaseH,X
clc
adc Volume
sta PhaseH,Y
Will combine Chan1 and Chan2 sines to produce a sine wave of controllable volume, and that without using any multiplication anywhere. I just tought this idea was very cool, so I wished to share it. I have no idea how much "channels" would be feasible in practice, it's a tradeoff between amount of channels, CPU usage and sampling frequency (and thus, maximum sine pitch). I think expecting 4 sine channels without volume control, or 2 sine channels with volume control, could already greatly expand what is possible to do for NES music !
I didn't mention it, but of course the sine table is pre-shifted so that it doesn't overflow, so maybe it's range will be -64..64 or something like that instead of -256..256.