Nuked-OPN2
Nuked-OPN2 copied to clipboard
No sound - missing something?
Hello! We are trying to run Nuked-OPN2 on a teensy MCU, everything appears to run OK but no sound.
We are first calling OPN2_Reset
then executing OPN2_Clock() inside our audio buffer,
We get noise at the output when manually updating mor and mol with random numbers inside of the PN2_ChOutput() function, but no signal is generated by the emulator when we send the test code below (taken from the datasheet):
`ym3438.write(0x22, 0x00); // LFO off ym3438.write(0x27, 0x00); // Note off (channel 0) ym3438.write(0x28, 0x01); // Note off (channel 1) ym3438.write(0x28, 0x02); // Note off (channel 2) ym3438.write(0x28, 0x04); // Note off (channel 3) ym3438.write(0x28, 0x05); // Note off (channel 4) ym3438.write(0x28, 0x06); // Note off (channel 5) ym3438.write(0x2B, 0x00); // DAC off ym3438.write(0x30, 0x71); // ym3438.write(0x34, 0x0D); // ym3438.write(0x38, 0x33); // ym3438.write(0x3C, 0x01); // DT1/MUL ym3438.write(0x40, 0x23); // ym3438.write(0x44, 0x2D); // ym3438.write(0x48, 0x26); // ym3438.write(0x4C, 0x00); // Total level ym3438.write(0x50, 0x5F); // ym3438.write(0x54, 0x99); // ym3438.write(0x58, 0x5F); // ym3438.write(0x5C, 0x94); // RS/AR ym3438.write(0x60, 0x05); // ym3438.write(0x64, 0x05); // ym3438.write(0x68, 0x05); // ym3438.write(0x6C, 0x07); // AM/D1R ym3438.write(0x70, 0x02); // ym3438.write(0x74, 0x02); // ym3438.write(0x78, 0x02); // ym3438.write(0x7C, 0x02); // D2R ym3438.write(0x80, 0x11); // ym3438.write(0x84, 0x11); // ym3438.write(0x88, 0x11); // ym3438.write(0x8C, 0xA6); // D1L/RR ym3438.write(0x90, 0x00); // ym3438.write(0x94, 0x00); // ym3438.write(0x98, 0x00); // ym3438.write(0x9C, 0x00); // Proprietary ym3438.write(0xB0, 0x32); // Feedback/algorithm ym3438.write(0xB4, 0xC0); // Both speakers on ym3438.write(0x28, 0x00); // Key off ym3438.write(0xA4, 0x22); // ym3438.write(0xA0, 0x69); // Set frequency
while(1){ ym3438.write(0x28, 0xC0); //key on delay(1000); ym3438.write(0x28, 0); //key off delay(1000); }`
I have a doubts about the following functions: OPN2_SetTestPin OPN2_SetChipType Must they be called to enable signal generation? Anything else we are missing? Thanks in advance! Cheers Alex
Do you call OPN2_Clock between OPN2_Write calls? YM3438 requires some delays between writes to process data correctly and Nuked OPN2 emulates this behaviour.
Thanks for the fast answer!
I tried to add a delay(100);
inside the write()
-wrapper:
void write(Bit32u port, Bit8u data)
{
OPN2_Write(&chip, port, data);
delay(100);
}
But the output of the buffers is again 0.
I have to note that we are currently have no resampler-code added, but I am looking at the signal sum to see if something happens.
Nope, this won't work, The emulator isn't asynchronous, because you do iterate its work by yourself. You should tick it to make it being iterated.,
here is an example of how that worked: https://github.com/Wohlstand/libOPNMIDI/blob/master/src/chips/nuked/ym3438.c#L1473-L1506 also, my fork of an emulator (linked here) has simplified calls that do all jobs for you if you want to have the simple processing with register data writing and PCM output after the process. Otherwise, the emulator needs to work with it using almost the same logic as with the hardware chip.
Thanks @Wohlstand!
We tried your code (mentioned inside the other thread, which I will close soon) with buffered write and resampler, but this code has problems with the Teensy audio stack when enabling the audio interrupts. It seems that the calculation of the sound eats up all CPU time. This is strange, because I have a running Dexed (with 2 * 16 voices * 6 OPs each voice = 192 OPs + envelopes) running on the same type of microcontroller.
This happens only when trying the resampler code with buffered write. The original code does not have this problem (apart from our write()
problems). I think I have to go deeper into the engine to find the solution of those problems.
Do you have any other hints?
Nuked OPN2 emulator is heavy by itself because it implements the chip very accurately. All internals of WriteBuffered and GenerateRsampled implement the logic to deal with the chip. Without these codes, you need to repeat the almost same work as these calls do. Your write()
problems resulted in the chip wasn't iterated properly at all, it was just idling, because you didn't call the OPN2_Clock()
that executes the chip's processing step. So, how that should be used actually without buffered and resampled calls:
- OPN2_Clock() - to process one cycle of the chip
- OPN2_Write() - to write the data
Also, the data writing here is different than you expected: you need to call it multiple times to send register value first, and then, value itself. So, to send one value into one address, you need to call OPN2_Write() twice.
Thanks @nukeykt and @Wohlstand!
I have now managed to successfully write data to the registers. Now I have to see if I can get the downsampling from 53267 Hz to 44100 Hz somehow.
Wouldn't it also be possible to tell the library that it should no longer start from a system clock of 7670454 Hz
, but from 44100 / 53267 * 7670454 = 6350405 Hz
?