mirror of
https://github.com/libretro/Mu.git
synced 2026-09-22 22:56:12 +00:00
Sound is fully working
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
Theory of speaker output issues:
|
||||
SysTaskDelay is used in PrvDoFreqDurationAmp, if SysTaskDelay waits on a timer the timer will not be triggered until addSysclks, the same time at which the PWM is sampled with empty samples due to the timer not being triggered properly.
|
||||
SysTaskDelay is used in PrvDoFreqDurationAmp, if SysTaskDelay waits on a timer the timer will not be triggered until addSysclks, the same time at which the PWM is sampled with empty samples due to the timer not being triggered properly.(this is wrong the actual solution is listed below)
|
||||
|
||||
It is not stated what PWM1 does when it runs out of samples, does it keep playing the last sample, or does it set 0% duty cycle?(the last sample plays infinitely!)
|
||||
|
||||
@@ -25,7 +25,7 @@ ICR POL(1,2,3,6) may flip the pin value as well as the interrupt, POL5 does not
|
||||
edge triggered INT* don't clear on write to ISR when masked in IMR(at least that seems to be the reason)
|
||||
if a sound interrupt is triggered while the button interrupt is disabled the button interrupt will still trigger(in galax game)
|
||||
Cyclone will cause SIGSEGVs, don't know why yet
|
||||
audio can max out the resampler buffer, the max 1 FIFO sample can play is around 2.16 minutes(CLK32 / period(257) / clockDivider(16) / prescaler(128) / repeat(8))(257 * 16 * 128 * 8 / 32768=128.5 seconds)
|
||||
PWM2 is not implemented
|
||||
|
||||
Debug tools:
|
||||
ADS7846 channels can't be read in single reference mode in hwTestSuite
|
||||
@@ -49,6 +49,7 @@ in the edge case that SPICLK2 is disabled while using ADS7846 and a 1 was the la
|
||||
|
||||
|
||||
Fixed:
|
||||
audio can max out the resampler buffer, the max 1 FIFO sample can play is around 2.16 minutes(CLK32 / period(257) / clockDivider(16) / prescaler(128) / repeat(8))(257 * 16 * 128 * 8 / 32768=128.5 seconds)(safety check added, >= 1 second duty cycle is useless and will just make annoying cracks anyway)
|
||||
Cyclone CPU emulator is not working
|
||||
PWM1 output value is not a direct range cast of 0<->255 to 0<->32767, its additive, see properPwmSineWave.png
|
||||
inductor dosent properly drain when PWM1 gets disabled
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
|
||||
#define INDUCTOR_CLOCK_POWER 0.0001//the amount 1 clock of true or false will change the inductors total value
|
||||
|
||||
#define INDUCTOR_SPEAKER_RANGE 0x6666//prevent hitting the top or bottom of the speaker when switching direction rapidly
|
||||
|
||||
double inductorCurrentCharge;
|
||||
double inductorChargeAtLastSample;
|
||||
@@ -18,19 +18,32 @@ void inductorReset(){
|
||||
inductorChargeAtLastSample = 0.0;
|
||||
}
|
||||
|
||||
void inductorPwmOff(int32_t clocks){
|
||||
void inductorPwmDutyCycle(int32_t now, int32_t clocks, double dutyCycle){
|
||||
int32_t onClocks = clocks * dutyCycle;
|
||||
int32_t offClocks = clocks * (1.00 - dutyCycle);
|
||||
double cutoffPoint = dutyCycle - 0.50;//cant go past the actual duty cycle percentage
|
||||
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
if(now + clocks > AUDIO_CLOCK_RATE)
|
||||
return;
|
||||
#endif
|
||||
|
||||
inductorCurrentCharge = dMin(inductorCurrentCharge + onClocks * INDUCTOR_CLOCK_POWER, cutoffPoint);
|
||||
blip_add_delta(palmAudioResampler, now, (inductorCurrentCharge - inductorChargeAtLastSample) * INDUCTOR_SPEAKER_RANGE);
|
||||
inductorChargeAtLastSample = inductorCurrentCharge;
|
||||
|
||||
inductorCurrentCharge = dMax(-1.0, inductorCurrentCharge - offClocks * INDUCTOR_CLOCK_POWER);
|
||||
blip_add_delta(palmAudioResampler, now + onClocks, (inductorCurrentCharge - inductorChargeAtLastSample) * INDUCTOR_SPEAKER_RANGE);
|
||||
inductorChargeAtLastSample = inductorCurrentCharge;
|
||||
}
|
||||
|
||||
void inductorPwmOff(int32_t now, int32_t clocks){
|
||||
//drift towards 0
|
||||
if(inductorCurrentCharge > 0.0)
|
||||
inductorCurrentCharge = dMax(0.0, inductorCurrentCharge - clocks * INDUCTOR_CLOCK_POWER);
|
||||
else
|
||||
inductorCurrentCharge = dMin(inductorCurrentCharge + clocks * INDUCTOR_CLOCK_POWER, 0.0);
|
||||
}
|
||||
|
||||
void inductorAddClocks(int32_t clocks, bool charge){
|
||||
inductorCurrentCharge = dClamp(-1.0, inductorCurrentCharge + (charge ? +clocks : -clocks) * INDUCTOR_CLOCK_POWER, 1.0);
|
||||
}
|
||||
|
||||
void inductorSampleAudio(int32_t now){
|
||||
blip_add_delta(palmAudioResampler, now, (inductorCurrentCharge - inductorChargeAtLastSample) * 0x6666/*INT16_MAX*/);
|
||||
blip_add_delta(palmAudioResampler, now, (inductorCurrentCharge - inductorChargeAtLastSample) * INDUCTOR_SPEAKER_RANGE);
|
||||
inductorChargeAtLastSample = inductorCurrentCharge;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,5 @@ extern double inductorChargeAtLastSample;
|
||||
|
||||
void inductorReset();
|
||||
|
||||
void inductorPwmOff(int32_t clocks);
|
||||
void inductorAddClocks(int32_t clocks, bool charge);
|
||||
void inductorSampleAudio(int32_t now);
|
||||
void inductorPwmDutyCycle(int32_t now, int32_t clocks, double dutyCycle);
|
||||
void inductorPwmOff(int32_t now, int32_t clocks);
|
||||
|
||||
@@ -39,7 +39,7 @@ uint8_t* palmReg;
|
||||
input_t palmInput;
|
||||
sd_card_t palmSdCard;
|
||||
misc_hw_t palmMisc;
|
||||
uint16_t palmFramebuffer[160 * (160 + 60)];//really 160*160, the extra pixels are the silkscreened digitizer area
|
||||
uint16_t* palmFramebuffer;
|
||||
uint16_t* palmExtendedFramebuffer;
|
||||
int16_t* palmAudio;
|
||||
blip_t* palmAudioResampler;
|
||||
@@ -62,16 +62,18 @@ uint32_t emulatorInit(buffer_t palmRomDump, buffer_t palmBootDump, uint32_t spec
|
||||
palmRam = malloc(((specialFeatures & FEATURE_RAM_HUGE) ? SUPERMASSIVE_RAM_SIZE : RAM_SIZE) + 4);
|
||||
palmRom = malloc(ROM_SIZE + 4);
|
||||
palmReg = malloc(REG_SIZE + 4);
|
||||
palmFramebuffer = malloc(160 * (160 + 60) * sizeof(uint16_t));//really 160*160, the extra pixels are the silkscreened digitizer area
|
||||
palmAudio = malloc(AUDIO_SAMPLES_PER_FRAME * 2 * sizeof(int16_t));
|
||||
palmAudioResampler = blip_new(AUDIO_SAMPLE_RATE);//have 1 second of samples
|
||||
if(specialFeatures & FEATURE_320x320)
|
||||
palmExtendedFramebuffer = malloc(320 * (320 + 120) * sizeof(uint16_t));//really 320*320, the extra pixels are the silkscreened digitizer area
|
||||
else
|
||||
palmExtendedFramebuffer = NULL;
|
||||
if(!palmRam || !palmRom || !palmReg || !palmAudio || !palmAudioResampler || (!palmExtendedFramebuffer && (specialFeatures & FEATURE_320x320))){
|
||||
if(!palmRam || !palmRom || !palmReg || !palmFramebuffer || !palmAudio || !palmAudioResampler || (!palmExtendedFramebuffer && (specialFeatures & FEATURE_320x320))){
|
||||
free(palmRam);
|
||||
free(palmRom);
|
||||
free(palmReg);
|
||||
free(palmFramebuffer);
|
||||
free(palmAudio);
|
||||
blip_delete(palmAudioResampler);
|
||||
free(palmExtendedFramebuffer);
|
||||
@@ -136,6 +138,7 @@ void emulatorExit(){
|
||||
free(palmRam);
|
||||
free(palmRom);
|
||||
free(palmReg);
|
||||
free(palmFramebuffer);
|
||||
free(palmAudio);
|
||||
blip_delete(palmAudioResampler);
|
||||
free(palmExtendedFramebuffer);
|
||||
|
||||
@@ -124,7 +124,7 @@ extern uint8_t* palmReg;//dont touch
|
||||
extern input_t palmInput;//write allowed
|
||||
extern sd_card_t palmSdCard;//dont touch
|
||||
extern misc_hw_t palmMisc;//read/write allowed
|
||||
extern uint16_t palmFramebuffer[];//read allowed if FEATURE_320x320 is off, or else invalid data will be displayed
|
||||
extern uint16_t* palmFramebuffer;//read allowed if FEATURE_320x320 is off, or else invalid data will be displayed
|
||||
extern uint16_t* palmExtendedFramebuffer;//read allowed if FEATURE_320x320 is on, or else SIGSEGV
|
||||
extern int16_t* palmAudio;//read allowed, 2 channel signed 16 bit audio
|
||||
extern blip_t* palmAudioResampler;//dont touch
|
||||
|
||||
@@ -87,14 +87,10 @@ int32_t pwm1FifoRunSample(int32_t now, int32_t clockOffset){
|
||||
uint8_t repeat = 1 << (pwmc1 >> 2 & 0x03);
|
||||
int32_t audioNow = now + clockOffset;
|
||||
int32_t audioSampleDuration = usingClk32 ? audioGetFramePercentIncrementFromClk32s(period * prescaler * clockDivider) : audioGetFramePercentIncrementFromSysclks(period * prescaler * clockDivider);
|
||||
int32_t audioDutyCycle = dMin((double)sample / period, 1.0)/*dutyCycle*/ * audioSampleDuration;
|
||||
double dutyCycle = dMin((double)sample / period, 1.00);
|
||||
|
||||
//relay all the samples to the inductor
|
||||
for(uint8_t index = 0; index < repeat; index++){
|
||||
inductorAddClocks(audioDutyCycle, true);
|
||||
inductorSampleAudio(audioNow + audioDutyCycle);
|
||||
inductorAddClocks(audioSampleDuration - audioDutyCycle, false);
|
||||
inductorSampleAudio(audioNow + audioSampleDuration);
|
||||
inductorPwmDutyCycle(audioNow, audioSampleDuration, dutyCycle);
|
||||
audioNow += audioSampleDuration;
|
||||
}
|
||||
|
||||
@@ -647,8 +643,7 @@ static void samplePwm1(bool forClk32, double sysclks){
|
||||
}
|
||||
else{
|
||||
//PWM1 not enabled
|
||||
inductorPwmOff(audioClocks);
|
||||
inductorSampleAudio(audioNow + audioClocks);
|
||||
inductorPwmOff(audioNow, audioClocks);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user