git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

commit 5c854dbdca808c0258cb34a3cb11b1f9d2dd67ca
parent 8e858c1bf146f7f62f7048f7089b9572bc3b2b30
Author: Lior Halphon <LIJI32@gmail.com>
Date:   Thu, 31 Dec 2020 00:06:36 +0200

Interference emulation

Diffstat:
MCocoa/Document.m12++++++++++++
MCocoa/GBPreferencesWindow.h1+
MCocoa/GBPreferencesWindow.m21+++++++++++++++++++++
MCocoa/Preferences.xib30++++++++++++++++++++++++------
MCore/apu.c55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
MCore/apu.h4++++
MSDL/gui.c26+++++++++++++++++++++++++-
MSDL/gui.h1+
MSDL/main.c2++
9 files changed, 145 insertions(+), 7 deletions(-)

diff --git a/Cocoa/Document.m b/Cocoa/Document.m @@ -287,6 +287,7 @@ static void infraredStateChanged(GB_gameboy_t *gb, bool on) GB_set_async_input_callback(&gb, (GB_input_callback_t) asyncConsoleInput); GB_set_color_correction_mode(&gb, (GB_color_correction_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorCorrection"]); GB_set_light_temperature(&gb, [[NSUserDefaults standardUserDefaults] doubleForKey:@"GBLightTemperature"]); + GB_set_interference_volume(&gb, [[NSUserDefaults standardUserDefaults] doubleForKey:@"GBInterferenceVolume"]); GB_set_border_mode(&gb, (GB_border_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBBorderMode"]); [self updatePalette]; GB_set_rgb_encode_callback(&gb, rgbEncode); @@ -696,6 +697,11 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateInterferenceVolume) + name:@"GBInterferenceVolumeChanged" + object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateFrameBlendingMode) name:@"GBFrameBlendingModeChanged" object:nil]; @@ -1848,6 +1854,12 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) } } +- (void) updateInterferenceVolume +{ + if (GB_is_inited(&gb)) { + GB_set_interference_volume(&gb, [[NSUserDefaults standardUserDefaults] doubleForKey:@"GBInterferenceVolume"]); + } +} - (void) updateFrameBlendingMode { diff --git a/Cocoa/GBPreferencesWindow.h b/Cocoa/GBPreferencesWindow.h @@ -18,6 +18,7 @@ @property (strong) IBOutlet NSPopUpButtonCell *bootROMsButton; @property (strong) IBOutlet NSPopUpButton *rumbleModePopupButton; @property (weak) IBOutlet NSSlider *temperatureSlider; +@property (weak) IBOutlet NSSlider *interferenceSlider; @property (weak) IBOutlet NSPopUpButton *dmgPopupButton; @property (weak) IBOutlet NSPopUpButton *sgbPopupButton; @property (weak) IBOutlet NSPopUpButton *cgbPopupButton; diff --git a/Cocoa/GBPreferencesWindow.m b/Cocoa/GBPreferencesWindow.m @@ -27,6 +27,7 @@ NSPopUpButton *_preferredJoypadButton; NSPopUpButton *_rumbleModePopupButton; NSSlider *_temperatureSlider; + NSSlider *_interferenceSlider; } + (NSArray *)filterList @@ -108,6 +109,18 @@ { return _temperatureSlider; } + +- (void)setInterferenceSlider:(NSSlider *)interferenceSlider +{ + _interferenceSlider = interferenceSlider; + [interferenceSlider setDoubleValue:[[NSUserDefaults standardUserDefaults] doubleForKey:@"GBInterferenceVolume"] * 256]; +} + +- (NSSlider *)interferenceSlider +{ + return _interferenceSlider; +} + - (void)setFrameBlendingModePopupButton:(NSPopUpButton *)frameBlendingModePopupButton { _frameBlendingModePopupButton = frameBlendingModePopupButton; @@ -303,6 +316,14 @@ [[NSNotificationCenter defaultCenter] postNotificationName:@"GBLightTemperatureChanged" object:nil]; } +- (IBAction)volumeTemperatureChanged:(id)sender +{ + [[NSUserDefaults standardUserDefaults] setObject:@([sender doubleValue] / 256.0) + forKey:@"GBInterferenceVolume"]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"GBInterferenceVolumeChanged" object:nil]; + +} + - (IBAction)franeBlendingModeChanged:(id)sender { [[NSUserDefaults standardUserDefaults] setObject:@([sender indexOfSelectedItem]) diff --git a/Cocoa/Preferences.xib b/Cocoa/Preferences.xib @@ -73,6 +73,7 @@ <outlet property="frameBlendingModePopupButton" destination="lxk-db-Sxv" id="wzt-uo-TE6"/> <outlet property="graphicsFilterPopupButton" destination="6pP-kK-EEC" id="LS7-HY-kHC"/> <outlet property="highpassFilterPopupButton" destination="T69-6N-dhT" id="0p6-4m-hb1"/> + <outlet property="interferenceSlider" destination="FpE-5i-j5L" id="hfH-e8-7cx"/> <outlet property="playerListButton" destination="gWx-7h-0xq" id="zo6-82-JId"/> <outlet property="preferredJoypadButton" destination="0Az-0R-oNw" id="7JM-tw-BhK"/> <outlet property="rewindPopupButton" destination="7fg-Ww-JjR" id="Ka2-TP-B1x"/> @@ -174,7 +175,7 @@ </textFieldCell> </textField> <popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lxk-db-Sxv"> - <rect key="frame" x="32" y="149" width="229" height="22"/> + <rect key="frame" x="30" y="149" width="231" height="22"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <popUpButtonCell key="cell" type="push" title="Disabled" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="iHP-Yz-fiH" id="aQ6-HN-7Aj"> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> @@ -264,7 +265,7 @@ </connections> </button> <slider verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="NuA-mL-AJZ"> - <rect key="frame" x="32" y="207" width="228" height="24"/> + <rect key="frame" x="30" y="207" width="230" height="24"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <sliderCell key="cell" continuous="YES" state="on" alignment="left" minValue="-256" maxValue="256" tickMarkPosition="below" numberOfTickMarks="3" sliderType="linear" id="KX7-G9-k0O"/> <connections> @@ -446,11 +447,11 @@ <point key="canvasLocation" x="-176" y="848"/> </customView> <customView id="Zn1-Y5-RbR"> - <rect key="frame" x="0.0" y="0.0" width="292" height="86"/> + <rect key="frame" x="0.0" y="0.0" width="292" height="134"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <subviews> <popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T69-6N-dhT"> - <rect key="frame" x="30" y="17" width="233" height="26"/> + <rect key="frame" x="30" y="65" width="233" height="26"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <popUpButtonCell key="cell" type="push" title="Disabled (Keep DC offset)" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Fgo-0S-zUG" id="om2-Bn-43B"> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> @@ -470,7 +471,7 @@ </connections> </popUpButton> <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="WU3-oV-KHO"> - <rect key="frame" x="18" y="49" width="256" height="17"/> + <rect key="frame" x="18" y="97" width="256" height="17"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="High-pass filter:" id="YLF-RL-b2D"> <font key="font" metaFont="system"/> @@ -478,8 +479,25 @@ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> </textFieldCell> </textField> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GPt-9I-QBh"> + <rect key="frame" x="18" y="43" width="252" height="17"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Interference volume:" id="I2Q-6U-uIx"> + <font key="font" metaFont="system"/> + <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <slider verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FpE-5i-j5L"> + <rect key="frame" x="30" y="18" width="232" height="19"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="256" tickMarkPosition="below" sliderType="linear" id="Rbx-DU-xYf"/> + <connections> + <action selector="volumeTemperatureChanged:" target="QvC-M9-y7g" id="HFU-0q-hj1"/> + </connections> + </slider> </subviews> - <point key="canvasLocation" x="-176" y="890"/> + <point key="canvasLocation" x="-176" y="914"/> </customView> <customView id="8TU-6J-NCg"> <rect key="frame" x="0.0" y="0.0" width="292" height="467"/> diff --git a/Core/apu.c b/Core/apu.c @@ -137,6 +137,45 @@ static double smooth(double x) return 3*x*x - 2*x*x*x; } +static signed interference(GB_gameboy_t *gb) +{ + /* These aren't scientifically measured, but based on ear based on several recordings */ + signed ret = 0; + if (gb->halted) { + if (gb->model != GB_MODEL_AGB) { + ret -= MAX_CH_AMP / 5; + } + else { + ret -= MAX_CH_AMP / 12; + } + } + if (gb->io_registers[GB_IO_LCDC] & 0x80) { + ret += MAX_CH_AMP / 7; + if ((gb->io_registers[GB_IO_STAT] & 3) == 3 && gb->model != GB_MODEL_AGB) { + ret += MAX_CH_AMP / 14; + } + else if ((gb->io_registers[GB_IO_STAT] & 3) == 1) { + ret -= MAX_CH_AMP / 7; + } + } + + if (gb->apu.global_enable) { + ret += MAX_CH_AMP / 10; + } + + if (GB_is_cgb(gb) && gb->model < GB_MODEL_AGB && (gb->io_registers[GB_IO_RP] & 1)) { + ret += MAX_CH_AMP / 10; + } + + if (!GB_is_cgb(gb)) { + ret /= 4; + } + + ret += rand() % (MAX_CH_AMP / 12); + + return ret; +} + static void render(GB_gameboy_t *gb) { GB_sample_t output = {0, 0}; @@ -226,6 +265,17 @@ static void render(GB_gameboy_t *gb) } + + if (gb->apu_output.interference_volume) { + signed interference_bias = interference(gb); + int16_t interference_sample = (interference_bias - gb->apu_output.interference_highpass); + gb->apu_output.interference_highpass = gb->apu_output.interference_highpass * gb->apu_output.highpass_rate + + (1 - gb->apu_output.highpass_rate) * interference_sample; + interference_bias *= gb->apu_output.interference_volume; + + filtered_output.left = MAX(MIN(filtered_output.left + interference_bias, 0x7FFF), -0x8000); + filtered_output.right = MAX(MIN(filtered_output.right + interference_bias, 0x7FFF), -0x8000); + } assert(gb->apu_output.sample_callback); gb->apu_output.sample_callback(gb, &filtered_output); } @@ -1122,3 +1172,8 @@ void GB_apu_update_cycles_per_sample(GB_gameboy_t *gb) gb->apu_output.cycles_per_sample = 2 * GB_get_clock_rate(gb) / (double)gb->apu_output.sample_rate; /* 2 * because we use 8MHz units */ } } + +void GB_set_interference_volume(GB_gameboy_t *gb, double volume) +{ + gb->apu_output.interference_volume = volume; +} diff --git a/Core/apu.h b/Core/apu.h @@ -154,12 +154,16 @@ typedef struct { GB_sample_callback_t sample_callback; bool rate_set_in_clocks; + double interference_volume; + double interference_highpass; } GB_apu_output_t; void GB_set_sample_rate(GB_gameboy_t *gb, unsigned sample_rate); void GB_set_sample_rate_by_clocks(GB_gameboy_t *gb, double cycles_per_sample); /* Cycles are in 8MHz units */ void GB_set_highpass_filter_mode(GB_gameboy_t *gb, GB_highpass_mode_t mode); +void GB_set_interference_volume(GB_gameboy_t *gb, double volume); void GB_apu_set_sample_callback(GB_gameboy_t *gb, GB_sample_callback_t callback); + #ifdef GB_INTERNAL bool GB_apu_is_DAC_enabled(GB_gameboy_t *gb, unsigned index); void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value); diff --git a/SDL/gui.c b/SDL/gui.c @@ -789,7 +789,7 @@ static const struct menu_item graphics_menu[] = { {"Default Window Scale:", cycle_default_scale, current_default_scale, cycle_default_scale_backwards}, {"Scaling Filter:", cycle_filter, current_filter_name, cycle_filter_backwards}, {"Color Correction:", cycle_color_correction, current_color_correction_mode, cycle_color_correction_backwards}, - {"Ambient Light:", decrease_color_temperature, current_color_temperature, increase_color_temperature}, + {"Ambient Light Temp.:", decrease_color_temperature, current_color_temperature, increase_color_temperature}, {"Frame Blending:", cycle_blending_mode, blending_mode_string, cycle_blending_mode_backwards}, {"Mono Palette:", cycle_palette, current_palette, cycle_palette_backwards}, {"Display Border:", cycle_border_mode, current_border_mode, cycle_border_mode_backwards}, @@ -852,9 +852,33 @@ void decrease_volume(unsigned index) } } +const char *interference_volume_string(unsigned index) +{ + static char ret[5]; + sprintf(ret, "%d%%", configuration.interference_volume); + return ret; +} + +void increase_interference_volume(unsigned index) +{ + configuration.interference_volume += 5; + if (configuration.interference_volume > 100) { + configuration.interference_volume = 100; + } +} + +void decrease_interference_volume(unsigned index) +{ + configuration.interference_volume -= 5; + if (configuration.interference_volume > 100) { + configuration.interference_volume = 0; + } +} + static const struct menu_item audio_menu[] = { {"Highpass Filter:", cycle_highpass_filter, highpass_filter_string, cycle_highpass_filter_backwards}, {"Volume:", increase_volume, volume_string, decrease_volume}, + {"Interference Volume:", increase_interference_volume, interference_volume_string, decrease_interference_volume}, {"Back", return_to_root_menu}, {NULL,} }; diff --git a/SDL/gui.h b/SDL/gui.h @@ -115,6 +115,7 @@ typedef struct { unsigned padding; uint8_t color_temperature; char bootrom_path[4096]; + uint8_t interference_volume; } configuration_t; extern configuration_t configuration; diff --git a/SDL/main.c b/SDL/main.c @@ -121,6 +121,7 @@ static void open_menu(void) } GB_set_color_correction_mode(&gb, configuration.color_correction_mode); GB_set_light_temperature(&gb, (configuration.color_temperature - 10.0) / 10.0); + GB_set_interference_volume(&gb, configuration.interference_volume / 100.0); GB_set_border_mode(&gb, configuration.border_mode); update_palette(); GB_set_highpass_filter_mode(&gb, configuration.highpass_mode); @@ -505,6 +506,7 @@ restart: GB_set_sample_rate(&gb, GB_audio_get_frequency()); GB_set_color_correction_mode(&gb, configuration.color_correction_mode); GB_set_light_temperature(&gb, (configuration.color_temperature - 10.0) / 10.0); + GB_set_interference_volume(&gb, configuration.interference_volume / 100.0); update_palette(); if ((unsigned)configuration.border_mode <= GB_BORDER_ALWAYS) { GB_set_border_mode(&gb, configuration.border_mode);

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.