mirror of
https://github.com/libretro/Mu.git
synced 2026-09-22 22:56:12 +00:00
The audio still sounds lower frequency, but the correct samples are playing
At this point its likely the speaker just doset squeal the same way as the Palm and never will since its not a peizo buzzer.
This commit is contained in:
@@ -25,7 +25,6 @@ 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)
|
||||
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
|
||||
|
||||
Debug tools:
|
||||
ADS7846 channels can't be read in single reference mode in hwTestSuite
|
||||
@@ -49,6 +48,7 @@ in the edge case that SPICLK2 is disabled while using ADS7846 and a 1 was the la
|
||||
|
||||
|
||||
Fixed:
|
||||
inductor dosent properly drain when PWM1 gets disabled
|
||||
PWM1 FIFOAV is always set true
|
||||
may need to force sound generation until buffer is adequately filled when sound is on(not possible, INT_PWM1 is masked)
|
||||
if a timer triggers more than once per CLK32(> 32768 times a second) it will lose any triggers after the first and get out of sync(still not perfect but resolution is much higher)
|
||||
|
||||
@@ -6,24 +6,23 @@
|
||||
#include "blip_buf.h"
|
||||
|
||||
|
||||
#define INDUCTOR_RANGE 10000
|
||||
#define INDUCTOR_CLOCK_POWER 0.80
|
||||
#define INDUCTOR_CLOCK_POWER 0.000001//the amount 1 clock of true or false will increase the inductors total value
|
||||
|
||||
|
||||
int32_t inductorCurrentCharge;
|
||||
int32_t inductorLastAudioSample;
|
||||
double inductorCurrentCharge;
|
||||
double inductorChargeAtLastSample;
|
||||
|
||||
|
||||
void inductorReset(){
|
||||
inductorCurrentCharge = 0;
|
||||
inductorLastAudioSample = 0;
|
||||
inductorCurrentCharge = 0.0;
|
||||
inductorChargeAtLastSample = 0.0;
|
||||
}
|
||||
|
||||
void inductorAddClocks(int32_t clocks, bool charge){
|
||||
inductorCurrentCharge = sClamp(-INDUCTOR_RANGE, inductorCurrentCharge + (charge ? +clocks : -clocks) * INDUCTOR_CLOCK_POWER, INDUCTOR_RANGE);
|
||||
inductorCurrentCharge = dClamp(0.0, inductorCurrentCharge + (charge ? +clocks : -clocks) * INDUCTOR_CLOCK_POWER, 1.0);
|
||||
}
|
||||
|
||||
void inductorSampleAudio(int32_t now){
|
||||
blip_add_delta(palmAudioResampler, now, inductorCurrentCharge - inductorLastAudioSample);
|
||||
inductorLastAudioSample = inductorCurrentCharge;
|
||||
blip_add_delta(palmAudioResampler, now, (inductorCurrentCharge - inductorChargeAtLastSample) * AUDIO_VOLUME);
|
||||
inductorChargeAtLastSample = inductorCurrentCharge;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern int32_t inductorCurrentCharge;
|
||||
extern int32_t inductorLastAudioSample;
|
||||
extern double inductorCurrentCharge;
|
||||
extern double inductorChargeAtLastSample;
|
||||
|
||||
void inductorReset();
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ uint64_t emulatorGetStateSize(){
|
||||
size += sizeof(int32_t);//pwm1ClocksToNextSample
|
||||
size += sizeof(uint8_t) * 6;//pwm1Fifo[6]
|
||||
size += sizeof(uint8_t) * 2;//pwm1(Read/Write)
|
||||
size += sizeof(int32_t) * 2;//inductorCurrentCharge / inductorLastAudioSample
|
||||
size += sizeof(uint64_t) * 2;//inductorCurrentCharge / inductorChargeAtLastSample
|
||||
size += sizeof(uint8_t) * 7;//palmMisc
|
||||
size += sizeof(uint32_t);//palmSdCard.command
|
||||
size += sizeof(uint8_t) * 2;//palmSdCard.response / palmSdCard.commandBitsRemaining
|
||||
@@ -313,10 +313,10 @@ bool emulatorSaveState(buffer_t buffer){
|
||||
offset += sizeof(uint8_t);
|
||||
writeStateValueUint8(buffer.data + offset, pwm1WritePosition);
|
||||
offset += sizeof(uint8_t);
|
||||
writeStateValueInt32(buffer.data + offset, inductorCurrentCharge);
|
||||
offset += sizeof(int32_t);
|
||||
writeStateValueInt32(buffer.data + offset, inductorLastAudioSample);
|
||||
offset += sizeof(int32_t);
|
||||
writeStateValueDouble(buffer.data + offset, inductorCurrentCharge);
|
||||
offset += sizeof(uint64_t);
|
||||
writeStateValueDouble(buffer.data + offset, inductorChargeAtLastSample);
|
||||
offset += sizeof(uint64_t);
|
||||
|
||||
//misc
|
||||
writeStateValueBool(buffer.data + offset, palmMisc.powerButtonLed);
|
||||
@@ -466,10 +466,10 @@ bool emulatorLoadState(buffer_t buffer){
|
||||
offset += sizeof(uint8_t);
|
||||
pwm1WritePosition = readStateValueUint8(buffer.data + offset);
|
||||
offset += sizeof(uint8_t);
|
||||
inductorCurrentCharge = readStateValueInt32(buffer.data + offset);
|
||||
offset += sizeof(int32_t);
|
||||
inductorLastAudioSample = readStateValueInt32(buffer.data + offset);
|
||||
offset += sizeof(int32_t);
|
||||
inductorCurrentCharge = readStateValueDouble(buffer.data + offset);
|
||||
offset += sizeof(uint64_t);
|
||||
inductorChargeAtLastSample = readStateValueDouble(buffer.data + offset);
|
||||
offset += sizeof(uint64_t);
|
||||
|
||||
//misc
|
||||
palmMisc.powerButtonLed = readStateValueBool(buffer.data + offset);
|
||||
|
||||
@@ -120,7 +120,7 @@ typedef struct{
|
||||
|
||||
//system constants
|
||||
#define CRYSTAL_FREQUENCY 32768
|
||||
#define AUDIO_VOLUME 10//1000000
|
||||
#define AUDIO_VOLUME 1000000
|
||||
#define AUDIO_SAMPLES_PER_FRAME (AUDIO_SAMPLE_RATE / EMU_FPS)
|
||||
#define AUDIO_END_OF_FRAME (235929600 / EMU_FPS)//smallest amount of time a second can be split into:(2.0 * (14.0 * (255 + 1.0) + 15 + 1.0)) * 32768 == 235929600, used to convert the variable timing of SYSCLK and CLK32 to a fixed location in the current frame 0<->AUDIO_END_OF_FRAME
|
||||
#define AUDIO_WAIT_FOR_SAMPLE INT32_MIN
|
||||
|
||||
@@ -620,53 +620,61 @@ static inline uint8_t getPortMValue(){
|
||||
static inline void samplePwm1(bool forClk32, double sysclks){
|
||||
//clear PWM1 FIFO values if enough time has passed
|
||||
uint16_t pwmc1 = registerArrayRead16(PWMC1);
|
||||
int32_t audioNow;
|
||||
int32_t audioClocks;
|
||||
|
||||
//check if enabled and validate clock mode
|
||||
if(!(pwmc1 & 0x0010) || forClk32 != (bool)(pwmc1 & 0x8000))
|
||||
if(forClk32 != (bool)(pwmc1 & 0x8000))
|
||||
return;
|
||||
|
||||
//this calculation is fairly heavy, only do it after we know the clock mode is valid
|
||||
//these calculations are fairly heavy, only do them after we know the clock mode is valid
|
||||
audioNow = audioGetFramePercentage();
|
||||
audioClocks = forClk32 ? audioGetFramePercentIncrementFromClk32s(1) : audioGetFramePercentIncrementFromSysclks(sysclks);
|
||||
|
||||
//add cycles
|
||||
if(pwm1ClocksToNextSample != AUDIO_WAIT_FOR_SAMPLE)
|
||||
pwm1ClocksToNextSample -= audioClocks;
|
||||
if(pwmc1 & 0x0010){
|
||||
//add cycles
|
||||
if(pwm1ClocksToNextSample != AUDIO_WAIT_FOR_SAMPLE)
|
||||
pwm1ClocksToNextSample -= audioClocks;
|
||||
|
||||
//use samples
|
||||
if(pwm1ClocksToNextSample <= 0){
|
||||
int32_t audioNow = audioGetFramePercentage();
|
||||
int32_t audioClocksLeft = audioClocks;
|
||||
//use samples
|
||||
if(pwm1ClocksToNextSample <= 0){
|
||||
int32_t audioClocksLeft = audioClocks;
|
||||
|
||||
while(pwm1FifoEntrys() > 0 && pwm1ClocksToNextSample <= 0){
|
||||
int32_t audioUsed;
|
||||
while(pwm1FifoEntrys() > 0 && pwm1ClocksToNextSample <= 0){
|
||||
int32_t audioUsed;
|
||||
|
||||
//switch out samples until waiting(pwm1ClocksToNextSample is positive)
|
||||
if(pwm1ClocksToNextSample == AUDIO_WAIT_FOR_SAMPLE){
|
||||
//got first sample in a while
|
||||
audioUsed = pwm1FifoRunSample(audioNow, 0);
|
||||
pwm1ClocksToNextSample = audioUsed;
|
||||
}
|
||||
else{
|
||||
//continue processing existing sample stream
|
||||
audioUsed += pwm1FifoRunSample(audioNow, pwm1ClocksToNextSample);
|
||||
pwm1ClocksToNextSample += audioUsed;
|
||||
//switch out samples until waiting(pwm1ClocksToNextSample is positive)
|
||||
if(pwm1ClocksToNextSample == AUDIO_WAIT_FOR_SAMPLE){
|
||||
//got first sample in a while
|
||||
audioUsed = pwm1FifoRunSample(audioNow, 0);
|
||||
pwm1ClocksToNextSample = audioUsed;
|
||||
}
|
||||
else{
|
||||
//continue processing existing sample stream
|
||||
audioUsed += pwm1FifoRunSample(audioNow, pwm1ClocksToNextSample);
|
||||
pwm1ClocksToNextSample += audioUsed;
|
||||
}
|
||||
|
||||
audioNow += audioUsed;
|
||||
audioClocksLeft -= audioUsed;//goes negative when extra clocks are used
|
||||
}
|
||||
|
||||
audioNow += audioUsed;
|
||||
audioClocksLeft -= audioUsed;//goes negative when extra clocks are used
|
||||
}
|
||||
//all samples used and its still negative, wait for next sample
|
||||
if(pwm1ClocksToNextSample <= 0)
|
||||
pwm1ClocksToNextSample = AUDIO_WAIT_FOR_SAMPLE;
|
||||
|
||||
//all samples used and its still negative, wait for next sample
|
||||
if(pwm1ClocksToNextSample <= 0)
|
||||
pwm1ClocksToNextSample = AUDIO_WAIT_FOR_SAMPLE;
|
||||
|
||||
//add 0 cycles to inductor when theres no samples
|
||||
if(audioClocksLeft > 0){
|
||||
inductorAddClocks(audioClocksLeft, false);
|
||||
inductorSampleAudio(audioNow + audioClocksLeft);
|
||||
//add 0 to inductor when theres no samples
|
||||
if(audioClocksLeft > 0){
|
||||
inductorAddClocks(audioClocksLeft, false);
|
||||
inductorSampleAudio(audioNow + audioClocksLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
//PWM1 not enabled, add 0 to inductor
|
||||
inductorAddClocks(audioClocks, false);
|
||||
inductorSampleAudio(audioNow + audioClocks);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint16_t getPwmc1(){
|
||||
|
||||
@@ -18,9 +18,9 @@ static inline uint64_t uMax(uint64_t x, uint64_t y){
|
||||
return x > y ? x : y;
|
||||
}
|
||||
|
||||
static inline uint64_t uClamp(uint64_t x, uint64_t y, uint64_t z){
|
||||
static inline uint64_t uClamp(uint64_t low, uint64_t value, uint64_t high){
|
||||
//x must always be less than z!
|
||||
return (y < x ? x : y) > z ? z : y;
|
||||
return uMax(low, uMin(value, high));
|
||||
}
|
||||
|
||||
static inline int64_t sMin(int64_t x, int64_t y){
|
||||
@@ -31,9 +31,9 @@ static inline int64_t sMax(int64_t x, int64_t y){
|
||||
return x > y ? x : y;
|
||||
}
|
||||
|
||||
static inline int64_t sClamp(int64_t x, int64_t y, int64_t z){
|
||||
static inline int64_t sClamp(int64_t low, int64_t value, int64_t high){
|
||||
//x must always be less than z!
|
||||
return (y < x ? x : y) > z ? z : y;
|
||||
return sMax(low, sMin(value, high));
|
||||
}
|
||||
|
||||
static inline double dMin(double x, double y){
|
||||
@@ -44,9 +44,9 @@ static inline double dMax(double x, double y){
|
||||
return x > y ? x : y;
|
||||
}
|
||||
|
||||
static inline double dClamp(double x, double y, double z){
|
||||
static inline double dClamp(double low, double value, double high){
|
||||
//x must always be less than z!
|
||||
return (y < x ? x : y) > z ? z : y;
|
||||
return dMax(low, dMin(value, high));
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ static inline uint64_t getUint64FromDouble(double data){
|
||||
|
||||
fixedPointDouble |= (uint64_t)data << 31;
|
||||
data -= (uint64_t)data;
|
||||
data *= 1000000000.0;
|
||||
data *= (double)0x7FFFFFFF;
|
||||
fixedPointDouble |= (uint64_t)data;
|
||||
|
||||
return fixedPointDouble;
|
||||
@@ -72,7 +72,7 @@ static inline double getDoubleFromUint64(uint64_t data){
|
||||
double floatingPointDouble;
|
||||
|
||||
floatingPointDouble = (double)(data & 0x000000007FFFFFFF);
|
||||
floatingPointDouble /= 1000000000.0;
|
||||
floatingPointDouble /= (double)0x7FFFFFFF;
|
||||
floatingPointDouble += (double)(data >> 31 & 0xFFFFFFFF);
|
||||
if(data & 0x8000000000000000)
|
||||
floatingPointDouble = -floatingPointDouble;
|
||||
|
||||
Reference in New Issue
Block a user