Cocoa GBS Player

This commit is contained in:
Lior Halphon 2021-04-03 01:29:43 +03:00
parent 9996c7b4a2
commit bb3a73ff88
15 changed files with 243 additions and 7 deletions

View File

@ -39,6 +39,14 @@
@property (nonatomic, strong) IBOutlet GBCheatWindowController *cheatWindowController; @property (nonatomic, strong) IBOutlet GBCheatWindowController *cheatWindowController;
@property (nonatomic, readonly) Document *partner; @property (nonatomic, readonly) Document *partner;
@property (nonatomic, readonly) bool isSlave; @property (nonatomic, readonly) bool isSlave;
@property (strong) IBOutlet NSView *gbsPlayerView;
@property (strong) IBOutlet NSTextField *gbsTitle;
@property (strong) IBOutlet NSTextField *gbsAuthor;
@property (strong) IBOutlet NSTextField *gbsCopyright;
@property (strong) IBOutlet NSPopUpButton *gbsTracks;
@property (strong) IBOutlet NSButton *gbsPlayPauseButton;
@property (strong) IBOutlet NSButton *gbsRewindButton;
@property (strong) IBOutlet NSSegmentedControl *gbsNextPrevButton;
-(uint8_t) readMemory:(uint16_t) addr; -(uint8_t) readMemory:(uint16_t) addr;
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value; -(void) writeMemory:(uint16_t) addr value:(uint8_t)value;

View File

@ -513,6 +513,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
- (void) start - (void) start
{ {
self.gbsPlayPauseButton.state = true;
self.view.mouseHidingEnabled = (self.mainWindow.styleMask & NSWindowStyleMaskFullScreen) != 0; self.view.mouseHidingEnabled = (self.mainWindow.styleMask & NSWindowStyleMaskFullScreen) != 0;
if (master) { if (master) {
[master start]; [master start];
@ -524,6 +525,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
- (void) stop - (void) stop
{ {
self.gbsPlayPauseButton.state = false;
if (master) { if (master) {
if (!master->running) return; if (!master->running) return;
GB_debugger_set_disabled(&gb, true); GB_debugger_set_disabled(&gb, true);
@ -834,14 +836,86 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
return YES; return YES;
} }
- (IBAction)changeGBSTrack:(id)sender
{
[self performAtomicBlock:^{
GB_gbs_switch_track(&gb, self.gbsTracks.indexOfSelectedItem);
}];
}
- (IBAction)gbsNextPrevPushed:(id)sender
{
if (self.gbsNextPrevButton.selectedSegment == 0) {
// Previous
if (self.gbsTracks.indexOfSelectedItem == 0) {
[self.gbsTracks selectItemAtIndex:self.gbsTracks.numberOfItems - 1];
}
else {
[self.gbsTracks selectItemAtIndex:self.gbsTracks.indexOfSelectedItem - 1];
}
}
else {
// Next
if (self.gbsTracks.indexOfSelectedItem == self.gbsTracks.numberOfItems - 1) {
[self.gbsTracks selectItemAtIndex: 0];
}
else {
[self.gbsTracks selectItemAtIndex:self.gbsTracks.indexOfSelectedItem + 1];
}
}
[self changeGBSTrack:sender];
}
- (void)prepareGBSInterface: (GB_gbs_info_t *)info
{
GB_set_rendering_disabled(&gb, true);
_view = nil;
for (NSView *view in _mainWindow.contentView.subviews) {
[view removeFromSuperview];
}
[[NSBundle mainBundle] loadNibNamed:@"GBS" owner:self topLevelObjects:nil];
[_mainWindow setContentSize:self.gbsPlayerView.bounds.size];
_mainWindow.styleMask &= ~NSWindowStyleMaskResizable;
[_mainWindow.contentView addSubview:self.gbsPlayerView];
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];
if (copyright) {
copyright = [@"©" stringByAppendingString:copyright];
}
self.gbsCopyright.stringValue = copyright ?: @"Missing copyright information";
for (unsigned i = 0; i < info->track_count; i++) {
[self.gbsTracks addItemWithTitle:[NSString stringWithFormat:@"Track %u", i + 1]];
}
[self.gbsTracks selectItemAtIndex:info->first_track];
self.gbsPlayPauseButton.image.template = true;
self.gbsPlayPauseButton.alternateImage.template = true;
self.gbsRewindButton.image.template = true;
for (unsigned i = 0; i < 2; i++) {
[self.gbsNextPrevButton imageForSegment:i].template = true;
}
if (!self.audioClient.isPlaying) {
[self.audioClient start];
}
if (@available(macOS 10.10, *)) {
_mainWindow.titlebarAppearsTransparent = true;
}
}
- (void) loadROM - (void) loadROM
{ {
NSString *rom_warnings = [self captureOutputForBlock:^{ NSString *rom_warnings = [self captureOutputForBlock:^{
GB_debugger_clear_symbols(&gb); GB_debugger_clear_symbols(&gb);
if ([[self.fileType pathExtension] isEqualToString:@"isx"]) { if ([[[self.fileType pathExtension] lowercaseString] isEqualToString:@"isx"]) {
GB_load_isx(&gb, self.fileURL.path.UTF8String); GB_load_isx(&gb, self.fileURL.path.UTF8String);
GB_load_battery(&gb, [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"ram"].path.UTF8String); GB_load_battery(&gb, [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"ram"].path.UTF8String);
}
else if ([[[self.fileType pathExtension] lowercaseString] isEqualToString:@"gbs"]) {
GB_gbs_info_t info;
GB_load_gbs(&gb, self.fileURL.path.UTF8String, &info);
[self prepareGBSInterface:&info];
} }
else { else {
GB_load_rom(&gb, [self.fileURL.path UTF8String]); GB_load_rom(&gb, [self.fileURL.path UTF8String]);
@ -861,8 +935,10 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
- (void)close - (void)close
{ {
[self disconnectLinkCable]; [self disconnectLinkCable];
[[NSUserDefaults standardUserDefaults] setInteger:self.mainWindow.frame.size.width forKey:@"LastWindowWidth"]; if (!self.gbsPlayerView) {
[[NSUserDefaults standardUserDefaults] setInteger:self.mainWindow.frame.size.height forKey:@"LastWindowHeight"]; [[NSUserDefaults standardUserDefaults] setInteger:self.mainWindow.frame.size.width forKey:@"LastWindowWidth"];
[[NSUserDefaults standardUserDefaults] setInteger:self.mainWindow.frame.size.height forKey:@"LastWindowHeight"];
}
[self stop]; [self stop];
[self.consoleWindow close]; [self.consoleWindow close];
[self.memoryWindow close]; [self.memoryWindow close];

113
Cocoa/GBS.xib Normal file
View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14868" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14868"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="Document">
<connections>
<outlet property="gbsAuthor" destination="gaD-ZH-Beh" id="2i7-BD-bJ2"/>
<outlet property="gbsCopyright" destination="2dl-dH-E3J" id="LnT-Vb-pN6"/>
<outlet property="gbsNextPrevButton" destination="SRS-M5-VVL" id="YEN-01-wRX"/>
<outlet property="gbsPlayPauseButton" destination="qxJ-pH-d0y" id="qk8-8I-9u5"/>
<outlet property="gbsPlayerView" destination="c22-O7-iKe" id="A1w-e5-EQE"/>
<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"/>
</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"/>
<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">
<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">
<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"/>
<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"/>
</buttonCell>
<connections>
<action selector="togglePause:" target="-2" id="AUe-I7-nOK"/>
</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"/>
<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"/>
</buttonCell>
<connections>
<action selector="changeGBSTrack:" target="-2" id="jug-AS-bW7"/>
</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"/>
<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"/>
<menu key="menu" id="Knp-Ok-Pb4"/>
</popUpButtonCell>
<connections>
<action selector="changeGBSTrack:" target="-2" id="HET-AT-CfQ"/>
</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"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="texturedRounded" trackingMode="momentary" id="cmq-I8-cFL">
<font key="font" metaFont="system"/>
<segments>
<segment toolTip="Previous Track" image="Previous" width="33"/>
<segment toolTip="Next Track" image="Next" width="32" tag="1"/>
</segments>
</segmentedCell>
<connections>
<action selector="gbsNextPrevPushed:" target="-2" id="roN-Iy-tDQ"/>
</connections>
</segmentedControl>
</subviews>
<point key="canvasLocation" x="67" y="253"/>
</customView>
</objects>
<resources>
<image name="Next" width="16" height="10"/>
<image name="Pause" width="10" height="10"/>
<image name="Play" width="10" height="10"/>
<image name="Previous" width="16" height="10"/>
<image name="Rewind" width="10" height="10"/>
</resources>
</document>

View File

@ -51,7 +51,7 @@
<dict> <dict>
<key>CFBundleTypeExtensions</key> <key>CFBundleTypeExtensions</key>
<array> <array>
<string>gbc</string> <string>isx</string>
</array> </array>
<key>CFBundleTypeIconFile</key> <key>CFBundleTypeIconFile</key>
<string>ColorCartridge</string> <string>ColorCartridge</string>
@ -68,6 +68,26 @@
<key>NSDocumentClass</key> <key>NSDocumentClass</key>
<string>Document</string> <string>Document</string>
</dict> </dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>gbs</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>ColorCartridge</string>
<key>CFBundleTypeName</key>
<string>Game Boy Sound File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>com.github.liji32.sameboy.gbs</string>
</array>
<key>LSTypeIsPackage</key>
<integer>0</integer>
<key>NSDocumentClass</key>
<string>Document</string>
</dict>
</array> </array>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>SameBoy</string> <string>SameBoy</string>
@ -156,6 +176,25 @@
</array> </array>
</dict> </dict>
</dict> </dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>Game Boy Sound File</string>
<key>UTTypeIconFile</key>
<string>ColorCartridge</string>
<key>UTTypeIdentifier</key>
<string>com.github.liji32.sameboy.gbs</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>gbs</string>
</array>
</dict>
</dict>
</array> </array>
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>SameBoy needs to access your camera to emulate the Game Boy Camera</string> <string>SameBoy needs to access your camera to emulate the Game Boy Camera</string>

BIN
Cocoa/Next.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Cocoa/Next@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
Cocoa/Pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Cocoa/Pause@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
Cocoa/Play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
Cocoa/Play@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
Cocoa/Previous.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Cocoa/Previous@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
Cocoa/Rewind.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Cocoa/Rewind@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -126,7 +126,7 @@ static void display_vblank(GB_gameboy_t *gb)
bool is_ppu_stopped = !GB_is_cgb(gb) && gb->stopped && gb->io_registers[GB_IO_LCDC] & 0x80; bool is_ppu_stopped = !GB_is_cgb(gb) && gb->stopped && gb->io_registers[GB_IO_LCDC] & 0x80;
if (!gb->disable_rendering && ((!(gb->io_registers[GB_IO_LCDC] & 0x80) || is_ppu_stopped) || gb->cgb_repeated_a_frame)) { if (!gb->disable_rendering && ((!(gb->io_registers[GB_IO_LCDC] & 0x80) || is_ppu_stopped) || gb->cgb_repeated_a_frame)) {
/* LCD is off, set screen to white or black (if LCD is on in stop mode) */ /* LCD is off, set screen to white or black (if LCD is on in stop mode) */
if (!GB_is_sgb(gb)) { if (!GB_is_sgb(gb)) {
uint32_t color = 0; uint32_t color = 0;
@ -153,7 +153,7 @@ static void display_vblank(GB_gameboy_t *gb)
} }
} }
if (gb->border_mode == GB_BORDER_ALWAYS && !GB_is_sgb(gb)) { if (!gb->disable_rendering && gb->border_mode == GB_BORDER_ALWAYS && !GB_is_sgb(gb)) {
GB_borrow_sgb_border(gb); GB_borrow_sgb_border(gb);
uint32_t border_colors[16 * 4]; uint32_t border_colors[16 * 4];