mirror of https://github.com/AxioDL/amuse.git
Work on AudioUnit data UI
This commit is contained in:
parent
81bd897ec1
commit
9ae92313e3
|
@ -17,6 +17,7 @@
|
|||
<connections>
|
||||
<outlet property="creditsView" destination="AWS-Zd-8ha" id="O75-15-wzr"/>
|
||||
<outlet property="dataOutline" destination="Vlv-Jw-A4U" id="Ggn-DC-cUY"/>
|
||||
<outlet property="dataSearchField" destination="Huk-pR-ayq" id="MbL-0b-KGw"/>
|
||||
<outlet property="mainWindow" destination="FDh-Mc-OFY" id="CQQ-Dm-Kv3"/>
|
||||
<outlet property="samplesTable" destination="Frt-wZ-1ZI" id="riC-O4-JXo"/>
|
||||
<outlet property="sfxTable" destination="4nw-rf-Dh4" id="ebY-ro-tqk"/>
|
||||
|
@ -69,7 +70,7 @@
|
|||
<items>
|
||||
<menuItem title="Import…" keyEquivalent="i" id="IAo-SY-fd9">
|
||||
<connections>
|
||||
<action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/>
|
||||
<action selector="importFile:" target="Y3H-Qy-a7C" id="j6G-7T-YiQ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
|
@ -149,7 +150,7 @@
|
|||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="283" y="305" width="544" height="367"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1366" height="745"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<view key="contentView" id="9Rk-3e-xVS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="544" height="367"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
|
@ -166,121 +167,75 @@
|
|||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Alc-jx-Z3v">
|
||||
<rect key="frame" x="0.0" y="-1" width="30" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="30" id="QjK-Fn-bKW"/>
|
||||
<constraint firstAttribute="width" constant="30" id="kSj-a9-U8v"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="1BM-r8-8er">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="importFile:" target="Y3H-Qy-a7C" id="bBJ-EO-41Y"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="eh8-gl-WoS">
|
||||
<rect key="frame" x="29" y="-1" width="31" height="31"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="31" id="HLy-Rb-n4I"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="edx-l4-aHD">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mpK-AK-Otf">
|
||||
<rect key="frame" x="59" y="-1" width="485" height="32"/>
|
||||
<rect key="frame" x="58" y="-1" width="486" height="32"/>
|
||||
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" refusesFirstResponder="YES" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="JwG-gw-HOj">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XHK-NM-ZAP">
|
||||
<scrollView autohidesScrollers="YES" horizontalLineScroll="22" horizontalPageScroll="10" verticalLineScroll="22" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XHK-NM-ZAP">
|
||||
<rect key="frame" x="0.0" y="28" width="544" height="339"/>
|
||||
<clipView key="contentView" id="cFf-wa-ZPx">
|
||||
<clipView key="contentView" drawsBackground="NO" id="cFf-wa-ZPx">
|
||||
<rect key="frame" x="1" y="0.0" width="542" height="338"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="jN4-UQ-VfT" viewBased="YES" indentationPerLevel="16" outlineTableColumn="DlG-iE-h1a" id="Vlv-Jw-A4U" customClass="DataOutlineView">
|
||||
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" alternatingRowBackgroundColors="YES" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="22" headerView="jN4-UQ-VfT" indentationPerLevel="14" outlineTableColumn="DlG-iE-h1a" id="Vlv-Jw-A4U" customClass="DataOutlineView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="542" height="315"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<size key="intercellSpacing" width="3" height="0.0"/>
|
||||
<color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="116" minWidth="40" maxWidth="1000" id="DlG-iE-h1a">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<tableColumn identifier="CollectionColumn" width="193" minWidth="100" maxWidth="1000" id="DlG-iE-h1a">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Collection">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="nfQ-a8-ezY">
|
||||
<buttonCell key="dataCell" type="check" title="CollectionTitle" bezelStyle="regularSquare" imagePosition="left" alignment="left" lineBreakMode="truncatingTail" inset="2" id="Lpp-wh-qX7">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</buttonCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="1eD-qr-jb9">
|
||||
<rect key="frame" x="1" y="1" width="116" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="cAp-67-fuc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="100" height="17"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="n5E-QL-7SS">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="cAp-67-fuc" firstAttribute="centerY" secondItem="1eD-qr-jb9" secondAttribute="centerY" id="5cE-qL-mGq"/>
|
||||
<constraint firstItem="cAp-67-fuc" firstAttribute="leading" secondItem="1eD-qr-jb9" secondAttribute="leading" constant="2" id="WPE-2V-xp9"/>
|
||||
<constraint firstAttribute="trailing" secondItem="cAp-67-fuc" secondAttribute="trailing" constant="18" id="tKa-Es-CKH"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="textField" destination="cAp-67-fuc" id="oYq-0I-143"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
<tableColumn width="420" minWidth="40" maxWidth="1000" id="alh-ut-BoX">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<tableColumn identifier="DetailsColumn" width="343" minWidth="40" maxWidth="1000" id="alh-ut-BoX">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Details">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="ywm-jc-RPk">
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" allowsUndo="NO" title="Text Cell" id="ywm-jc-RPk">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="textColor" name="disabledControlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView misplaced="YES" id="REu-Qt-X84">
|
||||
<rect key="frame" x="120" y="1" width="420" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="zPc-LM-WxA">
|
||||
<rect key="frame" x="0.0" y="0.0" width="100" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="96" id="hKb-R5-AZg"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="wy9-p6-MVa">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="zPc-LM-WxA" firstAttribute="centerY" secondItem="REu-Qt-X84" secondAttribute="centerY" id="HWb-8H-JTZ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="zPc-LM-WxA" secondAttribute="trailing" constant="-58" id="pfE-FE-k76"/>
|
||||
<constraint firstItem="zPc-LM-WxA" firstAttribute="leading" secondItem="REu-Qt-X84" secondAttribute="leading" constant="2" id="qPe-rp-KwI"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="textField" destination="zPc-LM-WxA" id="XMS-Lt-7aA"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
</outlineView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<nil key="backgroundColor"/>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="ZGl-Ws-7HQ">
|
||||
<rect key="frame" x="1" y="19" width="158" height="15"/>
|
||||
|
@ -298,7 +253,7 @@
|
|||
<searchField wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Huk-pR-ayq">
|
||||
<rect key="frame" x="65" y="4" width="474" height="22"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="22" id="bta-rr-Rjn"/>
|
||||
<constraint firstAttribute="height" constant="22" id="uJy-eO-Y8o"/>
|
||||
</constraints>
|
||||
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" usesSingleLineMode="YES" bezelStyle="round" id="u9E-Ld-d6I">
|
||||
<font key="font" metaFont="system"/>
|
||||
|
@ -308,24 +263,23 @@
|
|||
</searchField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="top" secondItem="GKx-9K-n29" secondAttribute="top" id="11d-cK-KTn"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Huk-pR-ayq" secondAttribute="trailing" constant="5" id="1Bp-rN-FgN"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Huk-pR-ayq" secondAttribute="bottom" constant="4" id="3Px-xo-dAv"/>
|
||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="trailing" secondItem="mpK-AK-Otf" secondAttribute="trailing" id="5i2-xa-qrD"/>
|
||||
<constraint firstItem="Alc-jx-Z3v" firstAttribute="baseline" secondItem="eh8-gl-WoS" secondAttribute="baseline" id="8uY-Ir-nmM"/>
|
||||
<constraint firstAttribute="trailing" secondItem="XHK-NM-ZAP" secondAttribute="trailing" id="9gd-HE-7uf"/>
|
||||
<constraint firstItem="Huk-pR-ayq" firstAttribute="leading" secondItem="eh8-gl-WoS" secondAttribute="trailing" constant="5" id="Aav-lf-aM8"/>
|
||||
<constraint firstItem="eh8-gl-WoS" firstAttribute="baseline" secondItem="mpK-AK-Otf" secondAttribute="baseline" id="Inf-xH-Xiu"/>
|
||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="leading" secondItem="Alc-jx-Z3v" secondAttribute="leading" id="Qwp-2y-pUU"/>
|
||||
<constraint firstItem="Huk-pR-ayq" firstAttribute="top" secondItem="XHK-NM-ZAP" secondAttribute="bottom" constant="2" id="S29-sA-pR1"/>
|
||||
<constraint firstItem="mpK-AK-Otf" firstAttribute="centerY" secondItem="Huk-pR-ayq" secondAttribute="centerY" id="Y1b-wA-j5b"/>
|
||||
<constraint firstItem="Alc-jx-Z3v" firstAttribute="centerY" secondItem="eh8-gl-WoS" secondAttribute="centerY" id="YXF-DS-Qzu"/>
|
||||
<constraint firstItem="mpK-AK-Otf" firstAttribute="leading" secondItem="Alc-jx-Z3v" secondAttribute="trailing" constant="29" id="bF7-N0-Fff"/>
|
||||
<constraint firstItem="eh8-gl-WoS" firstAttribute="leading" secondItem="GKx-9K-n29" secondAttribute="leading" constant="29" id="flM-s6-dSI"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Alc-jx-Z3v" secondAttribute="bottom" id="iKi-2E-TFe"/>
|
||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="leading" secondItem="GKx-9K-n29" secondAttribute="leading" id="lRg-3u-LsT"/>
|
||||
<constraint firstItem="Alc-jx-Z3v" firstAttribute="firstBaseline" secondItem="mpK-AK-Otf" secondAttribute="firstBaseline" id="pp9-Zc-noQ"/>
|
||||
<constraint firstItem="Huk-pR-ayq" firstAttribute="centerX" secondItem="mpK-AK-Otf" secondAttribute="centerX" id="xqj-LS-MnT"/>
|
||||
<constraint firstItem="Alc-jx-Z3v" firstAttribute="centerY" secondItem="eh8-gl-WoS" secondAttribute="centerY" id="0mR-AS-Iw9"/>
|
||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="top" secondItem="GKx-9K-n29" secondAttribute="top" id="2Gv-Q0-8sj"/>
|
||||
<constraint firstItem="eh8-gl-WoS" firstAttribute="leading" secondItem="GKx-9K-n29" secondAttribute="leading" constant="29" id="5Hp-Mp-Huw"/>
|
||||
<constraint firstItem="mpK-AK-Otf" firstAttribute="centerY" secondItem="Huk-pR-ayq" secondAttribute="centerY" id="92l-eR-8e5"/>
|
||||
<constraint firstItem="eh8-gl-WoS" firstAttribute="baseline" secondItem="mpK-AK-Otf" secondAttribute="baseline" id="EDq-BU-boS"/>
|
||||
<constraint firstAttribute="trailing" secondItem="XHK-NM-ZAP" secondAttribute="trailing" id="H11-09-cl1"/>
|
||||
<constraint firstItem="Huk-pR-ayq" firstAttribute="leading" secondItem="eh8-gl-WoS" secondAttribute="trailing" constant="5" id="KCn-oT-fwW"/>
|
||||
<constraint firstItem="mpK-AK-Otf" firstAttribute="leading" secondItem="Alc-jx-Z3v" secondAttribute="trailing" constant="28" id="Qse-Ec-Pqp"/>
|
||||
<constraint firstItem="Alc-jx-Z3v" firstAttribute="firstBaseline" secondItem="mpK-AK-Otf" secondAttribute="firstBaseline" id="Trd-67-sID"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Alc-jx-Z3v" secondAttribute="bottom" id="UD1-C6-vXP"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Huk-pR-ayq" secondAttribute="trailing" constant="5" id="jeG-bJ-zDw"/>
|
||||
<constraint firstItem="Alc-jx-Z3v" firstAttribute="baseline" secondItem="eh8-gl-WoS" secondAttribute="baseline" id="jo2-gd-6U0"/>
|
||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="leading" secondItem="GKx-9K-n29" secondAttribute="leading" id="lHj-7d-9KY"/>
|
||||
<constraint firstItem="Huk-pR-ayq" firstAttribute="top" secondItem="XHK-NM-ZAP" secondAttribute="bottom" constant="2" id="lbt-SK-129"/>
|
||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="trailing" secondItem="mpK-AK-Otf" secondAttribute="trailing" id="q3f-gS-tLA"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Huk-pR-ayq" secondAttribute="bottom" constant="4" id="rW0-CH-0JZ"/>
|
||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="leading" secondItem="Alc-jx-Z3v" secondAttribute="leading" id="wUx-3P-eJu"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
|
@ -715,10 +669,10 @@
|
|||
</tabView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="Kht-FW-Kf6" firstAttribute="leading" secondItem="9Rk-3e-xVS" secondAttribute="leading" id="EaK-L0-wht"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Kht-FW-Kf6" secondAttribute="trailing" id="JMc-UC-ORE"/>
|
||||
<constraint firstItem="Kht-FW-Kf6" firstAttribute="top" secondItem="9Rk-3e-xVS" secondAttribute="top" id="joC-pf-f1v"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Kht-FW-Kf6" secondAttribute="bottom" id="yTz-NI-FWd"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Kht-FW-Kf6" secondAttribute="trailing" id="QKQ-cu-CcX"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Kht-FW-Kf6" secondAttribute="bottom" id="aJq-Lv-Drp"/>
|
||||
<constraint firstItem="Kht-FW-Kf6" firstAttribute="top" secondItem="9Rk-3e-xVS" secondAttribute="top" id="cHb-PJ-LRW"/>
|
||||
<constraint firstItem="Kht-FW-Kf6" firstAttribute="leading" secondItem="9Rk-3e-xVS" secondAttribute="leading" id="qWs-qF-70Y"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<toolbar key="toolbar" implicitIdentifier="B4A5636B-DFED-420B-B2FF-540D729FD569" autosavesConfiguration="NO" allowsUserCustomization="NO" displayMode="iconAndLabel" sizeMode="regular" id="r4I-P0-82j">
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#import <CoreAudioKit/AUViewController.h>
|
||||
#import "AudioUnitViewController.hpp"
|
||||
#import "AudioGroupFilePresenter.hpp"
|
||||
#include <amuse/amuse.hpp>
|
||||
|
||||
@class DataOutlineController;
|
||||
@class SamplesTableController;
|
||||
|
@ -37,16 +38,17 @@
|
|||
{
|
||||
IBOutlet NSWindow* mainWindow;
|
||||
IBOutlet NSOutlineView* dataOutline;
|
||||
IBOutlet NSSearchField* dataSearchField;
|
||||
IBOutlet NSTableView* sfxTable;
|
||||
IBOutlet NSTableView* samplesTable;
|
||||
IBOutlet NSTextView* creditsView;
|
||||
|
||||
AudioGroupFilePresenter* groupFilePresenter;
|
||||
|
||||
DataOutlineController* dataController;
|
||||
SamplesTableController* samplesController;
|
||||
SFXTableController* sfxController;
|
||||
}
|
||||
- (BOOL)importURL:(NSURL*)url;
|
||||
@end
|
||||
|
||||
@interface MainTabView : NSTabView
|
||||
|
@ -98,17 +100,6 @@
|
|||
|
||||
@end
|
||||
|
||||
@interface DataOutlineController : NSObject <NSOutlineViewDataSource, NSOutlineViewDelegate>
|
||||
{
|
||||
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation DataOutlineController
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@interface SamplesTableController : NSObject <NSTableViewDataSource, NSTableViewDelegate>
|
||||
{
|
||||
|
@ -158,9 +149,8 @@
|
|||
|
||||
groupFilePresenter = [AudioGroupFilePresenter new];
|
||||
|
||||
dataController = [DataOutlineController new];
|
||||
dataOutline.dataSource = dataController;
|
||||
dataOutline.delegate = dataController;
|
||||
dataOutline.dataSource = groupFilePresenter;
|
||||
dataOutline.delegate = groupFilePresenter;
|
||||
[dataOutline reloadItem:nil reloadChildren:YES];
|
||||
|
||||
samplesController = [SamplesTableController new];
|
||||
|
@ -179,9 +169,34 @@
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (IBAction)quitApp:(id)sender
|
||||
- (BOOL)importURL:(NSURL*)url
|
||||
{
|
||||
[NSApp terminate:sender];
|
||||
amuse::ContainerRegistry::Type containerType;
|
||||
std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>> data =
|
||||
amuse::ContainerRegistry::LoadContainer(url.path.UTF8String, containerType);
|
||||
if (data.empty())
|
||||
{
|
||||
NSString* err = [NSString stringWithFormat:@"Unable to load Audio Groups from %s", url.path.UTF8String];
|
||||
NSAlert* alert = [[NSAlert alloc] init];
|
||||
alert.informativeText = err;
|
||||
alert.messageText = @"Invalid Data File";
|
||||
[alert runModal];
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name(amuse::ContainerRegistry::TypeToName(containerType));
|
||||
return [groupFilePresenter addCollectionName:std::move(name) items:std::move(data)];
|
||||
}
|
||||
|
||||
- (IBAction)importFile:(id)sender
|
||||
{
|
||||
__block NSOpenPanel* panel = [NSOpenPanel openPanel];
|
||||
[panel beginSheetModalForWindow:mainWindow completionHandler:^(NSInteger result) {
|
||||
if (result == NSFileHandlingPanelOKButton)
|
||||
{
|
||||
[self importURL:panel.URL];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -5,20 +5,44 @@
|
|||
#import <AppKit/AppKit.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "optional.hpp"
|
||||
#include <amuse/amuse.hpp>
|
||||
#include <athena/FileReader.hpp>
|
||||
|
||||
@class AudioGroupFilePresenter;
|
||||
@class AudioGroupDataToken;
|
||||
@class AudioGroupCollectionToken;
|
||||
|
||||
struct AudioGroupDataCollection
|
||||
{
|
||||
std::string m_name;
|
||||
NSURL* m_proj;
|
||||
NSURL* m_pool;
|
||||
NSURL* m_sdir;
|
||||
NSURL* m_samp;
|
||||
NSURL* m_meta;
|
||||
|
||||
AudioGroupDataToken* m_token;
|
||||
|
||||
std::unique_ptr<uint8_t[]> m_projData;
|
||||
std::unique_ptr<uint8_t[]> m_poolData;
|
||||
std::unique_ptr<uint8_t[]> m_sdirData;
|
||||
std::unique_ptr<uint8_t[]> m_sampData;
|
||||
std::vector<uint8_t> m_projData;
|
||||
std::vector<uint8_t> m_poolData;
|
||||
std::vector<uint8_t> m_sdirData;
|
||||
std::vector<uint8_t> m_sampData;
|
||||
|
||||
struct MetaData
|
||||
{
|
||||
amuse::DataFormat fmt;
|
||||
uint32_t absOffs;
|
||||
uint32_t active;
|
||||
MetaData(amuse::DataFormat fmtIn, uint32_t absOffsIn, uint32_t activeIn)
|
||||
: fmt(fmtIn), absOffs(absOffsIn), active(activeIn) {}
|
||||
MetaData(athena::io::FileReader& r)
|
||||
: fmt(amuse::DataFormat(r.readUint32Big())), absOffs(r.readUint32Big()), active(r.readUint32Big()) {}
|
||||
};
|
||||
std::experimental::optional<MetaData> m_metaData;
|
||||
|
||||
std::experimental::optional<amuse::AudioGroupData> m_loadedData;
|
||||
std::experimental::optional<amuse::AudioGroupProject> m_loadedProj;
|
||||
|
||||
void moveURL(NSURL* oldUrl, NSURL* newUrl);
|
||||
|
||||
|
@ -26,24 +50,82 @@ struct AudioGroupDataCollection
|
|||
bool loadPool(AudioGroupFilePresenter* presenter);
|
||||
bool loadSdir(AudioGroupFilePresenter* presenter);
|
||||
bool loadSamp(AudioGroupFilePresenter* presenter);
|
||||
bool loadMeta(AudioGroupFilePresenter* presenter);
|
||||
|
||||
AudioGroupDataCollection(NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp)
|
||||
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp) {}
|
||||
bool isDataComplete () const {return m_projData && m_poolData && m_sdirData && m_sampData;}
|
||||
AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp, NSURL* meta);
|
||||
bool isDataComplete() const {return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;}
|
||||
bool _attemptLoad(AudioGroupFilePresenter* presenter);
|
||||
};
|
||||
|
||||
@interface AudioGroupFilePresenter : NSObject <NSFilePresenter, NSOutlineViewDataSource>
|
||||
template <class T>
|
||||
class IteratorTracker
|
||||
{
|
||||
typename std::map<std::string, T>::const_iterator m_audioGroupOutlineBegin;
|
||||
typename std::map<std::string, T>::const_iterator m_audioGroupOutlineEnd;
|
||||
typename std::map<std::string, T>::const_iterator m_audioGroupOutlineIt;
|
||||
size_t m_audioGroupOutlineIdx = 0;
|
||||
|
||||
public:
|
||||
IteratorTracker(typename std::map<std::string, T>::const_iterator begin,
|
||||
typename std::map<std::string, T>::const_iterator end)
|
||||
: m_audioGroupOutlineBegin(begin), m_audioGroupOutlineEnd(end), m_audioGroupOutlineIt(begin) {}
|
||||
typename std::map<std::string, T>::const_iterator seekToIndex(size_t idx)
|
||||
{
|
||||
if (idx == m_audioGroupOutlineIdx)
|
||||
return m_audioGroupOutlineIt;
|
||||
if (idx < m_audioGroupOutlineIdx)
|
||||
{
|
||||
for (; idx < m_audioGroupOutlineIdx && m_audioGroupOutlineIt != m_audioGroupOutlineBegin ;
|
||||
--m_audioGroupOutlineIdx, --m_audioGroupOutlineIt) {}
|
||||
return m_audioGroupOutlineIt;
|
||||
}
|
||||
for (; idx > m_audioGroupOutlineIdx && m_audioGroupOutlineIt != m_audioGroupOutlineEnd ;
|
||||
++m_audioGroupOutlineIdx, ++m_audioGroupOutlineIt) {}
|
||||
return m_audioGroupOutlineIt;
|
||||
}
|
||||
};
|
||||
|
||||
struct AudioGroupCollection
|
||||
{
|
||||
NSURL* m_url;
|
||||
|
||||
AudioGroupCollectionToken* m_token;
|
||||
std::map<std::string, AudioGroupDataCollection> m_groups;
|
||||
std::experimental::optional<IteratorTracker<AudioGroupDataCollection>> m_iteratorTracker;
|
||||
|
||||
AudioGroupCollection(NSURL* url);
|
||||
void addCollection(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||
void update(AudioGroupFilePresenter* presenter);
|
||||
};
|
||||
|
||||
@interface AudioGroupDataToken : NSObject
|
||||
{
|
||||
@public
|
||||
AudioGroupDataCollection* m_collection;
|
||||
}
|
||||
- (id)initWithDataCollection:(AudioGroupDataCollection*)collection;
|
||||
@end
|
||||
|
||||
@interface AudioGroupCollectionToken : NSObject
|
||||
{
|
||||
@public
|
||||
AudioGroupCollection* m_collection;
|
||||
}
|
||||
- (id)initWithCollection:(AudioGroupCollection*)collection;
|
||||
@end
|
||||
|
||||
@interface AudioGroupFilePresenter : NSObject <NSFilePresenter, NSOutlineViewDataSource, NSOutlineViewDelegate>
|
||||
{
|
||||
NSURL* m_groupURL;
|
||||
NSOperationQueue* m_dataQueue;
|
||||
std::map<std::string, AudioGroupDataCollection> m_audioGroupCollections;
|
||||
std::map<std::string, AudioGroupCollection> m_audioGroupCollections;
|
||||
NSOutlineView* lastOutlineView;
|
||||
|
||||
std::map<std::string, AudioGroupDataCollection>::const_iterator m_audioGroupOutlineIt;
|
||||
size_t m_audioGroupOutlineIdx;
|
||||
std::experimental::optional<IteratorTracker<AudioGroupCollection>> m_iteratorTracker;
|
||||
}
|
||||
|
||||
- (BOOL)addCollectionName:(std::string&&)name items:(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&&)collection;
|
||||
- (void)update;
|
||||
|
||||
- (void)resetIterators;
|
||||
@end
|
||||
|
||||
#endif // __AMUSE_AUDIOUNIT_AUDIOGROUPFILEPRESENTER_HPP__
|
||||
|
|
|
@ -1,7 +1,30 @@
|
|||
#include "AudioGroupFilePresenter.hpp"
|
||||
#include <athena/FileReader.hpp>
|
||||
#include <amuse/AudioGroupProject.hpp>
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@implementation AudioGroupDataToken
|
||||
|
||||
- (id)initWithDataCollection:(AudioGroupDataCollection *)collection
|
||||
{
|
||||
self = [super init];
|
||||
m_collection = collection;
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation AudioGroupCollectionToken
|
||||
|
||||
- (id)initWithCollection:(AudioGroupCollection *)collection
|
||||
{
|
||||
self = [super init];
|
||||
m_collection = collection;
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation AudioGroupFilePresenter
|
||||
|
||||
- (NSURL*)presentedItemURL
|
||||
|
@ -14,6 +37,138 @@
|
|||
return m_dataQueue;
|
||||
}
|
||||
|
||||
AudioGroupCollection::AudioGroupCollection(NSURL* url)
|
||||
: m_url(url), m_token([[AudioGroupCollectionToken alloc] initWithCollection:this]) {}
|
||||
|
||||
void AudioGroupCollection::addCollection(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection)
|
||||
{
|
||||
for (std::pair<std::string, amuse::IntrusiveAudioGroupData>& pair : collection)
|
||||
{
|
||||
NSURL* collectionUrl = [m_url URLByAppendingPathComponent:@(pair.first.c_str())];
|
||||
|
||||
amuse::IntrusiveAudioGroupData& dataIn = pair.second;
|
||||
auto search = m_groups.find(pair.first);
|
||||
if (search == m_groups.end())
|
||||
{
|
||||
search = m_groups.emplace(pair.first,
|
||||
AudioGroupDataCollection{pair.first,
|
||||
[collectionUrl URLByAppendingPathComponent:@"proj"],
|
||||
[collectionUrl URLByAppendingPathComponent:@"pool"],
|
||||
[collectionUrl URLByAppendingPathComponent:@"sdir"],
|
||||
[collectionUrl URLByAppendingPathComponent:@"samp"],
|
||||
[collectionUrl URLByAppendingPathComponent:@"meta"]}).first;
|
||||
}
|
||||
|
||||
AudioGroupDataCollection& dataCollection = search->second;
|
||||
dataCollection.m_projData.resize(dataIn.getProjSize());
|
||||
memmove(dataCollection.m_projData.data(), dataIn.getProj(), dataIn.getProjSize());
|
||||
|
||||
dataCollection.m_poolData.resize(dataIn.getPoolSize());
|
||||
memmove(dataCollection.m_poolData.data(), dataIn.getPool(), dataIn.getPoolSize());
|
||||
|
||||
dataCollection.m_sdirData.resize(dataIn.getSdirSize());
|
||||
memmove(dataCollection.m_sdirData.data(), dataIn.getSdir(), dataIn.getSdirSize());
|
||||
|
||||
dataCollection.m_sampData.resize(dataIn.getSampSize());
|
||||
memmove(dataCollection.m_sampData.data(), dataIn.getSamp(), dataIn.getSampSize());
|
||||
|
||||
dataCollection.m_metaData.emplace(dataIn.getDataFormat(), dataIn.getAbsoluteProjOffsets(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioGroupCollection::update(AudioGroupFilePresenter* presenter)
|
||||
{
|
||||
NSFileManager* fman = [NSFileManager defaultManager];
|
||||
NSArray<NSURL*>* contents =
|
||||
[fman contentsOfDirectoryAtURL:m_url
|
||||
includingPropertiesForKeys:@[NSURLIsDirectoryKey]
|
||||
options:NSDirectoryEnumerationSkipsSubdirectoryDescendants |
|
||||
NSDirectoryEnumerationSkipsHiddenFiles
|
||||
error:nil];
|
||||
if (!contents)
|
||||
return;
|
||||
|
||||
for (NSURL* path in contents)
|
||||
{
|
||||
NSNumber* isDir;
|
||||
[path getResourceValue:&isDir forKey:NSURLIsDirectoryKey error:nil];
|
||||
|
||||
if (isDir.boolValue)
|
||||
{
|
||||
auto search = m_groups.find(path.lastPathComponent.UTF8String);
|
||||
if (search == m_groups.end())
|
||||
{
|
||||
std::string nameStr = path.lastPathComponent.UTF8String;
|
||||
search =
|
||||
m_groups.emplace(nameStr,
|
||||
AudioGroupDataCollection{nameStr,
|
||||
[path URLByAppendingPathComponent:@"proj"],
|
||||
[path URLByAppendingPathComponent:@"pool"],
|
||||
[path URLByAppendingPathComponent:@"sdir"],
|
||||
[path URLByAppendingPathComponent:@"samp"],
|
||||
[path URLByAppendingPathComponent:@"meta"]}).first;
|
||||
search->second._attemptLoad(presenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AudioGroupDataCollection::AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool,
|
||||
NSURL* sdir, NSURL* samp, NSURL* meta)
|
||||
: m_name(name), m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_meta(meta),
|
||||
m_token([[AudioGroupDataToken alloc] initWithDataCollection:this]) {}
|
||||
|
||||
bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter* presenter)
|
||||
{
|
||||
if (!isDataComplete())
|
||||
return false;
|
||||
if (m_metaData && m_loadedProj)
|
||||
return true;
|
||||
if (!loadProj(presenter))
|
||||
return false;
|
||||
if (!loadPool(presenter))
|
||||
return false;
|
||||
if (!loadSdir(presenter))
|
||||
return false;
|
||||
if (!loadSamp(presenter))
|
||||
return false;
|
||||
if (!loadMeta(presenter))
|
||||
return false;
|
||||
|
||||
switch (m_metaData->fmt)
|
||||
{
|
||||
case amuse::DataFormat::GCN:
|
||||
default:
|
||||
m_loadedData.emplace(m_projData.data(), m_projData.size(),
|
||||
m_poolData.data(), m_poolData.size(),
|
||||
m_sdirData.data(), m_sdirData.size(),
|
||||
m_sampData.data(), m_sampData.size(),
|
||||
amuse::GCNDataTag{});
|
||||
break;
|
||||
case amuse::DataFormat::N64:
|
||||
m_loadedData.emplace(m_projData.data(), m_projData.size(),
|
||||
m_poolData.data(), m_poolData.size(),
|
||||
m_sdirData.data(), m_sdirData.size(),
|
||||
m_sampData.data(), m_sampData.size(),
|
||||
m_metaData->absOffs, amuse::N64DataTag{});
|
||||
break;
|
||||
case amuse::DataFormat::PC:
|
||||
m_loadedData.emplace(m_projData.data(), m_projData.size(),
|
||||
m_poolData.data(), m_poolData.size(),
|
||||
m_sdirData.data(), m_sdirData.size(),
|
||||
m_sampData.data(), m_sampData.size(),
|
||||
m_metaData->absOffs, amuse::PCDataTag{});
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_metaData && m_loadedProj)
|
||||
{
|
||||
m_loadedProj.emplace(amuse::AudioGroupProject::CreateAudioGroupProject(*m_loadedData));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudioGroupDataCollection::moveURL(NSURL* oldUrl, NSURL* newUrl)
|
||||
{
|
||||
if (m_proj)
|
||||
|
@ -46,7 +201,7 @@ bool AudioGroupDataCollection::loadProj(AudioGroupFilePresenter* presenter)
|
|||
if (!coord)
|
||||
return false;
|
||||
NSError* err;
|
||||
__block std::unique_ptr<uint8_t[]>& ret = m_projData;
|
||||
__block std::vector<uint8_t>& ret = m_projData;
|
||||
[coord coordinateReadingItemAtURL:m_proj
|
||||
options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err
|
||||
byAccessor:^(NSURL* newUrl)
|
||||
|
@ -54,9 +209,11 @@ bool AudioGroupDataCollection::loadProj(AudioGroupFilePresenter* presenter)
|
|||
athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false);
|
||||
if (r.hasError())
|
||||
return;
|
||||
ret = r.readUBytes(r.length());
|
||||
size_t len = r.length();
|
||||
ret.resize(len);
|
||||
r.readUBytesToBuf(ret.data(), len);
|
||||
}];
|
||||
return m_projData.operator bool();
|
||||
return ret.size();
|
||||
}
|
||||
|
||||
bool AudioGroupDataCollection::loadPool(AudioGroupFilePresenter* presenter)
|
||||
|
@ -67,7 +224,7 @@ bool AudioGroupDataCollection::loadPool(AudioGroupFilePresenter* presenter)
|
|||
if (!coord)
|
||||
return false;
|
||||
NSError* err;
|
||||
__block std::unique_ptr<uint8_t[]>& ret = m_poolData;
|
||||
__block std::vector<uint8_t>& ret = m_poolData;
|
||||
[coord coordinateReadingItemAtURL:m_pool
|
||||
options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err
|
||||
byAccessor:^(NSURL* newUrl)
|
||||
|
@ -75,9 +232,11 @@ bool AudioGroupDataCollection::loadPool(AudioGroupFilePresenter* presenter)
|
|||
athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false);
|
||||
if (r.hasError())
|
||||
return;
|
||||
ret = r.readUBytes(r.length());
|
||||
size_t len = r.length();
|
||||
ret.resize(len);
|
||||
r.readUBytesToBuf(ret.data(), len);
|
||||
}];
|
||||
return m_poolData.operator bool();
|
||||
return ret.size();
|
||||
}
|
||||
|
||||
bool AudioGroupDataCollection::loadSdir(AudioGroupFilePresenter* presenter)
|
||||
|
@ -88,7 +247,7 @@ bool AudioGroupDataCollection::loadSdir(AudioGroupFilePresenter* presenter)
|
|||
if (!coord)
|
||||
return false;
|
||||
NSError* err;
|
||||
__block std::unique_ptr<uint8_t[]>& ret = m_sdirData;
|
||||
__block std::vector<uint8_t>& ret = m_sdirData;
|
||||
[coord coordinateReadingItemAtURL:m_sdir
|
||||
options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err
|
||||
byAccessor:^(NSURL* newUrl)
|
||||
|
@ -96,9 +255,11 @@ bool AudioGroupDataCollection::loadSdir(AudioGroupFilePresenter* presenter)
|
|||
athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false);
|
||||
if (r.hasError())
|
||||
return;
|
||||
ret = r.readUBytes(r.length());
|
||||
size_t len = r.length();
|
||||
ret.resize(len);
|
||||
r.readUBytesToBuf(ret.data(), len);
|
||||
}];
|
||||
return m_sdirData.operator bool();
|
||||
return ret.size();
|
||||
}
|
||||
|
||||
bool AudioGroupDataCollection::loadSamp(AudioGroupFilePresenter* presenter)
|
||||
|
@ -109,7 +270,7 @@ bool AudioGroupDataCollection::loadSamp(AudioGroupFilePresenter* presenter)
|
|||
if (!coord)
|
||||
return false;
|
||||
NSError* err;
|
||||
__block std::unique_ptr<uint8_t[]>& ret = m_sampData;
|
||||
__block std::vector<uint8_t>& ret = m_sampData;
|
||||
[coord coordinateReadingItemAtURL:m_samp
|
||||
options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err
|
||||
byAccessor:^(NSURL* newUrl)
|
||||
|
@ -117,63 +278,189 @@ bool AudioGroupDataCollection::loadSamp(AudioGroupFilePresenter* presenter)
|
|||
athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false);
|
||||
if (r.hasError())
|
||||
return;
|
||||
ret = r.readUBytes(r.length());
|
||||
size_t len = r.length();
|
||||
ret.resize(len);
|
||||
r.readUBytesToBuf(ret.data(), len);
|
||||
}];
|
||||
return m_sampData.operator bool();
|
||||
return ret.size();
|
||||
}
|
||||
|
||||
bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
||||
{
|
||||
if (!m_meta)
|
||||
return false;
|
||||
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter];
|
||||
if (!coord)
|
||||
return false;
|
||||
NSError* err;
|
||||
__block std::experimental::optional<MetaData>& ret = m_metaData;
|
||||
[coord coordinateReadingItemAtURL:m_meta
|
||||
options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err
|
||||
byAccessor:^(NSURL* newUrl)
|
||||
{
|
||||
athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false);
|
||||
if (r.hasError())
|
||||
return;
|
||||
ret.emplace(r);
|
||||
}];
|
||||
return ret.operator bool();
|
||||
}
|
||||
|
||||
- (void)presentedSubitemDidAppearAtURL:(NSURL*)url
|
||||
{
|
||||
NSURL* dir = nil;
|
||||
if ([url.lastPathComponent isEqualToString:@"proj"] ||
|
||||
[url.lastPathComponent isEqualToString:@"pool"] ||
|
||||
[url.lastPathComponent isEqualToString:@"sdir"] ||
|
||||
[url.lastPathComponent isEqualToString:@"samp"])
|
||||
dir = url.baseURL;
|
||||
|
||||
auto search = m_audioGroupCollections.find(dir.lastPathComponent.UTF8String);
|
||||
if (search == m_audioGroupCollections.end())
|
||||
{
|
||||
search =
|
||||
m_audioGroupCollections.emplace(dir.lastPathComponent.UTF8String,
|
||||
AudioGroupDataCollection{
|
||||
[dir URLByAppendingPathComponent:@"proj"],
|
||||
[dir URLByAppendingPathComponent:@"pool"],
|
||||
[dir URLByAppendingPathComponent:@"sdir"],
|
||||
[dir URLByAppendingPathComponent:@"samp"]}).first;
|
||||
}
|
||||
[self update];
|
||||
}
|
||||
|
||||
- (void)presentedSubitemAtURL:(NSURL*)oldUrl didMoveToURL:(NSURL*)newUrl
|
||||
{
|
||||
for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ; ++it)
|
||||
for (auto& pair : m_audioGroupCollections)
|
||||
{
|
||||
std::pair<const std::string, AudioGroupDataCollection>& pair = *it;
|
||||
pair.second.moveURL(oldUrl, newUrl);
|
||||
for (auto& pair2 : pair.second.m_groups)
|
||||
{
|
||||
pair2.second.moveURL(oldUrl, newUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(nullable id)item
|
||||
{
|
||||
lastOutlineView = outlineView;
|
||||
if (!item)
|
||||
return m_audioGroupCollections.size();
|
||||
return 0;
|
||||
|
||||
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||
return collection.m_groups.size();
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(nullable id)item
|
||||
{
|
||||
if (!item)
|
||||
{
|
||||
|
||||
auto search = m_iteratorTracker->seekToIndex(index);
|
||||
if (search == m_audioGroupCollections.end())
|
||||
return nil;
|
||||
return search->second.m_token;
|
||||
}
|
||||
return nil;
|
||||
|
||||
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||
auto search = collection.m_iteratorTracker->seekToIndex(index);
|
||||
if (search == collection.m_groups.end())
|
||||
return nil;
|
||||
return search->second.m_token;
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item
|
||||
{
|
||||
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
|
||||
{
|
||||
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||
{
|
||||
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
||||
return [NSNumber numberWithBool:true];
|
||||
else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"])
|
||||
return [NSString stringWithFormat:@"%" PRISize " groups", collection.m_groups.size()];
|
||||
}
|
||||
else if ([item isKindOfClass:[AudioGroupDataToken class]])
|
||||
{
|
||||
AudioGroupDataCollection& data = *((AudioGroupDataToken*)item)->m_collection;
|
||||
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
||||
return [NSNumber numberWithBool:data.m_metaData->active];
|
||||
else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"])
|
||||
{
|
||||
if (!data.m_loadedProj)
|
||||
return @"";
|
||||
return [NSString stringWithFormat:@"%zu SongGroups, %zu SFXGroups",
|
||||
data.m_loadedProj->songGroups().size(), data.m_loadedProj->sfxGroups().size()];
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(nonnull id)cell forTableColumn:(nullable NSTableColumn *)tableColumn item:(nonnull id)item
|
||||
{
|
||||
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||
{
|
||||
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
||||
((NSButtonCell*)cell).title = collection.m_url.lastPathComponent;
|
||||
}
|
||||
else if ([item isKindOfClass:[AudioGroupDataToken class]])
|
||||
{
|
||||
AudioGroupDataCollection& data = *((AudioGroupDataToken*)item)->m_collection;
|
||||
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
||||
((NSButtonCell*)cell).title = @(data.m_name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)addCollectionName:(std::string&&)name items:(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&&)collection
|
||||
{
|
||||
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:self];
|
||||
if (!coord)
|
||||
return false;
|
||||
|
||||
NSURL* dir = [m_groupURL URLByAppendingPathComponent:@(name.c_str())];
|
||||
__block AudioGroupCollection& insert = m_audioGroupCollections.emplace(name, dir).first->second;
|
||||
insert.addCollection(std::move(collection));
|
||||
|
||||
[coord coordinateWritingItemAtURL:m_groupURL options:0 error:nil
|
||||
byAccessor:^(NSURL* newUrl)
|
||||
{
|
||||
for (std::pair<const std::string, AudioGroupDataCollection>& pair : insert.m_groups)
|
||||
{
|
||||
NSURL* collectionUrl = [insert.m_url URLByAppendingPathComponent:@(pair.first.c_str())];
|
||||
[[NSFileManager defaultManager] createDirectoryAtURL:collectionUrl withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
|
||||
FILE* fp = fopen(pair.second.m_proj.path.UTF8String, "wb");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(pair.second.m_projData.data(), 1, pair.second.m_projData.size(), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
fp = fopen(pair.second.m_pool.path.UTF8String, "wb");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(pair.second.m_poolData.data(), 1, pair.second.m_poolData.size(), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
fp = fopen(pair.second.m_sdir.path.UTF8String, "wb");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(pair.second.m_sdirData.data(), 1, pair.second.m_sdirData.size(), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
fp = fopen(pair.second.m_samp.path.UTF8String, "wb");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(pair.second.m_sampData.data(), 1, pair.second.m_sampData.size(), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
fp = fopen(pair.second.m_meta.path.UTF8String, "wb");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(&*pair.second.m_metaData, 1, sizeof(*pair.second.m_metaData), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)update
|
||||
{
|
||||
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:self];
|
||||
|
@ -181,41 +468,47 @@ bool AudioGroupDataCollection::loadSamp(AudioGroupFilePresenter* presenter)
|
|||
return;
|
||||
NSError* coordErr;
|
||||
__block NSError* managerErr;
|
||||
__block std::map<std::string, AudioGroupDataCollection>& theMap = m_audioGroupCollections;
|
||||
__block std::map<std::string, AudioGroupCollection>& theMap = m_audioGroupCollections;
|
||||
__block AudioGroupFilePresenter* presenter = self;
|
||||
[coord coordinateReadingItemAtURL:m_groupURL options:NSFileCoordinatorReadingResolvesSymbolicLink error:&coordErr
|
||||
byAccessor:^(NSURL* newUrl)
|
||||
{
|
||||
NSFileManager* fman = [NSFileManager defaultManager];
|
||||
NSArray<NSURL*>* contents =
|
||||
[fman contentsOfDirectoryAtURL:newUrl
|
||||
includingPropertiesForKeys:@[NSURLIsDirectoryKey]
|
||||
options:NSDirectoryEnumerationSkipsSubdirectoryDescendants |
|
||||
NSDirectoryEnumerationSkipsHiddenFiles
|
||||
error:&managerErr];
|
||||
if (!contents)
|
||||
return;
|
||||
{
|
||||
NSFileManager* fman = [NSFileManager defaultManager];
|
||||
NSArray<NSURL*>* contents =
|
||||
[fman contentsOfDirectoryAtURL:newUrl
|
||||
includingPropertiesForKeys:@[NSURLIsDirectoryKey]
|
||||
options:NSDirectoryEnumerationSkipsSubdirectoryDescendants |
|
||||
NSDirectoryEnumerationSkipsHiddenFiles
|
||||
error:&managerErr];
|
||||
if (!contents)
|
||||
return;
|
||||
|
||||
for (NSURL* path in contents)
|
||||
{
|
||||
NSNumber* isDir;
|
||||
[path getResourceValue:&isDir forKey:NSURLIsDirectoryKey error:nil];
|
||||
|
||||
if (isDir.boolValue)
|
||||
{
|
||||
auto search = theMap.find(path.lastPathComponent.UTF8String);
|
||||
if (search == theMap.end())
|
||||
{
|
||||
search =
|
||||
theMap.emplace(path.lastPathComponent.UTF8String,
|
||||
AudioGroupDataCollection{
|
||||
[path URLByAppendingPathComponent:@"proj"],
|
||||
[path URLByAppendingPathComponent:@"pool"],
|
||||
[path URLByAppendingPathComponent:@"sdir"],
|
||||
[path URLByAppendingPathComponent:@"samp"]}).first;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
for (NSURL* path in contents)
|
||||
{
|
||||
NSNumber* isDir;
|
||||
[path getResourceValue:&isDir forKey:NSURLIsDirectoryKey error:nil];
|
||||
|
||||
if (isDir.boolValue)
|
||||
{
|
||||
auto search = theMap.find(path.lastPathComponent.UTF8String);
|
||||
if (search == theMap.end())
|
||||
{
|
||||
search = theMap.emplace(path.lastPathComponent.UTF8String, path).first;
|
||||
search->second.update(presenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
[self resetIterators];
|
||||
}
|
||||
|
||||
- (void)resetIterators
|
||||
{
|
||||
m_iteratorTracker.emplace(m_audioGroupCollections.begin(), m_audioGroupCollections.end());
|
||||
for (auto& pair : m_audioGroupCollections)
|
||||
pair.second.m_iteratorTracker.emplace(pair.second.m_groups.begin(), pair.second.m_groups.end());
|
||||
[lastOutlineView reloadItem:nil reloadChildren:YES];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
|
|
|
@ -57,7 +57,7 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE
|
|||
AmuseContainingApp.mm AudioGroupFilePresenter.mm
|
||||
PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||
target_link_libraries(amuse-au-container amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
|
||||
${AVFOUNDATION_LIBRARY} ${BOO_SYS_LIBS} logvisor athena-core)
|
||||
${AVFOUNDATION_LIBRARY} ${ZLIB_LIBRARIES} ${BOO_SYS_LIBS} logvisor athena-core)
|
||||
|
||||
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainer.entitlements.in
|
||||
|
|
|
@ -12,35 +12,70 @@ class AudioGroupData
|
|||
friend class Engine;
|
||||
protected:
|
||||
unsigned char* m_proj;
|
||||
size_t m_projSz;
|
||||
unsigned char* m_pool;
|
||||
size_t m_poolSz;
|
||||
unsigned char* m_sdir;
|
||||
size_t m_sdirSz;
|
||||
unsigned char* m_samp;
|
||||
size_t m_sampSz;
|
||||
|
||||
DataFormat m_fmt;
|
||||
bool m_absOffs;
|
||||
|
||||
AudioGroupData(unsigned char* proj, unsigned char* pool,
|
||||
unsigned char* sdir, unsigned char* samp,
|
||||
AudioGroupData(unsigned char* proj, size_t projSz,
|
||||
unsigned char* pool, size_t poolSz,
|
||||
unsigned char* sdir, size_t sdirSz,
|
||||
unsigned char* samp, size_t sampSz,
|
||||
DataFormat fmt, bool absOffs)
|
||||
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp),
|
||||
: m_proj(proj), m_projSz(projSz),
|
||||
m_pool(pool), m_poolSz(poolSz),
|
||||
m_sdir(sdir), m_sdirSz(sdirSz),
|
||||
m_samp(samp), m_sampSz(sampSz),
|
||||
m_fmt(fmt), m_absOffs(absOffs) {}
|
||||
public:
|
||||
AudioGroupData(unsigned char* proj, unsigned char* pool,
|
||||
unsigned char* sdir, unsigned char* samp, GCNDataTag)
|
||||
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp),
|
||||
AudioGroupData(unsigned char* proj, size_t projSz,
|
||||
unsigned char* pool, size_t poolSz,
|
||||
unsigned char* sdir, size_t sdirSz,
|
||||
unsigned char* samp, size_t sampSz, GCNDataTag)
|
||||
: m_proj(proj), m_projSz(projSz),
|
||||
m_pool(pool), m_poolSz(poolSz),
|
||||
m_sdir(sdir), m_sdirSz(sdirSz),
|
||||
m_samp(samp), m_sampSz(sampSz),
|
||||
m_fmt(DataFormat::GCN), m_absOffs(true) {}
|
||||
AudioGroupData(unsigned char* proj, unsigned char* pool,
|
||||
unsigned char* sdir, unsigned char* samp, bool absOffs, N64DataTag)
|
||||
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp),
|
||||
AudioGroupData(unsigned char* proj, size_t projSz,
|
||||
unsigned char* pool, size_t poolSz,
|
||||
unsigned char* sdir, size_t sdirSz,
|
||||
unsigned char* samp, size_t sampSz, bool absOffs, N64DataTag)
|
||||
: m_proj(proj), m_projSz(projSz),
|
||||
m_pool(pool), m_poolSz(poolSz),
|
||||
m_sdir(sdir), m_sdirSz(sdirSz),
|
||||
m_samp(samp), m_sampSz(sampSz),
|
||||
m_fmt(DataFormat::N64), m_absOffs(absOffs) {}
|
||||
AudioGroupData(unsigned char* proj, unsigned char* pool,
|
||||
unsigned char* sdir, unsigned char* samp, bool absOffs, PCDataTag)
|
||||
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp),
|
||||
AudioGroupData(unsigned char* proj, size_t projSz,
|
||||
unsigned char* pool, size_t poolSz,
|
||||
unsigned char* sdir, size_t sdirSz,
|
||||
unsigned char* samp, size_t sampSz, bool absOffs, PCDataTag)
|
||||
: m_proj(proj), m_projSz(projSz),
|
||||
m_pool(pool), m_poolSz(poolSz),
|
||||
m_sdir(sdir), m_sdirSz(sdirSz),
|
||||
m_samp(samp), m_sampSz(sampSz),
|
||||
m_fmt(DataFormat::PC), m_absOffs(absOffs) {}
|
||||
|
||||
const unsigned char* getProj() const {return m_proj;}
|
||||
const unsigned char* getPool() const {return m_pool;}
|
||||
const unsigned char* getSdir() const {return m_sdir;}
|
||||
const unsigned char* getSamp() const {return m_samp;}
|
||||
|
||||
unsigned char* getProj() {return m_proj;}
|
||||
unsigned char* getPool() {return m_pool;}
|
||||
unsigned char* getSdir() {return m_sdir;}
|
||||
unsigned char* getSamp() {return m_samp;}
|
||||
|
||||
size_t getProjSize() const {return m_projSz;}
|
||||
size_t getPoolSize() const {return m_poolSz;}
|
||||
size_t getSdirSize() const {return m_sdirSz;}
|
||||
size_t getSampSize() const {return m_sampSz;}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
|
@ -64,6 +99,8 @@ public:
|
|||
|
||||
IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other);
|
||||
IntrusiveAudioGroupData& operator=(IntrusiveAudioGroupData&& other);
|
||||
|
||||
void dangleOwnership() {m_owns = false;}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
static const char* TypeToName(Type tp);
|
||||
static Type DetectContainerType(const char* path);
|
||||
static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadContainer(const char* path);
|
||||
static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadContainer(const char* path, Type& typeOut);
|
||||
static std::vector<std::pair<std::string, SongData>> LoadSongs(const char* path);
|
||||
};
|
||||
|
||||
|
|
|
@ -15,7 +15,9 @@ IntrusiveAudioGroupData::~IntrusiveAudioGroupData()
|
|||
}
|
||||
|
||||
IntrusiveAudioGroupData::IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other)
|
||||
: AudioGroupData(other.m_proj, other.m_pool, other.m_sdir, other.m_samp, other.m_fmt, other.m_absOffs)
|
||||
: AudioGroupData(other.m_proj, other.m_projSz, other.m_pool, other.m_poolSz,
|
||||
other.m_sdir, other.m_sdirSz, other.m_samp, other.m_sampSz,
|
||||
other.m_fmt, other.m_absOffs)
|
||||
{
|
||||
m_owns = other.m_owns;
|
||||
other.m_owns = false;
|
||||
|
|
|
@ -119,7 +119,8 @@ static bool IsSongExtension(const char* path, const char*& dotOut)
|
|||
|
||||
static bool ValidateMP1(FILE* fp)
|
||||
{
|
||||
FileLength(fp);
|
||||
if (FileLength(fp) > 40 * 1024 * 1024)
|
||||
return false;
|
||||
|
||||
uint32_t magic;
|
||||
fread(&magic, 1, 4, fp);
|
||||
|
@ -228,29 +229,34 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadMP1(FILE
|
|||
ReadString(fp);
|
||||
std::string name = ReadString(fp);
|
||||
|
||||
uint32_t len;
|
||||
fread(&len, 1, 4, fp);
|
||||
len = SBig(len);
|
||||
std::unique_ptr<uint8_t[]> pool(new uint8_t[len]);
|
||||
fread(pool.get(), 1, len, fp);
|
||||
uint32_t poolLen;
|
||||
fread(&poolLen, 1, 4, fp);
|
||||
poolLen = SBig(poolLen);
|
||||
std::unique_ptr<uint8_t[]> pool(new uint8_t[poolLen]);
|
||||
fread(pool.get(), 1, poolLen, fp);
|
||||
|
||||
fread(&len, 1, 4, fp);
|
||||
len = SBig(len);
|
||||
std::unique_ptr<uint8_t[]> proj(new uint8_t[len]);
|
||||
fread(proj.get(), 1, len, fp);
|
||||
uint32_t projLen;
|
||||
fread(&projLen, 1, 4, fp);
|
||||
projLen = SBig(projLen);
|
||||
std::unique_ptr<uint8_t[]> proj(new uint8_t[projLen]);
|
||||
fread(proj.get(), 1, projLen, fp);
|
||||
|
||||
fread(&len, 1, 4, fp);
|
||||
len = SBig(len);
|
||||
std::unique_ptr<uint8_t[]> samp(new uint8_t[len]);
|
||||
fread(samp.get(), 1, len, fp);
|
||||
uint32_t sampLen;
|
||||
fread(&sampLen, 1, 4, fp);
|
||||
sampLen = SBig(sampLen);
|
||||
std::unique_ptr<uint8_t[]> samp(new uint8_t[sampLen]);
|
||||
fread(samp.get(), 1, sampLen, fp);
|
||||
|
||||
fread(&len, 1, 4, fp);
|
||||
len = SBig(len);
|
||||
std::unique_ptr<uint8_t[]> sdir(new uint8_t[len]);
|
||||
fread(sdir.get(), 1, len, fp);
|
||||
uint32_t sdirLen;
|
||||
fread(&sdirLen, 1, 4, fp);
|
||||
sdirLen = SBig(sdirLen);
|
||||
std::unique_ptr<uint8_t[]> sdir(new uint8_t[sdirLen]);
|
||||
fread(sdir.get(), 1, sdirLen, fp);
|
||||
|
||||
ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), pool.release(),
|
||||
sdir.release(), samp.release(), GCNDataTag{}});
|
||||
ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), projLen,
|
||||
pool.release(), poolLen,
|
||||
sdir.release(), sdirLen,
|
||||
samp.release(), sampLen, GCNDataTag{}});
|
||||
}
|
||||
}
|
||||
FSeek(fp, origPos, SEEK_SET);
|
||||
|
@ -263,7 +269,8 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadMP1(FILE
|
|||
|
||||
static bool ValidateMP1Songs(FILE* fp)
|
||||
{
|
||||
FileLength(fp);
|
||||
if (FileLength(fp) > 40 * 1024 * 1024)
|
||||
return false;
|
||||
|
||||
uint32_t magic;
|
||||
fread(&magic, 1, 4, fp);
|
||||
|
@ -404,7 +411,8 @@ static std::vector<std::pair<std::string, ContainerRegistry::SongData>> LoadMP1S
|
|||
|
||||
static bool ValidateMP2(FILE* fp)
|
||||
{
|
||||
FileLength(fp);
|
||||
if (FileLength(fp) > 40 * 1024 * 1024)
|
||||
return false;
|
||||
|
||||
uint32_t magic;
|
||||
fread(&magic, 1, 4, fp);
|
||||
|
@ -541,8 +549,10 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadMP2(FILE
|
|||
std::unique_ptr<uint8_t[]> samp(new uint8_t[sampSz]);
|
||||
fread(samp.get(), 1, sampSz, fp);
|
||||
|
||||
ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), pool.release(),
|
||||
sdir.release(), samp.release(), GCNDataTag{}});
|
||||
ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), projSz,
|
||||
pool.release(), poolSz,
|
||||
sdir.release(), sdirSz,
|
||||
samp.release(), sampSz, GCNDataTag{}});
|
||||
}
|
||||
}
|
||||
FSeek(fp, origPos, SEEK_SET);
|
||||
|
@ -589,6 +599,8 @@ static void SwapN64Rom32(void* data, size_t size)
|
|||
static bool ValidateRS1PC(FILE* fp)
|
||||
{
|
||||
size_t endPos = FileLength(fp);
|
||||
if (endPos > 100 * 1024 * 1024)
|
||||
return false;
|
||||
|
||||
uint32_t fstOff;
|
||||
uint32_t fstSz;
|
||||
|
@ -640,41 +652,49 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1PC(FI
|
|||
fread(entries.get(), fstSz, 1, fp);
|
||||
|
||||
std::unique_ptr<uint8_t[]> proj;
|
||||
size_t projSz = 0;
|
||||
std::unique_ptr<uint8_t[]> pool;
|
||||
size_t poolSz = 0;
|
||||
std::unique_ptr<uint8_t[]> sdir;
|
||||
size_t sdirSz = 0;
|
||||
std::unique_ptr<uint8_t[]> samp;
|
||||
size_t sampSz = 0;
|
||||
|
||||
for (uint32_t i=0 ; i<elemCount ; ++i)
|
||||
{
|
||||
RS1FSTEntry& entry = entries[i];
|
||||
if (!strncmp("proj_SND", entry.name, 16))
|
||||
{
|
||||
projSz = entry.decompSz;
|
||||
proj.reset(new uint8_t[entry.decompSz]);
|
||||
FSeek(fp, entry.offset, SEEK_SET);
|
||||
fread(proj.get(), 1, entry.decompSz, fp);
|
||||
}
|
||||
else if (!strncmp("pool_SND", entry.name, 16))
|
||||
{
|
||||
poolSz = entry.decompSz;
|
||||
pool.reset(new uint8_t[entry.decompSz]);
|
||||
FSeek(fp, entry.offset, SEEK_SET);
|
||||
fread(pool.get(), 1, entry.decompSz, fp);
|
||||
}
|
||||
else if (!strncmp("sdir_SND", entry.name, 16))
|
||||
{
|
||||
sdirSz = entry.decompSz;
|
||||
sdir.reset(new uint8_t[entry.decompSz]);
|
||||
FSeek(fp, entry.offset, SEEK_SET);
|
||||
fread(sdir.get(), 1, entry.decompSz, fp);
|
||||
}
|
||||
else if (!strncmp("samp_SND", entry.name, 16))
|
||||
{
|
||||
sampSz = entry.decompSz;
|
||||
samp.reset(new uint8_t[entry.decompSz]);
|
||||
FSeek(fp, entry.offset, SEEK_SET);
|
||||
fread(samp.get(), 1, entry.decompSz, fp);
|
||||
}
|
||||
}
|
||||
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
||||
sdir.release(), samp.release(),
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz,
|
||||
sdir.release(), sdirSz, samp.release(), sampSz,
|
||||
false, PCDataTag{}});
|
||||
}
|
||||
}
|
||||
|
@ -764,9 +784,13 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
|||
const RS1FSTEntry* lastEnt = reinterpret_cast<const RS1FSTEntry*>(dataSeg + fstEnd);
|
||||
|
||||
std::unique_ptr<uint8_t[]> proj;
|
||||
size_t projSz = 0;
|
||||
std::unique_ptr<uint8_t[]> pool;
|
||||
size_t poolSz = 0;
|
||||
std::unique_ptr<uint8_t[]> sdir;
|
||||
size_t sdirSz = 0;
|
||||
std::unique_ptr<uint8_t[]> samp;
|
||||
size_t sampSz = 0;
|
||||
|
||||
for (; entry != lastEnt ; ++entry)
|
||||
{
|
||||
|
@ -786,6 +810,7 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
|||
uLongf outSz = ent.decompSz;
|
||||
uncompress(proj.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||
}
|
||||
projSz = ent.decompSz;
|
||||
}
|
||||
else if (!strncmp("pool_SND", ent.name, 16))
|
||||
{
|
||||
|
@ -800,6 +825,7 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
|||
uLongf outSz = ent.decompSz;
|
||||
uncompress(pool.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||
}
|
||||
poolSz = ent.decompSz;
|
||||
}
|
||||
else if (!strncmp("sdir_SND", ent.name, 16))
|
||||
{
|
||||
|
@ -814,6 +840,7 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
|||
uLongf outSz = ent.decompSz;
|
||||
uncompress(sdir.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||
}
|
||||
sdirSz = ent.decompSz;
|
||||
}
|
||||
else if (!strncmp("samp_SND", ent.name, 16))
|
||||
{
|
||||
|
@ -828,11 +855,12 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
|||
uLongf outSz = ent.decompSz;
|
||||
uncompress(samp.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||
}
|
||||
sampSz = ent.decompSz;
|
||||
}
|
||||
}
|
||||
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
||||
sdir.release(), samp.release(),
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz,
|
||||
sdir.release(), sdirSz, samp.release(), sampSz,
|
||||
false, N64DataTag{}});
|
||||
}
|
||||
|
||||
|
@ -842,7 +870,9 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
|||
static bool ValidateBFNPC(FILE* fp)
|
||||
{
|
||||
size_t endPos = FileLength(fp);
|
||||
|
||||
if (endPos > 100 * 1024 * 1024)
|
||||
return false;
|
||||
|
||||
uint32_t fstOff;
|
||||
uint32_t fstSz;
|
||||
if (fread(&fstOff, 1, 4, fp) == 4 && fread(&fstSz, 1, 4, fp) == 4)
|
||||
|
@ -893,9 +923,13 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNPC(FI
|
|||
fread(entries.get(), fstSz, 1, fp);
|
||||
|
||||
std::unique_ptr<uint8_t[]> proj;
|
||||
size_t projSz = 0;
|
||||
std::unique_ptr<uint8_t[]> pool;
|
||||
size_t poolSz = 0;
|
||||
std::unique_ptr<uint8_t[]> sdir;
|
||||
size_t sdirSz = 0;
|
||||
std::unique_ptr<uint8_t[]> samp;
|
||||
size_t sampSz = 0;
|
||||
|
||||
for (uint32_t i=0 ; i<elemCount ; ++i)
|
||||
{
|
||||
|
@ -905,29 +939,33 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNPC(FI
|
|||
proj.reset(new uint8_t[entry.decompSz]);
|
||||
FSeek(fp, entry.offset, SEEK_SET);
|
||||
fread(proj.get(), 1, entry.decompSz, fp);
|
||||
projSz = entry.decompSz;
|
||||
}
|
||||
else if (!strncmp("pool", entry.name, 16))
|
||||
{
|
||||
pool.reset(new uint8_t[entry.decompSz]);
|
||||
FSeek(fp, entry.offset, SEEK_SET);
|
||||
fread(pool.get(), 1, entry.decompSz, fp);
|
||||
poolSz = entry.decompSz;
|
||||
}
|
||||
else if (!strncmp("sdir", entry.name, 16))
|
||||
{
|
||||
sdir.reset(new uint8_t[entry.decompSz]);
|
||||
FSeek(fp, entry.offset, SEEK_SET);
|
||||
fread(sdir.get(), 1, entry.decompSz, fp);
|
||||
sdirSz = entry.decompSz;
|
||||
}
|
||||
else if (!strncmp("samp", entry.name, 16))
|
||||
{
|
||||
samp.reset(new uint8_t[entry.decompSz]);
|
||||
FSeek(fp, entry.offset, SEEK_SET);
|
||||
fread(samp.get(), 1, entry.decompSz, fp);
|
||||
sampSz = entry.decompSz;
|
||||
}
|
||||
}
|
||||
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
||||
sdir.release(), samp.release(),
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz,
|
||||
sdir.release(), sdirSz, samp.release(), sampSz,
|
||||
true, PCDataTag{}});
|
||||
}
|
||||
}
|
||||
|
@ -1017,9 +1055,13 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(F
|
|||
const RS1FSTEntry* lastEnt = reinterpret_cast<const RS1FSTEntry*>(dataSeg + fstEnd);
|
||||
|
||||
std::unique_ptr<uint8_t[]> proj;
|
||||
size_t projSz = 0;
|
||||
std::unique_ptr<uint8_t[]> pool;
|
||||
size_t poolSz = 0;
|
||||
std::unique_ptr<uint8_t[]> sdir;
|
||||
size_t sdirSz = 0;
|
||||
std::unique_ptr<uint8_t[]> samp;
|
||||
size_t sampSz = 0;
|
||||
|
||||
for (; entry != lastEnt ; ++entry)
|
||||
{
|
||||
|
@ -1039,6 +1081,7 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(F
|
|||
uLongf outSz = ent.decompSz;
|
||||
uncompress(proj.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||
}
|
||||
projSz = ent.decompSz;
|
||||
}
|
||||
else if (!strncmp("pool", ent.name, 16))
|
||||
{
|
||||
|
@ -1053,6 +1096,7 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(F
|
|||
uLongf outSz = ent.decompSz;
|
||||
uncompress(pool.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||
}
|
||||
poolSz = ent.decompSz;
|
||||
}
|
||||
else if (!strncmp("sdir", ent.name, 16))
|
||||
{
|
||||
|
@ -1067,6 +1111,7 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(F
|
|||
uLongf outSz = ent.decompSz;
|
||||
uncompress(sdir.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||
}
|
||||
sdirSz = ent.decompSz;
|
||||
}
|
||||
else if (!strncmp("samp", ent.name, 16))
|
||||
{
|
||||
|
@ -1081,11 +1126,12 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(F
|
|||
uLongf outSz = ent.decompSz;
|
||||
uncompress(samp.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||
}
|
||||
sampSz = ent.decompSz;
|
||||
}
|
||||
}
|
||||
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
||||
sdir.release(), samp.release(),
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz,
|
||||
sdir.release(), sdirSz, samp.release(), sampSz,
|
||||
true, N64DataTag{}});
|
||||
}
|
||||
|
||||
|
@ -1164,7 +1210,9 @@ struct RS23SONHead
|
|||
static bool ValidateRS2(FILE* fp)
|
||||
{
|
||||
size_t endPos = FileLength(fp);
|
||||
|
||||
if (endPos > 600 * 1024 * 1024)
|
||||
return false;
|
||||
|
||||
uint64_t fstOff;
|
||||
fread(&fstOff, 1, 8, fp);
|
||||
fstOff = SBig(fstOff);
|
||||
|
@ -1241,8 +1289,8 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS2(FILE
|
|||
|
||||
char name[128];
|
||||
snprintf(name, 128, "GroupFile%u", j);
|
||||
ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), pool.release(),
|
||||
sdir.release(), samp.release(), GCNDataTag{}});
|
||||
ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), head.projLen, pool.release(), head.poolLen,
|
||||
sdir.release(), head.sdirLen, samp.release(), head.sampLen, GCNDataTag{}});
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -1334,7 +1382,9 @@ struct RS3FSTEntry
|
|||
static bool ValidateRS3(FILE* fp)
|
||||
{
|
||||
size_t endPos = FileLength(fp);
|
||||
|
||||
if (endPos > 600 * 1024 * 1024)
|
||||
return false;
|
||||
|
||||
uint64_t fstOff;
|
||||
fread(&fstOff, 1, 8, fp);
|
||||
fstOff = SBig(fstOff);
|
||||
|
@ -1409,8 +1459,8 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS3(FILE
|
|||
|
||||
char name[128];
|
||||
snprintf(name, 128, "GroupFile%u", j);
|
||||
ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), pool.release(),
|
||||
sdir.release(), samp.release(), GCNDataTag{}});
|
||||
ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), head.projLen, pool.release(), head.poolLen,
|
||||
sdir.release(), head.sdirLen, samp.release(), head.sampLen, GCNDataTag{}});
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -1538,11 +1588,19 @@ ContainerRegistry::Type ContainerRegistry::DetectContainerType(const char* path)
|
|||
|
||||
return Type::Invalid;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::pair<std::string, IntrusiveAudioGroupData>>
|
||||
ContainerRegistry::LoadContainer(const char* path)
|
||||
{
|
||||
Type typeOut;
|
||||
return LoadContainer(path, typeOut);
|
||||
};
|
||||
|
||||
std::vector<std::pair<std::string, IntrusiveAudioGroupData>>
|
||||
ContainerRegistry::LoadContainer(const char* path, Type& typeOut)
|
||||
{
|
||||
FILE* fp;
|
||||
typeOut = Type::Invalid;
|
||||
|
||||
/* See if provided file is one of four raw chunks */
|
||||
const char* dot = nullptr;
|
||||
|
@ -1603,49 +1661,50 @@ ContainerRegistry::LoadContainer(const char* path)
|
|||
fclose(fp);
|
||||
|
||||
fp = fopen(projPath, "rb");
|
||||
size_t fLen = FileLength(fp);
|
||||
if (!fLen)
|
||||
size_t projLen = FileLength(fp);
|
||||
if (!projLen)
|
||||
return ret;
|
||||
std::unique_ptr<uint8_t[]> proj(new uint8_t[fLen]);
|
||||
fread(proj.get(), 1, fLen, fp);
|
||||
std::unique_ptr<uint8_t[]> proj(new uint8_t[projLen]);
|
||||
fread(proj.get(), 1, projLen, fp);
|
||||
|
||||
fp = fopen(poolPath, "rb");
|
||||
fLen = FileLength(fp);
|
||||
if (!fLen)
|
||||
size_t poolLen = FileLength(fp);
|
||||
if (!poolLen)
|
||||
return ret;
|
||||
std::unique_ptr<uint8_t[]> pool(new uint8_t[fLen]);
|
||||
fread(pool.get(), 1, fLen, fp);
|
||||
std::unique_ptr<uint8_t[]> pool(new uint8_t[poolLen]);
|
||||
fread(pool.get(), 1, poolLen, fp);
|
||||
|
||||
fp = fopen(sdirPath, "rb");
|
||||
fLen = FileLength(fp);
|
||||
if (!fLen)
|
||||
size_t sdirLen = FileLength(fp);
|
||||
if (!sdirLen)
|
||||
return ret;
|
||||
std::unique_ptr<uint8_t[]> sdir(new uint8_t[fLen]);
|
||||
fread(sdir.get(), 1, fLen, fp);
|
||||
std::unique_ptr<uint8_t[]> sdir(new uint8_t[sdirLen]);
|
||||
fread(sdir.get(), 1, sdirLen, fp);
|
||||
|
||||
fp = fopen(sampPath, "rb");
|
||||
fLen = FileLength(fp);
|
||||
if (!fLen)
|
||||
size_t sampLen = FileLength(fp);
|
||||
if (!sampPath)
|
||||
return ret;
|
||||
std::unique_ptr<uint8_t[]> samp(new uint8_t[fLen]);
|
||||
fread(samp.get(), 1, fLen, fp);
|
||||
std::unique_ptr<uint8_t[]> samp(new uint8_t[sampLen]);
|
||||
fread(samp.get(), 1, sampLen, fp);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
/* SDIR-based format detection */
|
||||
if (*reinterpret_cast<uint32_t*>(sdir.get() + 8) == 0x0)
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
||||
sdir.release(), samp.release(),
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen,
|
||||
sdir.release(), sdirLen, samp.release(), sampLen,
|
||||
GCNDataTag{}});
|
||||
else if (sdir[9] == 0x0)
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
||||
sdir.release(), samp.release(),
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen,
|
||||
sdir.release(), sdirLen, samp.release(), sampLen,
|
||||
false, N64DataTag{}});
|
||||
else
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
||||
sdir.release(), samp.release(),
|
||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen,
|
||||
sdir.release(), sdirLen, samp.release(), sampLen,
|
||||
false, PCDataTag{}});
|
||||
|
||||
typeOut = Type::Raw4;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1657,6 +1716,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
|||
{
|
||||
auto ret = LoadMP1(fp);
|
||||
fclose(fp);
|
||||
typeOut = Type::MetroidPrime;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1664,6 +1724,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
|||
{
|
||||
auto ret = LoadMP2(fp);
|
||||
fclose(fp);
|
||||
typeOut = Type::MetroidPrime2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1671,6 +1732,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
|||
{
|
||||
auto ret = LoadRS1PC(fp);
|
||||
fclose(fp);
|
||||
typeOut = Type::RogueSquadronPC;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1678,6 +1740,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
|||
{
|
||||
auto ret = LoadRS1N64(fp);
|
||||
fclose(fp);
|
||||
typeOut = Type::RogueSquadronN64;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1685,6 +1748,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
|||
{
|
||||
auto ret = LoadBFNPC(fp);
|
||||
fclose(fp);
|
||||
typeOut = Type::BattleForNabooPC;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1692,6 +1756,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
|||
{
|
||||
auto ret = LoadBFNN64(fp);
|
||||
fclose(fp);
|
||||
typeOut = Type::BattleForNabooN64;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1699,6 +1764,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
|||
{
|
||||
auto ret = LoadRS2(fp);
|
||||
fclose(fp);
|
||||
typeOut = Type::RogueSquadron2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1706,6 +1772,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
|||
{
|
||||
auto ret = LoadRS3(fp);
|
||||
fclose(fp);
|
||||
typeOut = Type::RogueSquadron3;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue