git.y1.nz

SameBoy

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

commit 6ddfcc9725603f7a6ab7469d39240b585e7efbac
parent 77384a5f6af578792cb34826fa9cd6b7cbe7b268
Author: Lior Halphon <LIJI32@gmail.com>
Date:   Sat, 10 Apr 2021 16:10:10 +0300

Added visualizer to the GBS player, various GBS UI improvements

Diffstat:
MCocoa/Document.h2++
MCocoa/Document.m15++++++++++++++-
MCocoa/GBS.xib65++++++++++++++++++++++++++++++++++++++++-------------------------
MCocoa/GBViewMetal.m4++--
ACocoa/GBVisualizerView.h14++++++++++++++
ACocoa/GBVisualizerView.m95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 167 insertions(+), 28 deletions(-)

diff --git a/Cocoa/Document.h b/Cocoa/Document.h @@ -2,6 +2,7 @@ #include "GBView.h" #include "GBImageView.h" #include "GBSplitView.h" +#include "GBVisualizerView.h" @class GBCheatWindowController; @@ -47,6 +48,7 @@ @property (strong) IBOutlet NSButton *gbsPlayPauseButton; @property (strong) IBOutlet NSButton *gbsRewindButton; @property (strong) IBOutlet NSSegmentedControl *gbsNextPrevButton; +@property (strong) IBOutlet GBVisualizerView *gbsVisualizer; -(uint8_t) readMemory:(uint16_t) addr; -(void) writeMemory:(uint16_t) addr value:(uint8_t)value; diff --git a/Cocoa/Document.m b/Cocoa/Document.m @@ -318,6 +318,11 @@ static void infraredStateChanged(GB_gameboy_t *gb, bool on) - (void) vblank { + if (_gbsVisualizer) { + dispatch_async(dispatch_get_main_queue(), ^{ + [_gbsVisualizer setNeedsDisplay:YES]; + }); + } [self.view flip]; if (borderModeChanged) { dispatch_sync(dispatch_get_main_queue(), ^{ @@ -344,6 +349,9 @@ static void infraredStateChanged(GB_gameboy_t *gb, bool on) - (void)gotNewSample:(GB_sample_t *)sample { + if (_gbsVisualizer) { + [_gbsVisualizer addSample:sample]; + } [audioLock lock]; if (self.audioClient.isPlaying) { if (audioBufferPosition == audioBufferSize) { @@ -837,6 +845,9 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) - (IBAction)changeGBSTrack:(id)sender { + if (!running) { + [self start]; + } [self performAtomicBlock:^{ GB_gbs_switch_track(&gb, self.gbsTracks.indexOfSelectedItem); }]; @@ -878,7 +889,9 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) [_mainWindow standardWindowButton:NSWindowZoomButton].enabled = false; }); [_mainWindow.contentView addSubview:self.gbsPlayerView]; - + _mainWindow.movableByWindowBackground = true; + [_mainWindow setContentBorderThickness:24 forEdge:NSRectEdgeMinY]; + self.gbsTitle.stringValue = [NSString stringWithCString:info->title encoding:NSISOLatin1StringEncoding] ?: @"GBS Player"; self.gbsAuthor.stringValue = [NSString stringWithCString:info->author encoding:NSISOLatin1StringEncoding] ?: @"Unknown Composer"; NSString *copyright = [NSString stringWithCString:info->copyright encoding:NSISOLatin1StringEncoding]; diff --git a/Cocoa/GBS.xib b/Cocoa/GBS.xib @@ -16,44 +16,36 @@ <outlet property="gbsRewindButton" destination="0yD-Sp-Ilo" id="FgR-xd-JW5"/> <outlet property="gbsTitle" destination="H3v-X3-48q" id="DCl-wL-oy8"/> <outlet property="gbsTracks" destination="I1T-VS-Vse" id="Vk4-GP-RjB"/> + <outlet property="gbsVisualizer" destination="Q3o-bK-DIN" id="1YC-C5-Je6"/> </connections> </customObject> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/> <customView id="c22-O7-iKe"> - <rect key="frame" x="0.0" y="0.0" width="332" height="142"/> + <rect key="frame" x="0.0" y="0.0" width="332" height="221"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <subviews> <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="H3v-X3-48q"> - <rect key="frame" x="19.5" y="103" width="296" height="19"/> - <autoresizingMask key="autoresizingMask" flexibleMaxY="YES"/> - <textFieldCell key="cell" lineBreakMode="clipping" selectable="YES" alignment="center" title="Title" id="BwZ-Zj-sP6"> + <rect key="frame" x="18" y="192" width="296" height="19"/> + <autoresizingMask key="autoresizingMask" flexibleMinY="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Title" id="BwZ-Zj-sP6"> <font key="font" metaFont="systemBold" size="16"/> <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> </textField> <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="gaD-ZH-Beh"> - <rect key="frame" x="19.5" y="79" width="296" height="16"/> - <autoresizingMask key="autoresizingMask" flexibleMaxY="YES"/> - <textFieldCell key="cell" lineBreakMode="clipping" selectable="YES" alignment="center" title="Author" id="IgT-r1-T38"> - <font key="font" metaFont="system"/> - <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> - </textFieldCell> - </textField> - <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="2dl-dH-E3J"> - <rect key="frame" x="18.5" y="24" width="296" height="16"/> - <autoresizingMask key="autoresizingMask" flexibleMaxY="YES"/> - <textFieldCell key="cell" lineBreakMode="clipping" selectable="YES" title="Copyright" id="nM9-oF-OV9"> + <rect key="frame" x="18" y="166" width="296" height="16"/> + <autoresizingMask key="autoresizingMask" flexibleMinY="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Author" id="IgT-r1-T38"> <font key="font" metaFont="system"/> <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> </textField> <button focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qxJ-pH-d0y"> - <rect key="frame" x="61.5" y="48" width="39" height="23"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <rect key="frame" x="61.5" y="127" width="39" height="23"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="Play" imagePosition="only" alignment="center" alternateImage="Pause" state="on" borderStyle="border" focusRingType="none" inset="2" id="3ZK-br-UrS"> <behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/> <font key="font" metaFont="system"/> @@ -63,8 +55,8 @@ </connections> </button> <button focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0yD-Sp-Ilo"> - <rect key="frame" x="19.5" y="48" width="38" height="23"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <rect key="frame" x="19.5" y="127" width="38" height="23"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="Rewind" imagePosition="only" alignment="center" state="on" borderStyle="border" focusRingType="none" inset="2" id="ZIF-TP-Fqn"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <font key="font" metaFont="system"/> @@ -74,8 +66,8 @@ </connections> </button> <popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="I1T-VS-Vse"> - <rect key="frame" x="105.5" y="48" width="131" height="23"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <rect key="frame" x="106" y="127" width="131" height="23"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <popUpButtonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" id="YJh-dI-A5D"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <font key="font" metaFont="menu"/> @@ -86,8 +78,8 @@ </connections> </popUpButton> <segmentedControl verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SRS-M5-VVL"> - <rect key="frame" x="240.5" y="48" width="72" height="23"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <rect key="frame" x="240.5" y="127" width="72" height="23"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <segmentedCell key="cell" borderStyle="border" alignment="left" style="texturedRounded" trackingMode="momentary" id="cmq-I8-cFL"> <font key="font" metaFont="system"/> <segments> @@ -99,8 +91,31 @@ <action selector="gbsNextPrevPushed:" target="-2" id="roN-Iy-tDQ"/> </connections> </segmentedControl> + <box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="b9A-cd-ias"> + <rect key="frame" x="0.0" y="117" width="332" height="5"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + </box> + <customView appearanceType="darkAqua" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tRy-Gw-IaG" customClass="GBOptionalVisualEffectView"> + <rect key="frame" x="0.0" y="24" width="332" height="95"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <subviews> + <customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Q3o-bK-DIN" customClass="GBVisualizerView"> + <rect key="frame" x="0.0" y="0.0" width="332" height="95"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + </customView> + </subviews> + </customView> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="2dl-dH-E3J"> + <rect key="frame" x="18" y="5" width="296" height="14"/> + <autoresizingMask key="autoresizingMask" flexibleMinY="YES"/> + <textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="Copyright" id="nM9-oF-OV9"> + <font key="font" metaFont="smallSystem"/> + <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> </subviews> - <point key="canvasLocation" x="67" y="253"/> + <point key="canvasLocation" x="67" y="292.5"/> </customView> </objects> <resources> diff --git a/Cocoa/GBViewMetal.m b/Cocoa/GBViewMetal.m @@ -123,7 +123,7 @@ static const vector_float2 rect[] = command_queue = [device newCommandQueue]; } -- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size +- (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size { output_resolution = (vector_float2){size.width, size.height}; dispatch_async(dispatch_get_main_queue(), ^{ @@ -131,7 +131,7 @@ static const vector_float2 rect[] = }); } -- (void)drawInMTKView:(nonnull MTKView *)view +- (void)drawInMTKView:(MTKView *)view { if (!(view.window.occlusionState & NSWindowOcclusionStateVisible)) return; if (!self.gb) return; diff --git a/Cocoa/GBVisualizerView.h b/Cocoa/GBVisualizerView.h @@ -0,0 +1,14 @@ +// +// GBVisualizerView.h +// SameBoySDL +// +// Created by Lior Halphon on 7/4/21. +// Copyright © 2021 Lior Halphon. All rights reserved. +// + +#import <Cocoa/Cocoa.h> +#include <Core/gb.h> + +@interface GBVisualizerView : NSView +- (void)addSample:(GB_sample_t *)sample; +@end diff --git a/Cocoa/GBVisualizerView.m b/Cocoa/GBVisualizerView.m @@ -0,0 +1,95 @@ +// +// GBVisualizerView.m +// SameBoySDL +// +// Created by Lior Halphon on 7/4/21. +// Copyright © 2021 Lior Halphon. All rights reserved. +// + +#import "GBVisualizerView.h" +#include <Core/gb.h> + +#define SAMPLE_COUNT 1024 + +static NSColor *color_to_effect_color(typeof(GB_PALETTE_DMG.colors[0]) color) +{ + if (@available(macOS 10.10, *)) { + double tint = MAX(color.r, MAX(color.g, color.b)) + 64; + + return [NSColor colorWithRed:color.r / tint + green:color.g / tint + blue:color.b / tint + alpha:tint/(255 + 64)]; + + } + return [NSColor colorWithRed:color.r / 255.0 + green:color.g / 255.0 + blue:color.b / 255.0 + alpha:1.0]; +} + +@implementation GBVisualizerView +{ + GB_sample_t _samples[SAMPLE_COUNT]; + size_t _position; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + const GB_palette_t *palette; + switch ([[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorPalette"]) { + case 1: + palette = &GB_PALETTE_DMG; + break; + + case 2: + palette = &GB_PALETTE_MGB; + break; + + case 3: + palette = &GB_PALETTE_GBL; + break; + + default: + palette = &GB_PALETTE_GREY; + break; + } + NSSize size = self.bounds.size; + + [color_to_effect_color(palette->colors[0]) setFill]; + NSRectFill(self.bounds); + + NSBezierPath *line = [NSBezierPath bezierPath]; + [line moveToPoint:NSMakePoint(0, size.height / 2)]; + + for (unsigned i = 0; i < SAMPLE_COUNT; i++) { + GB_sample_t *sample = _samples + ((i + _position) % SAMPLE_COUNT); + double volume = ((signed)sample->left + (signed)sample->right) / 32768.0; + [line lineToPoint:NSMakePoint(size.width * (i + 0.5) / SAMPLE_COUNT, + (volume + 1) * size.height / 2)]; + } + + [line lineToPoint:NSMakePoint(size.width, size.height / 2)]; + [line setLineWidth:1.0]; + + [color_to_effect_color(palette->colors[2]) setFill]; + [line fill]; + + [color_to_effect_color(palette->colors[1]) setFill]; + NSRectFill(NSMakeRect(0, size.height / 2 - 0.5, size.width, 1)); + + [color_to_effect_color(palette->colors[3]) setStroke]; + [line stroke]; + + [super drawRect:dirtyRect]; +} + +- (void)addSample:(GB_sample_t *)sample +{ + _samples[_position++] = *sample; + if (_position == SAMPLE_COUNT) { + _position = 0; + } +} + +@end

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