mirror of
https://github.com/ksherlock/ample.git
synced 2026-10-25 13:02:57 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e9088c41b | ||
|
|
23dee5bf2a | ||
|
|
bd9d4972b5 | ||
|
|
4224a942ef |
No files matched your search
@@ -64,6 +64,29 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>gio64_gfx</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>GIO64 Graphics</string>
|
||||||
|
<key>options</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>xl24</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>SGI 24-bit XL board</string>
|
||||||
|
<key>default</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>xl8</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>SGI 8-bit XL board</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>devices</key>
|
<key>devices</key>
|
||||||
<array>
|
<array>
|
||||||
|
|||||||
@@ -76,6 +76,29 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>gio64_gfx</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>GIO32 Graphics</string>
|
||||||
|
<key>options</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>xl24</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>SGI 24-bit XL board</string>
|
||||||
|
<key>default</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>xl8</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>SGI 8-bit XL board</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>devices</key>
|
<key>devices</key>
|
||||||
<array>
|
<array>
|
||||||
|
|||||||
@@ -76,6 +76,29 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>gio64_gfx</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>GIO32 Graphics</string>
|
||||||
|
<key>options</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>xl24</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>SGI 24-bit XL board</string>
|
||||||
|
<key>default</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>xl8</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>SGI 8-bit XL board</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>devices</key>
|
<key>devices</key>
|
||||||
<array>
|
<array>
|
||||||
|
|||||||
@@ -58,6 +58,29 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>gio64_gfx</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>GIO32 Graphics</string>
|
||||||
|
<key>options</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>xl24</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>SGI 24-bit XL board</string>
|
||||||
|
<key>default</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>xl8</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>SGI 8-bit XL board</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>devices</key>
|
<key>devices</key>
|
||||||
<array>
|
<array>
|
||||||
|
|||||||
@@ -880,6 +880,37 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>description</key>
|
||||||
|
<string>Lisa</string>
|
||||||
|
<key>children</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>description</key>
|
||||||
|
<string>Lisa</string>
|
||||||
|
<key>value</key>
|
||||||
|
<string>lisa</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>description</key>
|
||||||
|
<string>Lisa2</string>
|
||||||
|
<key>value</key>
|
||||||
|
<string>lisa2</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>description</key>
|
||||||
|
<string>Lisa2/10</string>
|
||||||
|
<key>value</key>
|
||||||
|
<string>lisa210</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>description</key>
|
||||||
|
<string>Macintosh XL</string>
|
||||||
|
<key>value</key>
|
||||||
|
<string>macxl</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>description</key>
|
<key>description</key>
|
||||||
<string>Acorn</string>
|
<string>Acorn</string>
|
||||||
@@ -1129,5 +1160,36 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>description</key>
|
||||||
|
<string>Silicon Graphics</string>
|
||||||
|
<key>children</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>description</key>
|
||||||
|
<string> Indigo2 (R4400, 150MHz)</string>
|
||||||
|
<key>value</key>
|
||||||
|
<string>indigo2_4415</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>description</key>
|
||||||
|
<string> Indy (R4600, 100MHz)</string>
|
||||||
|
<key>value</key>
|
||||||
|
<string>indy_4610</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>description</key>
|
||||||
|
<string> Indy (R4600, 133MHz)</string>
|
||||||
|
<key>value</key>
|
||||||
|
<string>indy_4613</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>description</key>
|
||||||
|
<string> Indy (R5000, 150MHz)</string>
|
||||||
|
<key>value</key>
|
||||||
|
<string>indy_5015</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -1921,6 +1921,12 @@
|
|||||||
<string>pd3_mclr</string>
|
<string>pd3_mclr</string>
|
||||||
<key>description</key>
|
<key>description</key>
|
||||||
<string>Micron/XCEED Technology MacroColor 30</string>
|
<string>Micron/XCEED Technology MacroColor 30</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>kb_ms_natural</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>Microsoft Natural Keyboard</string>
|
||||||
</dict>
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>value</key>
|
<key>value</key>
|
||||||
@@ -2174,6 +2180,12 @@
|
|||||||
<key>description</key>
|
<key>description</key>
|
||||||
<string>Prológica CP-450 BASIC Disco V. 1.0 (1984)</string>
|
<string>Prológica CP-450 BASIC Disco V. 1.0 (1984)</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>ps2_keybc</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>PS/2 Keyboard</string>
|
||||||
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>value</key>
|
<key>value</key>
|
||||||
<string>qsound</string>
|
<string>qsound</string>
|
||||||
@@ -2282,6 +2294,18 @@
|
|||||||
<key>description</key>
|
<key>description</key>
|
||||||
<string>SDTANDY FDC</string>
|
<string>SDTANDY FDC</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>indigo2_4415</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>SGI Indigo2 (R4400, 150MHz)</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>value</key>
|
||||||
|
<string>indy_4610</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>SGI Indy (R4600, 100MHz)</string>
|
||||||
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>value</key>
|
<key>value</key>
|
||||||
<string>gpib_hardbox</string>
|
<string>gpib_hardbox</string>
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
# Agent Task Audit Log - Ample Linux Port
|
# Agent Task Audit Log - Ample Linux Port
|
||||||
|
|
||||||
|
## 📅 Session: 2026-08-02 (Session 7)
|
||||||
|
|
||||||
|
### 🎯 Objective: Upstream MAME v0.289 Synchronization
|
||||||
|
Synchronized AmpleLinux with upstream `ksherlock/ample` v0.289 release and updated machine `.plist` configuration definitions.
|
||||||
|
|
||||||
|
### ✅ Key Achievements:
|
||||||
|
1. **PowerBook Native Launch (EASC Bug Fixed)**:
|
||||||
|
* Removed `macpb160`, `macpb165`, `macpb165c`, `macpb180`, `macpb180c` fallback prompt mechanism in `main.py`, as MAME 0.289 officially resolved the EASC audio chip crash bug.
|
||||||
|
2. **ROM Manager Priority & Dragon32/Laser Series Fixes**:
|
||||||
|
* Reordered download servers in `rom_manager.py` to prioritize CallApple (`https://www.callapple.org/roms/`) with MDK (`https://mdk.cab/download/split/`) as backup failover.
|
||||||
|
* Integrated `patch_dragon32()` in `DownloadWorker` to auto-merge missing modern MAME 0.289 split ROM files (`dragon_data_ltd_1-0.ic18`, `dragon_data_ltd_1-1.ic17`) when downloading `dragon32.zip`.
|
||||||
|
* Expanded `custom_roms` fallback array to include Laser 128 series (`las128ex`, `las128e2`, `laser128`, `laser128o`, `laser2c`), ensuring seamless auto-download even if omitted from upstream `roms.plist`.
|
||||||
|
3. **Upstream MAME 0.289 Alignment**:
|
||||||
|
* Verified `.plist` machine profile definitions (251 files) updated to MAME 0.289.
|
||||||
|
* Validated compatibility with local MAME 0.289 binaries and slot options.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 📅 Session: 2026-06-05 (Session 6)
|
## 📅 Session: 2026-06-05 (Session 6)
|
||||||
|
|
||||||
### 🎯 Objective: PowerBook Compatibility Fallback & Downloader Parity
|
### 🎯 Objective: PowerBook Compatibility Fallback & Downloader Parity
|
||||||
@@ -42,6 +60,25 @@ Synchronized slot initialization logic with AmpleWin to fix "None" persistence i
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 📅 Session: 2026-05-11 (Session 4)
|
||||||
|
|
||||||
|
### 🎯 Objective: Slot Configuration Alignment & Bug Fix
|
||||||
|
Synchronized slot initialization logic with AmpleWin to fix the issue where "None" selections were being overwritten by defaults.
|
||||||
|
|
||||||
|
### ✅ Key Achievements:
|
||||||
|
1. **"None-Aware" Slot Initialization**:
|
||||||
|
* Applied the `slot_name not in self.current_slots` fix to `main.py`.
|
||||||
|
* Ensured that manual "None" selections (empty string) are preserved across UI refreshes.
|
||||||
|
2. **Cross-Platform Feature Parity**:
|
||||||
|
* Aligned slot behavior with the Windows and Web ports.
|
||||||
|
3. **Stability**:
|
||||||
|
* Verified that nested slot defaults still load correctly for new cards.
|
||||||
|
|
||||||
|
### 🚀 Current Project Status
|
||||||
|
The Linux port now shares the same robust slot configuration logic as the Windows version, ensuring a consistent user experience.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 📅 Session: 2026-03-02 (Session 3)
|
## 📅 Session: 2026-03-02 (Session 3)
|
||||||
|
|
||||||
### 🎯 Objective: Upstream Version Tracking & Documentation Maintenance
|
### 🎯 Objective: Upstream Version Tracking & Documentation Maintenance
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ This is a port of the macOS native [Ample](https://github.com/ksherlock/ample) p
|
|||||||
* **Visual Precision**: Precision support for **Window 1x-4x** modes with machine-specific aspect ratio heuristics.
|
* **Visual Precision**: Precision support for **Window 1x-4x** modes with machine-specific aspect ratio heuristics.
|
||||||
* **Software Library**: Smart filtering, search overlay, and compatibility checking.
|
* **Software Library**: Smart filtering, search overlay, and compatibility checking.
|
||||||
* **Advanced Slot Emulation**: Full support for nested sub-slots (e.g. SCSI cards) with robust default device initialization and persistence for "None" selections.
|
* **Advanced Slot Emulation**: Full support for nested sub-slots (e.g. SCSI cards) with robust default device initialization and persistence for "None" selections.
|
||||||
* **ROM Management**: Real-time search, multi-server failover download, extended library.
|
* **ROM Management**: Real-time search, CallApple primary / MDK failover downloads, `dragon32` auto-patching, and full Laser 128 series library compatibility.
|
||||||
* **Compatibility Fallback**: Automatically detects affected Macintosh PowerBook models (`macpb160` etc.) that suffer from the MAME 0.288 EASC crash bug. Seamlessly switches to a local MAME 0.287 (`mame_0287`) or VGM Mod (`mame-vgm`) if available, or guides users to the MAME SDL Supported Platforms Wiki page to retrieve older packages.
|
* **Full Native Compatibility**: Upstream MAME 0.289 resolved the EASC audio chip crash bug on Macintosh PowerBook models (`macpb160`, `macpb180`, etc.), enabling seamless native launch across all PowerBook systems.
|
||||||
* **Shared Directory**: Full parity with `-share_directory` argument.
|
* **Shared Directory**: Full parity with `-share_directory` argument.
|
||||||
|
|
||||||
### 🐧 Linux-Specific Features
|
### 🐧 Linux-Specific Features
|
||||||
@@ -123,3 +123,6 @@ The app auto-detects GNOME and KDE dark/light themes. If your desktop environmen
|
|||||||
* Original macOS version developer: [Kelvin Sherlock](https://github.com/ksherlock)
|
* Original macOS version developer: [Kelvin Sherlock](https://github.com/ksherlock)
|
||||||
* **Windows Port Developers: anomixer + Antigravity**
|
* **Windows Port Developers: anomixer + Antigravity**
|
||||||
* **Linux Port**: Adapted from AmpleWin by anomixer + Antigravity
|
* **Linux Port**: Adapted from AmpleWin by anomixer + Antigravity
|
||||||
|
|
||||||
|
---
|
||||||
|
*Disclaimer: AmpleLinux is an independent open-source project and is not affiliated with, authorized, maintained, or endorsed by Apple Inc. or any other respective companies mentioned. All product and company names are trademarks™ or registered® trademarks of their respective holders.*
|
||||||
@@ -28,8 +28,8 @@
|
|||||||
* **視覺精準度**:精準支援 **Window 1x-4x** 模式,並內建機器專屬的比例啟發邏輯。
|
* **視覺精準度**:精準支援 **Window 1x-4x** 模式,並內建機器專屬的比例啟發邏輯。
|
||||||
* **軟體資料庫**:智慧過濾、搜尋遮罩、相容性檢查。
|
* **軟體資料庫**:智慧過濾、搜尋遮罩、相容性檢查。
|
||||||
* **進階槽位模擬**:完整支援嵌套子槽位(如 SCSI 卡),並具備穩健的設備初始化與「空」(None) 選項持久化邏輯。
|
* **進階槽位模擬**:完整支援嵌套子槽位(如 SCSI 卡),並具備穩健的設備初始化與「空」(None) 選項持久化邏輯。
|
||||||
* **ROM 管理**:即時搜尋、多伺服器 Failover 下載、擴展韌體庫。
|
* **ROM 管理**:即時搜尋、CallApple 優先/MDK 備用 Failover 下載、`dragon32` 自動補丁及 Laser 128 全系列韌體庫相容性。
|
||||||
* **相容性降級 (Compatibility Fallback)**:自動偵測受 MAME 0.288 EASC 晶片崩潰 Bug 影響的 PowerBook 機型(如 `macpb160` 等),自動切換至本地的 `mame_0287` 或 `mame-vgm`;若無備用執行檔,則會彈窗提供引導按鈕,協助使用者開啟官方 SDL Wiki 取得適用於該 Linux 發行版的舊版 MAME 執行檔。
|
* **全面相容性**:MAME 0.289 官方已修正 PowerBook 機型(如 `macpb160`, `macpb180` 等)的 EASC 晶片崩潰 Bug,所有 PowerBook 機型現可使用最新 MAME 核心直接原生啟動。
|
||||||
* **共享目錄**:與 Mac 版功能完全對齊 (`-share_directory`)。
|
* **共享目錄**:與 Mac 版功能完全對齊 (`-share_directory`)。
|
||||||
|
|
||||||
### 🐧 Linux 專屬功能
|
### 🐧 Linux 專屬功能
|
||||||
@@ -112,3 +112,6 @@ chmod +x build_elf.sh
|
|||||||
* 原始 macOS 版本開發者: [Kelvin Sherlock](https://github.com/ksherlock)
|
* 原始 macOS 版本開發者: [Kelvin Sherlock](https://github.com/ksherlock)
|
||||||
* **Windows Port 開發者: anomixer + Antigravity**
|
* **Windows Port 開發者: anomixer + Antigravity**
|
||||||
* **Linux Port**:由 anomixer + Antigravity 基於 AmpleWin 改編
|
* **Linux Port**:由 anomixer + Antigravity 基於 AmpleWin 改編
|
||||||
|
|
||||||
|
---
|
||||||
|
*免責聲明:AmpleLinux 是一個獨立的開源專案,與 Apple Inc. 或本專案提及之任何其他公司均無任何隸屬、授權、維護或背書關係。所有產品及公司名稱均為其各自持有人的商標™或註冊®商標。*
|
||||||
+34
-61
@@ -1228,6 +1228,16 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
# 不再於切換時立即填充軟體清單 (延遲加載以優化效能)
|
# 不再於切換時立即填充軟體清單 (延遲加載以優化效能)
|
||||||
if hasattr(self, 'sw_list'): self.sw_list.clear()
|
if hasattr(self, 'sw_list'): self.sw_list.clear()
|
||||||
|
|
||||||
|
def get_default_slots(self):
|
||||||
|
if not self.current_machine_data:
|
||||||
|
return {}
|
||||||
|
old_slots = self.current_slots
|
||||||
|
self.current_slots = {}
|
||||||
|
self.initialize_default_slots(self.current_machine_data)
|
||||||
|
defaults = self.current_slots
|
||||||
|
self.current_slots = old_slots
|
||||||
|
return defaults
|
||||||
|
|
||||||
def initialize_default_slots(self, data, depth=0):
|
def initialize_default_slots(self, data, depth=0):
|
||||||
if depth > 20: return
|
if depth > 20: return
|
||||||
|
|
||||||
@@ -1312,6 +1322,12 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
self.add_slot_row(self.slots_layout, ram_slot)
|
self.add_slot_row(self.slots_layout, ram_slot)
|
||||||
self.slots_layout.addSpacing(5)
|
self.slots_layout.addSpacing(5)
|
||||||
|
|
||||||
|
# 1.5 ROM Group
|
||||||
|
rom_slot = next((s for s in self.current_machine_data['slots'] if s['name'] in ('rom', 'romsize') or s.get('description') in ('ROM', 'ROM/RAM')), None)
|
||||||
|
if rom_slot:
|
||||||
|
self.add_slot_row(self.slots_layout, rom_slot)
|
||||||
|
self.slots_layout.addSpacing(5)
|
||||||
|
|
||||||
# 2. Disk Drives - EXACTLY same structure as add_slot_row
|
# 2. Disk Drives - EXACTLY same structure as add_slot_row
|
||||||
# Mac hides popup button but it still takes up space. Hamburger at far right.
|
# Mac hides popup button but it still takes up space. Hamburger at far right.
|
||||||
dd_slot = next((s for s in self.current_machine_data['slots'] if s.get('description') == 'Disk Drives'), None)
|
dd_slot = next((s for s in self.current_machine_data['slots'] if s.get('description') == 'Disk Drives'), None)
|
||||||
@@ -1350,19 +1366,12 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
|
|
||||||
self.slots_layout.addLayout(row)
|
self.slots_layout.addLayout(row)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 3. All other slots
|
# 3. All other slots
|
||||||
|
excluded_names = {'ramsize'}
|
||||||
|
if rom_slot:
|
||||||
|
excluded_names.add(rom_slot['name'])
|
||||||
for slot in self.current_machine_data['slots']:
|
for slot in self.current_machine_data['slots']:
|
||||||
if slot['name'] != 'ramsize' and slot.get('description') != 'Disk Drives':
|
if slot['name'] not in excluded_names and slot.get('description') != 'Disk Drives':
|
||||||
self.add_slot_row(self.slots_layout, slot)
|
self.add_slot_row(self.slots_layout, slot)
|
||||||
|
|
||||||
self.slots_layout.addStretch()
|
self.slots_layout.addStretch()
|
||||||
@@ -1879,8 +1888,20 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
# Positional arguments allow MAME's Software List manager to resolve them.
|
# Positional arguments allow MAME's Software List manager to resolve them.
|
||||||
soft_list_args.append(self.selected_software)
|
soft_list_args.append(self.selected_software)
|
||||||
|
|
||||||
|
# Get defaults recursively
|
||||||
|
defaults = self.get_default_slots()
|
||||||
|
|
||||||
|
# Filter slots: if a slot is set to empty "", only pass it to MAME if its default value was NOT empty
|
||||||
|
active_slots = {}
|
||||||
|
for slot_name, option in self.current_slots.items():
|
||||||
|
if option == "":
|
||||||
|
default_val = defaults.get(slot_name, "")
|
||||||
|
if default_val == "":
|
||||||
|
continue
|
||||||
|
active_slots[slot_name] = option
|
||||||
|
|
||||||
# Build base args
|
# Build base args
|
||||||
args = self.launcher.build_args(self.selected_machine, self.current_slots, filtered_media, soft_list_args)
|
args = self.launcher.build_args(self.selected_machine, active_slots, filtered_media, soft_list_args)
|
||||||
|
|
||||||
# Add UI Video options for preview
|
# Add UI Video options for preview
|
||||||
win_mode = self.win_mode.currentText()
|
win_mode = self.win_mode.currentText()
|
||||||
@@ -2145,40 +2166,6 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
cmd_str = self.cmd_preview.toPlainText().strip()
|
cmd_str = self.cmd_preview.toPlainText().strip()
|
||||||
if not cmd_str: return
|
if not cmd_str: return
|
||||||
|
|
||||||
# EASC PowerBook 0.288 Crash Fallback Check
|
|
||||||
affected_macs = ["macpb160", "macpb180", "macpb165", "macpb165c", "macpb180c"]
|
|
||||||
if self.selected_machine in affected_macs:
|
|
||||||
mame_bin_dir = os.path.dirname(self.launcher.mame_path)
|
|
||||||
alt_mac_exe = os.path.join(mame_bin_dir, "mame_0287")
|
|
||||||
vgm_mac_exe = os.path.join(mame_bin_dir, "mame-vgm")
|
|
||||||
|
|
||||||
# Check if any fallback is already present
|
|
||||||
has_fallback = os.path.exists(alt_mac_exe) or os.path.exists(vgm_mac_exe)
|
|
||||||
|
|
||||||
if not has_fallback:
|
|
||||||
msg_box = QMessageBox(self)
|
|
||||||
msg_box.setIcon(QMessageBox.Warning)
|
|
||||||
msg_box.setWindowTitle("EASC Audio Chip Bug (MAME v0.288)")
|
|
||||||
msg_box.setText(f"The machine '{self.selected_machine}' will crash on MAME v0.288 due to an upstream C++ type mismatch bug.")
|
|
||||||
msg_box.setInformativeText(
|
|
||||||
"To run this model, you can download a compatible older version of MAME (e.g. v0.287) and place the executable named 'mame_0287' inside your 'mame' folder,\n"
|
|
||||||
"or run a compatible sibling model instead (e.g. 'macpb170' or 'macpb140')."
|
|
||||||
)
|
|
||||||
|
|
||||||
dl_btn = msg_box.addButton("Download Fallback (v0.287)", QMessageBox.YesRole)
|
|
||||||
force_btn = msg_box.addButton("Force Launch (v0.288)", QMessageBox.NoRole)
|
|
||||||
cancel_btn = msg_box.addButton("Cancel", QMessageBox.RejectRole)
|
|
||||||
|
|
||||||
msg_box.exec()
|
|
||||||
|
|
||||||
if msg_box.clickedButton() == dl_btn:
|
|
||||||
_xdg_open("https://wiki.mamedev.org/index.php/SDL_Supported_Platforms")
|
|
||||||
return
|
|
||||||
elif msg_box.clickedButton() == force_btn:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
print(f"Launching custom command: {cmd_str}")
|
print(f"Launching custom command: {cmd_str}")
|
||||||
|
|
||||||
# Determine the MAME binary directory
|
# Determine the MAME binary directory
|
||||||
@@ -2204,21 +2191,7 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
target_exe_path = args[0]
|
target_exe_path = args[0]
|
||||||
|
|
||||||
if exe_cmd == "mame":
|
if exe_cmd == "mame":
|
||||||
affected_macs = ["macpb160", "macpb180", "macpb165", "macpb165c", "macpb180c"]
|
target_exe_path = self.launcher.mame_path
|
||||||
alt_mac_exe = os.path.join(mame_bin_dir, "mame_0287")
|
|
||||||
vgm_mac_exe = os.path.join(mame_bin_dir, "mame-vgm")
|
|
||||||
|
|
||||||
if self.selected_machine in affected_macs:
|
|
||||||
if os.path.exists(alt_mac_exe):
|
|
||||||
target_exe_path = alt_mac_exe
|
|
||||||
print(f"Applying compatibility fallback: using mame_0287 for {self.selected_machine}")
|
|
||||||
elif os.path.exists(vgm_mac_exe):
|
|
||||||
target_exe_path = vgm_mac_exe
|
|
||||||
print(f"Applying compatibility fallback: using mame-vgm for {self.selected_machine}")
|
|
||||||
else:
|
|
||||||
target_exe_path = self.launcher.mame_path
|
|
||||||
else:
|
|
||||||
target_exe_path = self.launcher.mame_path
|
|
||||||
elif exe_cmd == "mame-vgm":
|
elif exe_cmd == "mame-vgm":
|
||||||
path_vgm = os.path.join(mame_bin_dir, "mame-vgm")
|
path_vgm = os.path.join(mame_bin_dir, "mame-vgm")
|
||||||
if os.path.exists(path_vgm):
|
if os.path.exists(path_vgm):
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ class DownloadWorker(QRunnable):
|
|||||||
with open(self.dest_path, 'wb') as f:
|
with open(self.dest_path, 'wb') as f:
|
||||||
f.write(response.content)
|
f.write(response.content)
|
||||||
|
|
||||||
|
# Special patch for dragon32 to merge MDK split files if missing
|
||||||
|
if self.value == 'dragon32':
|
||||||
|
self.patch_dragon32()
|
||||||
|
|
||||||
self.signals.finished.emit(self.value, True)
|
self.signals.finished.emit(self.value, True)
|
||||||
return # Success!
|
return # Success!
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -53,14 +57,41 @@ class DownloadWorker(QRunnable):
|
|||||||
self.signals.status.emit(f"Error: {last_error}")
|
self.signals.status.emit(f"Error: {last_error}")
|
||||||
self.signals.finished.emit(self.value, False)
|
self.signals.finished.emit(self.value, False)
|
||||||
|
|
||||||
|
def patch_dragon32(self):
|
||||||
|
try:
|
||||||
|
mdk_url = "https://mdk.cab/download/split/dragon32.zip"
|
||||||
|
resp = requests.get(mdk_url, headers=self.headers, timeout=20)
|
||||||
|
if resp.status_code == 200 and len(resp.content) > 100:
|
||||||
|
import zipfile, io
|
||||||
|
existing_data = open(self.dest_path, 'rb').read()
|
||||||
|
z_existing = zipfile.ZipFile(io.BytesIO(existing_data))
|
||||||
|
z_mdk = zipfile.ZipFile(io.BytesIO(resp.content))
|
||||||
|
|
||||||
|
existing_names = set(z_existing.namelist())
|
||||||
|
mdk_names = set(z_mdk.namelist())
|
||||||
|
|
||||||
|
missing = mdk_names - existing_names
|
||||||
|
if missing:
|
||||||
|
out_buf = io.BytesIO()
|
||||||
|
with zipfile.ZipFile(out_buf, 'w', zipfile.ZIP_DEFLATED) as zout:
|
||||||
|
for item in z_existing.infolist():
|
||||||
|
zout.writestr(item, z_existing.read(item.filename))
|
||||||
|
for item in z_mdk.infolist():
|
||||||
|
if item.filename in missing:
|
||||||
|
zout.writestr(item, z_mdk.read(item.filename))
|
||||||
|
with open(self.dest_path, 'wb') as f:
|
||||||
|
f.write(out_buf.getvalue())
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Warning: dragon32 patch failed: {e}")
|
||||||
|
|
||||||
class RomManager(QObject):
|
class RomManager(QObject):
|
||||||
def __init__(self, resources_path, roms_dir):
|
def __init__(self, resources_path, roms_dir):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.resources_path = resources_path
|
self.resources_path = resources_path
|
||||||
self.roms_dir = roms_dir
|
self.roms_dir = roms_dir
|
||||||
self.base_urls = [
|
self.base_urls = [
|
||||||
"https://mdk.cab/download/split/",
|
"https://www.callapple.org/roms/",
|
||||||
"https://www.callapple.org/roms/"
|
"https://mdk.cab/download/split/"
|
||||||
]
|
]
|
||||||
self.rom_list = self.load_rom_list()
|
self.rom_list = self.load_rom_list()
|
||||||
|
|
||||||
@@ -78,7 +109,12 @@ class RomManager(QObject):
|
|||||||
{'value': 'prav8c', 'description': 'Pravetz 8C'},
|
{'value': 'prav8c', 'description': 'Pravetz 8C'},
|
||||||
{'value': 'prav82', 'description': 'Pravetz 82'},
|
{'value': 'prav82', 'description': 'Pravetz 82'},
|
||||||
{'value': 'prav8m', 'description': 'Pravetz 8M'},
|
{'value': 'prav8m', 'description': 'Pravetz 8M'},
|
||||||
{'value': 'prav8d', 'description': 'Pravetz 8D'}
|
{'value': 'prav8d', 'description': 'Pravetz 8D'},
|
||||||
|
{'value': 'las128ex', 'description': 'Laser 128EX'},
|
||||||
|
{'value': 'las128e2', 'description': 'Laser 128EX/2'},
|
||||||
|
{'value': 'laser128', 'description': 'Laser 128'},
|
||||||
|
{'value': 'laser128o', 'description': 'Laser 128 (Original)'},
|
||||||
|
{'value': 'laser2c', 'description': 'Laser 2c'}
|
||||||
]
|
]
|
||||||
existing_values = {r.get('value') for r in roms if 'value' in r}
|
existing_values = {r.get('value') for r in roms if 'value' in r}
|
||||||
for cr in custom_roms:
|
for cr in custom_roms:
|
||||||
|
|||||||
+55
-10
@@ -1,19 +1,44 @@
|
|||||||
# Agent Task Audit Log - Ample Windows Port
|
# Agent Task Audit Log - Ample Windows Port
|
||||||
|
|
||||||
|
## 📅 Session: 2026-08-02 (Session 17)
|
||||||
|
|
||||||
|
### 🎯 Objective: Upstream MAME v0.289 Synchronization
|
||||||
|
Synchronized AmpleWin with upstream `ksherlock/ample` v0.289 release, updated official MAME download binary URL, and updated machine `.plist` configuration definitions.
|
||||||
|
|
||||||
|
### ✅ Key Achievements:
|
||||||
|
1. **MAME 0.289 Downloader Upgrade**:
|
||||||
|
* Updated `mame_downloader.py` download target to official MAME v0.289 64-bit binary release (`mame0289b_x64.exe`).
|
||||||
|
2. **PowerBook Native Launch (EASC Bug Fixed)**:
|
||||||
|
* Removed `macpb160`, `macpb165`, `macpb165c`, `macpb180`, `macpb180c` fallback prompt mechanism in `main.py`, as MAME 0.289 officially resolved the EASC audio chip crash bug. All PowerBook models now launch directly using the main MAME 0.289 binary.
|
||||||
|
3. **ROM Manager Priority & Dragon32/Laser Series Fixes**:
|
||||||
|
* Reordered download servers in `rom_manager.py` to prioritize CallApple (`https://www.callapple.org/roms/`) with MDK (`https://mdk.cab/download/split/`) as backup failover.
|
||||||
|
* Integrated `patch_dragon32()` in `DownloadWorker` to auto-merge missing modern MAME 0.289 split ROM files (`dragon_data_ltd_1-0.ic18`, `dragon_data_ltd_1-1.ic17`) when downloading `dragon32.zip`.
|
||||||
|
* Expanded `custom_roms` fallback array to include Laser 128 series (`las128ex`, `las128e2`, `laser128`, `laser128o`, `laser2c`), ensuring seamless auto-download even if omitted from upstream `roms.plist`.
|
||||||
|
4. **Machine Profile & ROM Parity**:
|
||||||
|
* Verified `.plist` machine profile definitions (251 files) updated to MAME 0.289.
|
||||||
|
* Synchronized all updated `.plist` configurations across monorepo to `AmpleWeb/public/resources/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 📅 Session: 2026-06-05 (Session 16)
|
## 📅 Session: 2026-06-05 (Session 16)
|
||||||
|
|
||||||
### 🎯 Objective: PowerBook Compatibility Fallback & Downloader Acceleration
|
### 🎯 Objective: MAME v0.288 Upgrade, PowerBook Fallbacks & AmpleWeb Synchronization
|
||||||
Addressed upstream MAME 0.288 C++ late-binding bug causing crashes on EASC audio chip Macs, and accelerated the VGM Mod download.
|
Addressed upstream MAME 0.288 EASC crash bugs, compiled the v0.288-patched Wasm core, and synchronized all 0.288 machine plists and ROM mapping to AmpleWeb frontend.
|
||||||
|
|
||||||
### ✅ Key Achievements:
|
### ✅ Key Achievements:
|
||||||
1. **EASC Crash Fallback Mechanism**:
|
1. **MAME v0.288 Wasm Compile & Deploy**:
|
||||||
* Added automatic detection for affected PowerBook models (`macpb160`, `macpb180`, `macpb165`, `macpb165c`, `macpb180c`).
|
* Integrated memory export and EASC patch in `c:\dev\MameWasm` and compiled production Wasm core (`mameample.js` / `mameample.wasm`).
|
||||||
* Implements seamless redirect to `mame_0287.exe` or `mame-vgm.exe` (v0.280) if present in the executable folder.
|
* Compressed and deployed `mame.js` / `mame.wasm.gz` to both `AmpleWeb` and `ampleweb-ai`.
|
||||||
* Provides user warning with options to auto-download MAME v0.280 (VGM Mod) fallback, force launch under 0.288, or cancel.
|
2. **0.288 Machine Configuration Sync**:
|
||||||
2. **Downloader Optimization**:
|
* Copied 251 updated `.plist` machine profiles from Core to both web projects.
|
||||||
* Switched VGM Mod download mirror to prioritize `mirror.ghproxy.com` GitHub proxy for faster global asset retrieval.
|
* Expanded `DRIVER_ROM_MAP` in both `App.tsx` from 158 to 248 entries to fully support new 0.288 models (Amiga A1000/A2000/A500, Atari ST, Lisa, etc.).
|
||||||
3. **ROM Manager Priority Check**:
|
3. **EASC Crash Fallback (Core)**:
|
||||||
* Reordered ROM base URLs to prioritize `mdk.cab` over `callapple.org`. This guarantees the latest split set ROMs (like `dragon32` with split files) are downloaded correctly, solving the missing files crash on MAME 0.288+.
|
* Added automatic detection and v0.280/v0.287 fallback launcher mechanism for EASC audio chip Macs in AmpleWin/Linux.
|
||||||
|
4. **UI Slots Layout Ordering Parity (Core)**:
|
||||||
|
* Reordered rendering in `AmpleWin` and `AmpleLinux` slots panel. Now, ROM slots (`rom` or `romsize` or description `ROM`/`ROM/RAM`) are rendered directly after the RAM slot, positioning `Disk Drives` properly in the 3rd slot when ROM configuration exists.
|
||||||
|
5. **Downloader Optimization & SCSI Fix**:
|
||||||
|
* Prioritized `mdk.cab` split server in `rom_manager.py` and `rom_manager_cli.py` to prevent missing file errors on 0.288+.
|
||||||
|
* Verified SCSI CD-ROM 2x speed fallback `cdrom_2x` mappings on both frontends to resolve media mount bugs.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -43,6 +68,26 @@ Resolved an issue where slots with defaults could not be set to "None" because U
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 📅 Session: 2026-05-11 (Session 14)
|
||||||
|
|
||||||
|
### 🎯 Objective: Slot Configuration Parity & "None" Persistence
|
||||||
|
Resolved a long-standing issue where slots with default equipment could not be set to "None" because UI refreshes would force-revert them to defaults.
|
||||||
|
|
||||||
|
### ✅ Key Achievements:
|
||||||
|
1. **"None-Aware" Slot Initialization**:
|
||||||
|
* Modified `initialize_default_slots` in `main.py` to use key existence checks (`if slot_name not in self.current_slots`) instead of truthiness checks.
|
||||||
|
* This ensures that an empty string selection (`""` or "None") is respected as a deliberate user choice and not overwritten by defaults.
|
||||||
|
2. **Cross-Platform Alignment**:
|
||||||
|
* Coordinated this fix across **AmpleWin** and **AmpleLinux**.
|
||||||
|
* Verified that **AmpleWeb** already correctly handled this logic due to its Object-based option finding mechanism.
|
||||||
|
3. **Nested Slot Preservation**:
|
||||||
|
* Ensured that newly appeared sub-slots (e.g., when plugging in a SCSI or CFFA2 card) still automatically load their default devices, maintaining high usability.
|
||||||
|
|
||||||
|
### 🚀 Current Project Status
|
||||||
|
Slot configuration behavior is now fully consistent across Windows, Linux, and Web ports, accurately respecting "None" selections while preserving automated nested configurations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 📅 Session: 2026-03-02 (Session 13)
|
## 📅 Session: 2026-03-02 (Session 13)
|
||||||
|
|
||||||
### 🎯 Objective: Upstream Version Bump & Documentation Maintenance
|
### 🎯 Objective: Upstream Version Bump & Documentation Maintenance
|
||||||
|
|||||||
+5
-2
@@ -45,9 +45,9 @@ This is a precision port of the macOS native [Ample](https://github.com/ksherloc
|
|||||||
* **Slot Consistency**: Improved logic to respect "None" (empty) selections across UI refreshes, matching the high standards of the native macOS port.
|
* **Slot Consistency**: Improved logic to respect "None" (empty) selections across UI refreshes, matching the high standards of the native macOS port.
|
||||||
* **ROM Management**:
|
* **ROM Management**:
|
||||||
* **Search Filter**: Real-time searching in the ROM manager window to quickly find system firmwares.
|
* **Search Filter**: Real-time searching in the ROM manager window to quickly find system firmwares.
|
||||||
* **Download Failover**: Automatic multi-server acquisition (callapple + mdk.cab) with transparent failover for maximum stability.
|
* **Download Failover**: CallApple server primary acquisition with MDK failover support, featuring automated `dragon32` split ROM patching and full Laser 128 series firmware compatibility.
|
||||||
* **Extended Library**: Expanded support for PowerBook Duo 280, Pravetz 8C, TK3000, and more.
|
* **Extended Library**: Expanded support for PowerBook Duo 280, Pravetz 8C, TK3000, and more.
|
||||||
* **Compatibility Fallback**: Automatically detects affected Macintosh PowerBook models (`macpb160` etc.) that suffer from the MAME 0.288 EASC crash bug. Seamlessly switches to a local MAME 0.287 (`mame_0287.exe`) or VGM Mod (`mame-vgm.exe`), or offers to download the v0.280 fallback copy.
|
* **Full Native Compatibility**: Upstream MAME 0.289 resolved the EASC audio chip crash bug on Macintosh PowerBook models (`macpb160`, `macpb180`, etc.), enabling seamless native launch across all PowerBook systems.
|
||||||
* **Shared Directory**: Full parity with the Mac version, allowing direct host-to-emulator file sharing via the `-share_directory` argument. (Includes click-to-browse support).
|
* **Shared Directory**: Full parity with the Mac version, allowing direct host-to-emulator file sharing via the `-share_directory` argument. (Includes click-to-browse support).
|
||||||
* **VGM Support (Advanced)**: Since modern MAME removed VGM support, AmpleWin implements a robust background workflow to download and configure the **MAME-VGM Mod (v0.280)**. It uses a non-destructive extraction process (`mame-vgm.exe`) to preserve your main MAME core while restoring high-fidelity music recording.
|
* **VGM Support (Advanced)**: Since modern MAME removed VGM support, AmpleWin implements a robust background workflow to download and configure the **MAME-VGM Mod (v0.280)**. It uses a non-destructive extraction process (`mame-vgm.exe`) to preserve your main MAME core while restoring high-fidelity music recording.
|
||||||
|
|
||||||
@@ -106,3 +106,6 @@ If you want to create a standalone executable for distribution:
|
|||||||
|
|
||||||
* Original macOS version developer: [Kelvin Sherlock](https://github.com/ksherlock)
|
* Original macOS version developer: [Kelvin Sherlock](https://github.com/ksherlock)
|
||||||
* **Windows Port Developers: anomixer + Antigravity**: Dedicated to providing the ultimate Apple II / Macintosh emulation experience on Windows.
|
* **Windows Port Developers: anomixer + Antigravity**: Dedicated to providing the ultimate Apple II / Macintosh emulation experience on Windows.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Disclaimer: AmpleWin is an independent open-source project and is not affiliated with, authorized, maintained, or endorsed by Apple Inc. or any other respective companies mentioned. All product and company names are trademarks™ or registered® trademarks of their respective holders.*
|
||||||
@@ -45,9 +45,9 @@
|
|||||||
* **配置持久性**:優化插槽初始化邏輯,確保在 UI 重新整理時能正確保留「空」(None) 的選取狀態,與 Mac 原生行為一致。
|
* **配置持久性**:優化插槽初始化邏輯,確保在 UI 重新整理時能正確保留「空」(None) 的選取狀態,與 Mac 原生行為一致。
|
||||||
* **ROM 管理**:
|
* **ROM 管理**:
|
||||||
* **搜尋過濾**:ROM 管理器視窗中新增即時搜尋功能,方便快速查詢系統韌體。
|
* **搜尋過濾**:ROM 管理器視窗中新增即時搜尋功能,方便快速查詢系統韌體。
|
||||||
* **下載 Failover**:多伺服器自動獲取 (callapple + mdk.cab),主伺服器失敗時自動切換,確保最高穩定性。
|
* **下載 Failover**:CallApple 伺服器優先獲取,MDK 伺服器備用 failover 支援,並具備 `dragon32` 缺檔自動補丁與 Laser 128 全系列韌體相容性保障。
|
||||||
* **擴展支援**:新增 Macintosh PowerBook Duo 280, Pravetz 8C, TK3000 //e 等機型。
|
* **擴展支援**:新增 Macintosh PowerBook Duo 280, Pravetz 8C, TK3000 //e 等機型。
|
||||||
* **相容性降級 (Compatibility Fallback)**:自動偵測受 MAME 0.288 EASC 晶片崩潰 Bug 影響的 PowerBook 機型(如 `macpb160` 等),無縫切換至本地的 `mame_0287.exe` 或 `mame-vgm.exe` (v0.280),或提示一鍵下載備用版本,防範啟動崩潰。
|
* **全面相容性**:MAME 0.289 官方已修正 PowerBook 機型(如 `macpb160`, `macpb180` 等)的 EASC 晶片崩潰 Bug,所有 PowerBook 機型現可使用最新 MAME 核心直接原生啟動。
|
||||||
* **共享目錄 (Shared Directory)**:與 Mac 版功能完全對齊,支援透過 `-share_directory` 直接在主機與模擬器間共享檔案 (支援點擊輸入框瀏覽)。
|
* **共享目錄 (Shared Directory)**:與 Mac 版功能完全對齊,支援透過 `-share_directory` 直接在主機與模擬器間共享檔案 (支援點擊輸入框瀏覽)。
|
||||||
* **VGM 錄音支援 (進階)**:由於現代 MAME 已移除 VGM 支援,AmpleWin 實作了強韌的自動化工作流,可下載並平行配置 **MAME-VGM Mod (v0.280)**。透過非破壞性的解壓技術(保留原本的 `mame.exe` 並另存為 `mame-vgm.exe`),在不影響主核心的情況下完美還原錄音功能。
|
* **VGM 錄音支援 (進階)**:由於現代 MAME 已移除 VGM 支援,AmpleWin 實作了強韌的自動化工作流,可下載並平行配置 **MAME-VGM Mod (v0.280)**。透過非破壞性的解壓技術(保留原本的 `mame.exe` 並另存為 `mame-vgm.exe`),在不影響主核心的情況下完美還原錄音功能。
|
||||||
|
|
||||||
@@ -106,3 +106,6 @@
|
|||||||
|
|
||||||
* 原始 macOS 版本開發者: [Kelvin Sherlock](https://github.com/ksherlock)
|
* 原始 macOS 版本開發者: [Kelvin Sherlock](https://github.com/ksherlock)
|
||||||
* **Windows Port 開發者: anomixer + Antigravity**:致力於在 Windows 生態系中提供最極致的 Apple II / Macintosh 模擬體驗。
|
* **Windows Port 開發者: anomixer + Antigravity**:致力於在 Windows 生態系中提供最極致的 Apple II / Macintosh 模擬體驗。
|
||||||
|
|
||||||
|
---
|
||||||
|
*免責聲明:AmpleWin 是一個獨立的開源專案,與 Apple Inc. 或本專案提及之任何其他公司均無任何隸屬、授權、維護或背書關係。所有產品及公司名稱均為其各自持有人的商標™或註冊®商標。*
|
||||||
+34
-61
@@ -1121,6 +1121,16 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
# 不再於切換時立即填充軟體清單 (延遲加載以優化效能)
|
# 不再於切換時立即填充軟體清單 (延遲加載以優化效能)
|
||||||
if hasattr(self, 'sw_list'): self.sw_list.clear()
|
if hasattr(self, 'sw_list'): self.sw_list.clear()
|
||||||
|
|
||||||
|
def get_default_slots(self):
|
||||||
|
if not self.current_machine_data:
|
||||||
|
return {}
|
||||||
|
old_slots = self.current_slots
|
||||||
|
self.current_slots = {}
|
||||||
|
self.initialize_default_slots(self.current_machine_data)
|
||||||
|
defaults = self.current_slots
|
||||||
|
self.current_slots = old_slots
|
||||||
|
return defaults
|
||||||
|
|
||||||
def initialize_default_slots(self, data, depth=0):
|
def initialize_default_slots(self, data, depth=0):
|
||||||
if depth > 20: return
|
if depth > 20: return
|
||||||
|
|
||||||
@@ -1205,6 +1215,12 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
self.add_slot_row(self.slots_layout, ram_slot)
|
self.add_slot_row(self.slots_layout, ram_slot)
|
||||||
self.slots_layout.addSpacing(5)
|
self.slots_layout.addSpacing(5)
|
||||||
|
|
||||||
|
# 1.5 ROM Group
|
||||||
|
rom_slot = next((s for s in self.current_machine_data['slots'] if s['name'] in ('rom', 'romsize') or s.get('description') in ('ROM', 'ROM/RAM')), None)
|
||||||
|
if rom_slot:
|
||||||
|
self.add_slot_row(self.slots_layout, rom_slot)
|
||||||
|
self.slots_layout.addSpacing(5)
|
||||||
|
|
||||||
# 2. Disk Drives - EXACTLY same structure as add_slot_row
|
# 2. Disk Drives - EXACTLY same structure as add_slot_row
|
||||||
# Mac hides popup button but it still takes up space. Hamburger at far right.
|
# Mac hides popup button but it still takes up space. Hamburger at far right.
|
||||||
dd_slot = next((s for s in self.current_machine_data['slots'] if s.get('description') == 'Disk Drives'), None)
|
dd_slot = next((s for s in self.current_machine_data['slots'] if s.get('description') == 'Disk Drives'), None)
|
||||||
@@ -1243,19 +1259,12 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
|
|
||||||
self.slots_layout.addLayout(row)
|
self.slots_layout.addLayout(row)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 3. All other slots
|
# 3. All other slots
|
||||||
|
excluded_names = {'ramsize'}
|
||||||
|
if rom_slot:
|
||||||
|
excluded_names.add(rom_slot['name'])
|
||||||
for slot in self.current_machine_data['slots']:
|
for slot in self.current_machine_data['slots']:
|
||||||
if slot['name'] != 'ramsize' and slot.get('description') != 'Disk Drives':
|
if slot['name'] not in excluded_names and slot.get('description') != 'Disk Drives':
|
||||||
self.add_slot_row(self.slots_layout, slot)
|
self.add_slot_row(self.slots_layout, slot)
|
||||||
|
|
||||||
self.slots_layout.addStretch()
|
self.slots_layout.addStretch()
|
||||||
@@ -1772,8 +1781,20 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
# Positional arguments allow MAME's Software List manager to resolve them.
|
# Positional arguments allow MAME's Software List manager to resolve them.
|
||||||
soft_list_args.append(self.selected_software)
|
soft_list_args.append(self.selected_software)
|
||||||
|
|
||||||
|
# Get defaults recursively
|
||||||
|
defaults = self.get_default_slots()
|
||||||
|
|
||||||
|
# Filter slots: if a slot is set to empty "", only pass it to MAME if its default value was NOT empty
|
||||||
|
active_slots = {}
|
||||||
|
for slot_name, option in self.current_slots.items():
|
||||||
|
if option == "":
|
||||||
|
default_val = defaults.get(slot_name, "")
|
||||||
|
if default_val == "":
|
||||||
|
continue
|
||||||
|
active_slots[slot_name] = option
|
||||||
|
|
||||||
# Build base args
|
# Build base args
|
||||||
args = self.launcher.build_args(self.selected_machine, self.current_slots, filtered_media, soft_list_args)
|
args = self.launcher.build_args(self.selected_machine, active_slots, filtered_media, soft_list_args)
|
||||||
|
|
||||||
# Add UI Video options for preview
|
# Add UI Video options for preview
|
||||||
win_mode = self.win_mode.currentText()
|
win_mode = self.win_mode.currentText()
|
||||||
@@ -2029,40 +2050,6 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
cmd_str = self.cmd_preview.toPlainText().strip()
|
cmd_str = self.cmd_preview.toPlainText().strip()
|
||||||
if not cmd_str: return
|
if not cmd_str: return
|
||||||
|
|
||||||
# EASC PowerBook 0.288 Crash Fallback Check
|
|
||||||
affected_macs = ["macpb160", "macpb180", "macpb165", "macpb165c", "macpb180c"]
|
|
||||||
if self.selected_machine in affected_macs:
|
|
||||||
mame_bin_dir = os.path.dirname(self.launcher.mame_path)
|
|
||||||
alt_mac_exe = os.path.join(mame_bin_dir, "mame_0287.exe")
|
|
||||||
vgm_mac_exe = os.path.join(mame_bin_dir, "mame-vgm.exe")
|
|
||||||
|
|
||||||
# Check if any fallback is already present
|
|
||||||
has_fallback = os.path.exists(alt_mac_exe) or os.path.exists(vgm_mac_exe)
|
|
||||||
|
|
||||||
if not has_fallback:
|
|
||||||
msg_box = QMessageBox(self)
|
|
||||||
msg_box.setIcon(QMessageBox.Warning)
|
|
||||||
msg_box.setWindowTitle("EASC Audio Chip Bug (MAME v0.288)")
|
|
||||||
msg_box.setText(f"The machine '{self.selected_machine}' will crash on MAME v0.288 due to an upstream C++ type mismatch bug.")
|
|
||||||
msg_box.setInformativeText(
|
|
||||||
"To run this model, you can automatically download MAME v0.280 (VGM Mod) as a fallback, "
|
|
||||||
"or run a compatible sibling model instead (e.g. 'macpb170' or 'macpb140')."
|
|
||||||
)
|
|
||||||
|
|
||||||
dl_btn = msg_box.addButton("Download Fallback (v0.280)", QMessageBox.YesRole)
|
|
||||||
force_btn = msg_box.addButton("Force Launch (v0.288)", QMessageBox.NoRole)
|
|
||||||
cancel_btn = msg_box.addButton("Cancel", QMessageBox.RejectRole)
|
|
||||||
|
|
||||||
msg_box.exec()
|
|
||||||
|
|
||||||
if msg_box.clickedButton() == dl_btn:
|
|
||||||
self.download_vgm_mod(mame_bin_dir)
|
|
||||||
return
|
|
||||||
elif msg_box.clickedButton() == force_btn:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
print(f"Launching custom command: {cmd_str}")
|
print(f"Launching custom command: {cmd_str}")
|
||||||
|
|
||||||
# Determine the MAME binary directory
|
# Determine the MAME binary directory
|
||||||
@@ -2097,21 +2084,7 @@ class AmpleMainWindow(QMainWindow):
|
|||||||
target_exe_path = args[0]
|
target_exe_path = args[0]
|
||||||
|
|
||||||
if exe_cmd in ["mame", "mame.exe"]:
|
if exe_cmd in ["mame", "mame.exe"]:
|
||||||
affected_macs = ["macpb160", "macpb180", "macpb165", "macpb165c", "macpb180c"]
|
target_exe_path = self.launcher.mame_path
|
||||||
alt_mac_exe = os.path.join(mame_bin_dir, "mame_0287.exe")
|
|
||||||
vgm_mac_exe = os.path.join(mame_bin_dir, "mame-vgm.exe")
|
|
||||||
|
|
||||||
if self.selected_machine in affected_macs:
|
|
||||||
if os.path.exists(alt_mac_exe):
|
|
||||||
target_exe_path = alt_mac_exe
|
|
||||||
print(f"Applying compatibility fallback: using mame_0287.exe for {self.selected_machine}")
|
|
||||||
elif os.path.exists(vgm_mac_exe):
|
|
||||||
target_exe_path = vgm_mac_exe
|
|
||||||
print(f"Applying compatibility fallback: using mame-vgm.exe for {self.selected_machine}")
|
|
||||||
else:
|
|
||||||
target_exe_path = self.launcher.mame_path
|
|
||||||
else:
|
|
||||||
target_exe_path = self.launcher.mame_path
|
|
||||||
elif exe_cmd in ["mame-vgm", "mame-vgm.exe"]:
|
elif exe_cmd in ["mame-vgm", "mame-vgm.exe"]:
|
||||||
path_vgm = os.path.join(mame_bin_dir, "mame-vgm.exe")
|
path_vgm = os.path.join(mame_bin_dir, "mame-vgm.exe")
|
||||||
if os.path.exists(path_vgm):
|
if os.path.exists(path_vgm):
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ class MameDownloadWorker(QThread):
|
|||||||
def __init__(self, dest_dir):
|
def __init__(self, dest_dir):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.dest_dir = dest_dir
|
self.dest_dir = dest_dir
|
||||||
# MAME official self-extracting EXE - Updated to 0.288
|
# MAME official self-extracting EXE - Updated to 0.289
|
||||||
self.url = "https://github.com/mamedev/mame/releases/download/mame0288/mame0288b_x64.exe"
|
self.url = "https://github.com/mamedev/mame/releases/download/mame0289/mame0289b_x64.exe"
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
|
|||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "AmpleWin",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {}
|
||||||
|
}
|
||||||
+39
-3
@@ -40,6 +40,10 @@ class DownloadWorker(QRunnable):
|
|||||||
with open(self.dest_path, 'wb') as f:
|
with open(self.dest_path, 'wb') as f:
|
||||||
f.write(response.content)
|
f.write(response.content)
|
||||||
|
|
||||||
|
# Special patch for dragon32 to merge MDK split files if missing
|
||||||
|
if self.value == 'dragon32':
|
||||||
|
self.patch_dragon32()
|
||||||
|
|
||||||
self.signals.finished.emit(self.value, True)
|
self.signals.finished.emit(self.value, True)
|
||||||
return # Success!
|
return # Success!
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -53,14 +57,41 @@ class DownloadWorker(QRunnable):
|
|||||||
self.signals.status.emit(f"Error: {last_error}")
|
self.signals.status.emit(f"Error: {last_error}")
|
||||||
self.signals.finished.emit(self.value, False)
|
self.signals.finished.emit(self.value, False)
|
||||||
|
|
||||||
|
def patch_dragon32(self):
|
||||||
|
try:
|
||||||
|
mdk_url = "https://mdk.cab/download/split/dragon32.zip"
|
||||||
|
resp = requests.get(mdk_url, headers=self.headers, timeout=20)
|
||||||
|
if resp.status_code == 200 and len(resp.content) > 100:
|
||||||
|
import zipfile, io
|
||||||
|
existing_data = open(self.dest_path, 'rb').read()
|
||||||
|
z_existing = zipfile.ZipFile(io.BytesIO(existing_data))
|
||||||
|
z_mdk = zipfile.ZipFile(io.BytesIO(resp.content))
|
||||||
|
|
||||||
|
existing_names = set(z_existing.namelist())
|
||||||
|
mdk_names = set(z_mdk.namelist())
|
||||||
|
|
||||||
|
missing = mdk_names - existing_names
|
||||||
|
if missing:
|
||||||
|
out_buf = io.BytesIO()
|
||||||
|
with zipfile.ZipFile(out_buf, 'w', zipfile.ZIP_DEFLATED) as zout:
|
||||||
|
for item in z_existing.infolist():
|
||||||
|
zout.writestr(item, z_existing.read(item.filename))
|
||||||
|
for item in z_mdk.infolist():
|
||||||
|
if item.filename in missing:
|
||||||
|
zout.writestr(item, z_mdk.read(item.filename))
|
||||||
|
with open(self.dest_path, 'wb') as f:
|
||||||
|
f.write(out_buf.getvalue())
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Warning: dragon32 patch failed: {e}")
|
||||||
|
|
||||||
class RomManager(QObject):
|
class RomManager(QObject):
|
||||||
def __init__(self, resources_path, roms_dir):
|
def __init__(self, resources_path, roms_dir):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.resources_path = resources_path
|
self.resources_path = resources_path
|
||||||
self.roms_dir = roms_dir
|
self.roms_dir = roms_dir
|
||||||
self.base_urls = [
|
self.base_urls = [
|
||||||
"https://mdk.cab/download/split/",
|
"https://www.callapple.org/roms/",
|
||||||
"https://www.callapple.org/roms/"
|
"https://mdk.cab/download/split/"
|
||||||
]
|
]
|
||||||
self.rom_list = self.load_rom_list()
|
self.rom_list = self.load_rom_list()
|
||||||
|
|
||||||
@@ -78,7 +109,12 @@ class RomManager(QObject):
|
|||||||
{'value': 'prav8c', 'description': 'Pravetz 8C'},
|
{'value': 'prav8c', 'description': 'Pravetz 8C'},
|
||||||
{'value': 'prav82', 'description': 'Pravetz 82'},
|
{'value': 'prav82', 'description': 'Pravetz 82'},
|
||||||
{'value': 'prav8m', 'description': 'Pravetz 8M'},
|
{'value': 'prav8m', 'description': 'Pravetz 8M'},
|
||||||
{'value': 'prav8d', 'description': 'Pravetz 8D'}
|
{'value': 'prav8d', 'description': 'Pravetz 8D'},
|
||||||
|
{'value': 'las128ex', 'description': 'Laser 128EX'},
|
||||||
|
{'value': 'las128e2', 'description': 'Laser 128EX/2'},
|
||||||
|
{'value': 'laser128', 'description': 'Laser 128'},
|
||||||
|
{'value': 'laser128o', 'description': 'Laser 128 (Original)'},
|
||||||
|
{'value': 'laser2c', 'description': 'Laser 2c'}
|
||||||
]
|
]
|
||||||
existing_values = {r.get('value') for r in roms if 'value' in r}
|
existing_values = {r.get('value') for r in roms if 'value' in r}
|
||||||
for cr in custom_roms:
|
for cr in custom_roms:
|
||||||
|
|||||||
@@ -171,6 +171,9 @@ SLOTS = (
|
|||||||
|
|
||||||
# lisa
|
# lisa
|
||||||
"pp",
|
"pp",
|
||||||
|
|
||||||
|
# sgi
|
||||||
|
"gio64_gfx",
|
||||||
)
|
)
|
||||||
|
|
||||||
SLOT_NAMES = {
|
SLOT_NAMES = {
|
||||||
@@ -289,6 +292,9 @@ SLOT_NAMES = {
|
|||||||
# lisa
|
# lisa
|
||||||
"pp": "Parallel",
|
"pp": "Parallel",
|
||||||
|
|
||||||
|
# sgi
|
||||||
|
"gio64_gfx": "GIO64 Graphics",
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
+1
-1
@@ -116,6 +116,7 @@ TREE = [
|
|||||||
("Macintosh (LC)", None, mac_lc_children),
|
("Macintosh (LC)", None, mac_lc_children),
|
||||||
("Macintosh (Portable)", None, mac_portable_children),
|
("Macintosh (Portable)", None, mac_portable_children),
|
||||||
("Macintosh (PowerBook)", None, mac_powerbook_children),
|
("Macintosh (PowerBook)", None, mac_powerbook_children),
|
||||||
|
("Lisa", None, lisa_children),
|
||||||
|
|
||||||
("Acorn", None, acorn_children),
|
("Acorn", None, acorn_children),
|
||||||
("Atari ST", "st", atari_st_children),
|
("Atari ST", "st", atari_st_children),
|
||||||
@@ -125,7 +126,6 @@ TREE = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
TREE_EXTRA = TREE + [
|
TREE_EXTRA = TREE + [
|
||||||
("Lisa", None, lisa_children),
|
|
||||||
|
|
||||||
("Amiga", None, amiga_children),
|
("Amiga", None, amiga_children),
|
||||||
("DEC VT", None, dec_vt_children),
|
("DEC VT", None, dec_vt_children),
|
||||||
|
|||||||
Reference in new issue
Block a user