mirror of https://github.com/AxioDL/amuse.git
Merge branch 'master' of https://github.com/AxioDL/amuse
This commit is contained in:
commit
ad784966e9
|
@ -6,6 +6,10 @@
|
||||||
<string>@APPLE_TEAM_ID@.@APPLE_BUNDLE_ID@</string>
|
<string>@APPLE_TEAM_ID@.@APPLE_BUNDLE_ID@</string>
|
||||||
<key>com.apple.developer.team-identifier</key>
|
<key>com.apple.developer.team-identifier</key>
|
||||||
<string>@APPLE_TEAM_ID@</string>
|
<string>@APPLE_TEAM_ID@</string>
|
||||||
|
<key>com.apple.security.app-sandbox</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.files.user-selected.read-only</key>
|
||||||
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>group.io.github.axiodl.Amuse.AudioGroups</string>
|
<string>group.io.github.axiodl.Amuse.AudioGroups</string>
|
||||||
|
|
|
@ -17,7 +17,10 @@
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="creditsView" destination="AWS-Zd-8ha" id="O75-15-wzr"/>
|
<outlet property="creditsView" destination="AWS-Zd-8ha" id="O75-15-wzr"/>
|
||||||
<outlet property="dataOutline" destination="Vlv-Jw-A4U" id="Ggn-DC-cUY"/>
|
<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="mainWindow" destination="FDh-Mc-OFY" id="CQQ-Dm-Kv3"/>
|
||||||
|
<outlet property="removeDataButton" destination="eh8-gl-WoS" id="U9P-dt-tN5"/>
|
||||||
|
<outlet property="removeDataMenu" destination="pa3-QI-u2k" id="xnq-of-WvG"/>
|
||||||
<outlet property="samplesTable" destination="Frt-wZ-1ZI" id="riC-O4-JXo"/>
|
<outlet property="samplesTable" destination="Frt-wZ-1ZI" id="riC-O4-JXo"/>
|
||||||
<outlet property="sfxTable" destination="4nw-rf-Dh4" id="ebY-ro-tqk"/>
|
<outlet property="sfxTable" destination="4nw-rf-Dh4" id="ebY-ro-tqk"/>
|
||||||
</connections>
|
</connections>
|
||||||
|
@ -69,7 +72,7 @@
|
||||||
<items>
|
<items>
|
||||||
<menuItem title="Import…" keyEquivalent="i" id="IAo-SY-fd9">
|
<menuItem title="Import…" keyEquivalent="i" id="IAo-SY-fd9">
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/>
|
<action selector="importFile:" target="Y3H-Qy-a7C" id="j6G-7T-YiQ"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
</items>
|
</items>
|
||||||
|
@ -77,17 +80,15 @@
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem title="Edit" id="5QF-Oa-p0T">
|
<menuItem title="Edit" id="5QF-Oa-p0T">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
|
<menu key="submenu" title="Edit" autoenablesItems="NO" id="W48-6f-4Dl">
|
||||||
<items>
|
<items>
|
||||||
<menuItem title="Delete" id="pa3-QI-u2k">
|
<menuItem title="Delete" enabled="NO" id="pa3-QI-u2k">
|
||||||
|
<string key="keyEquivalent" base64-UTF8="YES">
|
||||||
|
CA
|
||||||
|
</string>
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
|
<action selector="removeDataItem:" target="Y3H-Qy-a7C" id="aAl-Ko-LrT"/>
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
|
|
||||||
<connections>
|
|
||||||
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
|
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
</items>
|
</items>
|
||||||
|
@ -166,128 +167,86 @@
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Alc-jx-Z3v">
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Alc-jx-Z3v">
|
||||||
<rect key="frame" x="0.0" y="-1" width="30" height="32"/>
|
<rect key="frame" x="0.0" y="-1" width="30" height="32"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="30" id="QjK-Fn-bKW"/>
|
<constraint firstAttribute="width" constant="30" id="4fr-kb-eaI"/>
|
||||||
|
<constraint firstAttribute="height" constant="30" id="Sib-AA-UGB"/>
|
||||||
</constraints>
|
</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">
|
<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"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="importFile:" target="Y3H-Qy-a7C" id="bBJ-EO-41Y"/>
|
||||||
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="eh8-gl-WoS">
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="eh8-gl-WoS">
|
||||||
<rect key="frame" x="29" y="-1" width="31" height="31"/>
|
<rect key="frame" x="29" y="-1" width="30" height="32"/>
|
||||||
<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">
|
<constraints>
|
||||||
|
<constraint firstAttribute="width" constant="30" id="6ej-Xv-zwY"/>
|
||||||
|
</constraints>
|
||||||
|
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" enabled="NO" 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>
|
||||||
|
<connections>
|
||||||
|
<action selector="removeDataItem:" target="Y3H-Qy-a7C" id="hau-zt-Ozz"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mpK-AK-Otf" customClass="InactiveButton">
|
||||||
|
<rect key="frame" x="58" y="-1" width="486" height="32"/>
|
||||||
|
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="JwG-gw-HOj">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
</button>
|
</button>
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mpK-AK-Otf">
|
<scrollView autohidesScrollers="YES" horizontalLineScroll="22" horizontalPageScroll="10" verticalLineScroll="22" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XHK-NM-ZAP">
|
||||||
<rect key="frame" x="59" y="-1" width="485" 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">
|
|
||||||
<rect key="frame" x="0.0" y="28" width="544" height="339"/>
|
<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="23" width="542" height="315"/>
|
<rect key="frame" x="1" y="0.0" width="542" height="338"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<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">
|
<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"/>
|
<rect key="frame" x="0.0" y="0.0" width="542" height="315"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<size key="intercellSpacing" width="3" height="2"/>
|
<size key="intercellSpacing" width="3" height="0.0"/>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||||
<tableColumns>
|
<tableColumns>
|
||||||
<tableColumn width="116" minWidth="40" maxWidth="1000" id="DlG-iE-h1a">
|
<tableColumn identifier="CollectionColumn" width="300" minWidth="100" maxWidth="1000" id="DlG-iE-h1a">
|
||||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Collection">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
</tableHeaderCell>
|
</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" refusesFirstResponder="YES" allowsMixedState="YES" inset="2" id="Lpp-wh-qX7" customClass="RestrictedCheckButton">
|
||||||
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
</buttonCell>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
</textFieldCell>
|
|
||||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
<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>
|
||||||
<tableColumn width="420" minWidth="40" maxWidth="1000" id="alh-ut-BoX">
|
<tableColumn identifier="DetailsColumn" width="236" minWidth="40" maxWidth="1000" id="alh-ut-BoX">
|
||||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Details">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
</tableHeaderCell>
|
</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"/>
|
<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"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
<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>
|
</tableColumn>
|
||||||
</tableColumns>
|
</tableColumns>
|
||||||
</outlineView>
|
</outlineView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<nil key="backgroundColor"/>
|
||||||
</clipView>
|
</clipView>
|
||||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="ZGl-Ws-7HQ">
|
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="ZGl-Ws-7HQ">
|
||||||
<rect key="frame" x="1" y="19" width="158" height="15"/>
|
<rect key="frame" x="1" y="19" width="158" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="cwa-Vo-ZEb">
|
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="cwa-Vo-ZEb">
|
||||||
<rect key="frame" x="159" y="23" width="15" height="-4"/>
|
<rect key="frame" x="159" y="23" width="15" height="4"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
<tableHeaderView key="headerView" id="jN4-UQ-VfT">
|
<tableHeaderView key="headerView" id="jN4-UQ-VfT">
|
||||||
|
@ -296,36 +255,34 @@
|
||||||
</tableHeaderView>
|
</tableHeaderView>
|
||||||
</scrollView>
|
</scrollView>
|
||||||
<searchField wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Huk-pR-ayq">
|
<searchField wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Huk-pR-ayq">
|
||||||
<rect key="frame" x="65" y="4" width="474" height="22"/>
|
<rect key="frame" x="63" y="3" width="477" height="22"/>
|
||||||
<constraints>
|
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" usesSingleLineMode="YES" bezelStyle="round" sendsSearchStringImmediately="YES" id="u9E-Ld-d6I">
|
||||||
<constraint firstAttribute="height" constant="22" id="bta-rr-Rjn"/>
|
|
||||||
</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"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</searchFieldCell>
|
</searchFieldCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="filterDataOutline:" target="Y3H-Qy-a7C" id="D8g-Qv-0QG"/>
|
||||||
|
</connections>
|
||||||
</searchField>
|
</searchField>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="top" secondItem="GKx-9K-n29" secondAttribute="top" id="11d-cK-KTn"/>
|
<constraint firstAttribute="trailing" secondItem="XHK-NM-ZAP" secondAttribute="trailing" id="1pE-DU-h1S"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="Huk-pR-ayq" secondAttribute="trailing" constant="5" id="1Bp-rN-FgN"/>
|
<constraint firstItem="eh8-gl-WoS" firstAttribute="firstBaseline" secondItem="mpK-AK-Otf" secondAttribute="firstBaseline" id="3Y4-En-NmZ"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="Huk-pR-ayq" secondAttribute="bottom" constant="4" id="3Px-xo-dAv"/>
|
<constraint firstItem="XHK-NM-ZAP" firstAttribute="leading" secondItem="GKx-9K-n29" secondAttribute="leading" id="B0v-IP-0Ic"/>
|
||||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="trailing" secondItem="mpK-AK-Otf" secondAttribute="trailing" id="5i2-xa-qrD"/>
|
<constraint firstAttribute="bottom" secondItem="Alc-jx-Z3v" secondAttribute="bottom" id="KIX-cn-mNM"/>
|
||||||
<constraint firstItem="Alc-jx-Z3v" firstAttribute="baseline" secondItem="eh8-gl-WoS" secondAttribute="baseline" id="8uY-Ir-nmM"/>
|
<constraint firstItem="Alc-jx-Z3v" firstAttribute="firstBaseline" secondItem="eh8-gl-WoS" secondAttribute="firstBaseline" id="O7r-da-zgD"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="XHK-NM-ZAP" secondAttribute="trailing" id="9gd-HE-7uf"/>
|
<constraint firstItem="XHK-NM-ZAP" firstAttribute="leading" secondItem="Alc-jx-Z3v" secondAttribute="leading" id="QqG-Ek-LI8"/>
|
||||||
<constraint firstItem="Huk-pR-ayq" firstAttribute="leading" secondItem="eh8-gl-WoS" secondAttribute="trailing" constant="5" id="Aav-lf-aM8"/>
|
<constraint firstAttribute="bottom" secondItem="Huk-pR-ayq" secondAttribute="bottom" constant="3" id="R5r-Tf-sig"/>
|
||||||
<constraint firstItem="eh8-gl-WoS" firstAttribute="baseline" secondItem="mpK-AK-Otf" secondAttribute="baseline" id="Inf-xH-Xiu"/>
|
<constraint firstItem="XHK-NM-ZAP" firstAttribute="trailing" secondItem="mpK-AK-Otf" secondAttribute="trailing" id="Xa6-xa-785"/>
|
||||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="leading" secondItem="Alc-jx-Z3v" secondAttribute="leading" id="Qwp-2y-pUU"/>
|
<constraint firstItem="Alc-jx-Z3v" firstAttribute="baseline" secondItem="eh8-gl-WoS" secondAttribute="baseline" id="ZPG-ox-LD0"/>
|
||||||
<constraint firstItem="Huk-pR-ayq" firstAttribute="top" secondItem="XHK-NM-ZAP" secondAttribute="bottom" constant="2" id="S29-sA-pR1"/>
|
<constraint firstItem="eh8-gl-WoS" firstAttribute="baseline" secondItem="mpK-AK-Otf" secondAttribute="baseline" id="ax4-ux-lgm"/>
|
||||||
<constraint firstItem="mpK-AK-Otf" firstAttribute="centerY" secondItem="Huk-pR-ayq" secondAttribute="centerY" id="Y1b-wA-j5b"/>
|
<constraint firstItem="Huk-pR-ayq" firstAttribute="top" secondItem="XHK-NM-ZAP" secondAttribute="bottom" constant="3" id="iG2-ku-8X4"/>
|
||||||
<constraint firstItem="Alc-jx-Z3v" firstAttribute="centerY" secondItem="eh8-gl-WoS" secondAttribute="centerY" id="YXF-DS-Qzu"/>
|
<constraint firstItem="XHK-NM-ZAP" firstAttribute="top" secondItem="GKx-9K-n29" secondAttribute="top" id="mp7-MY-xub"/>
|
||||||
<constraint firstItem="mpK-AK-Otf" firstAttribute="leading" secondItem="Alc-jx-Z3v" secondAttribute="trailing" constant="29" id="bF7-N0-Fff"/>
|
<constraint firstItem="Huk-pR-ayq" firstAttribute="centerX" secondItem="mpK-AK-Otf" secondAttribute="centerX" id="uB6-uO-1Wh"/>
|
||||||
<constraint firstItem="eh8-gl-WoS" firstAttribute="leading" secondItem="GKx-9K-n29" secondAttribute="leading" constant="29" id="flM-s6-dSI"/>
|
<constraint firstItem="mpK-AK-Otf" firstAttribute="leading" secondItem="Alc-jx-Z3v" secondAttribute="trailing" constant="28" id="vkC-Xs-dXI"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="Alc-jx-Z3v" secondAttribute="bottom" id="iKi-2E-TFe"/>
|
<constraint firstItem="eh8-gl-WoS" firstAttribute="leading" secondItem="GKx-9K-n29" secondAttribute="leading" constant="29" id="wTd-sN-gen"/>
|
||||||
<constraint firstItem="XHK-NM-ZAP" firstAttribute="leading" secondItem="GKx-9K-n29" secondAttribute="leading" id="lRg-3u-LsT"/>
|
<constraint firstItem="Huk-pR-ayq" firstAttribute="leading" secondItem="eh8-gl-WoS" secondAttribute="trailing" constant="4" id="xpV-H6-3B5"/>
|
||||||
<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"/>
|
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
</tabViewItem>
|
</tabViewItem>
|
||||||
|
@ -334,74 +291,39 @@
|
||||||
<rect key="frame" x="0.0" y="0.0" width="544" height="367"/>
|
<rect key="frame" x="0.0" y="0.0" width="544" height="367"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KBz-ap-rBr">
|
|
||||||
<rect key="frame" x="0.0" y="-1" width="30" height="32"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="width" constant="30" id="JPF-XW-Zrm"/>
|
|
||||||
</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="eb5-rf-bFE">
|
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
</buttonCell>
|
|
||||||
</button>
|
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="3Ss-Wh-6dp">
|
|
||||||
<rect key="frame" x="29" y="-1" width="31" height="31"/>
|
|
||||||
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="xGw-iM-KTu">
|
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
</buttonCell>
|
|
||||||
</button>
|
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="AnJ-nZ-Zfp">
|
|
||||||
<rect key="frame" x="59" y="-1" width="485" 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="SjA-P5-3He">
|
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
</buttonCell>
|
|
||||||
</button>
|
|
||||||
<searchField wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="oAG-fe-WMm">
|
|
||||||
<rect key="frame" x="65" y="4" width="474" height="22"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" constant="22" id="NcP-aU-Wkl"/>
|
|
||||||
</constraints>
|
|
||||||
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" usesSingleLineMode="YES" bezelStyle="round" id="gRb-aR-GFw">
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
</searchFieldCell>
|
|
||||||
</searchField>
|
|
||||||
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4I7-lP-08K">
|
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4I7-lP-08K">
|
||||||
<rect key="frame" x="0.0" y="29" width="544" height="338"/>
|
<rect key="frame" x="0.0" y="0.0" width="544" height="367"/>
|
||||||
<clipView key="contentView" id="vf9-4W-0Zi">
|
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="vf9-4W-0Zi">
|
||||||
<rect key="frame" x="1" y="23" width="542" height="314"/>
|
<rect key="frame" x="1" y="0.0" width="542" height="366"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="9pb-bl-sSa" viewBased="YES" id="4nw-rf-Dh4">
|
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="9pb-bl-sSa" viewBased="YES" id="4nw-rf-Dh4">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="542" height="314"/>
|
<rect key="frame" x="0.0" y="0.0" width="542" height="343"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<size key="intercellSpacing" width="3" height="2"/>
|
<size key="intercellSpacing" width="3" height="2"/>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||||
<tableColumns>
|
<tableColumns>
|
||||||
<tableColumn width="116" minWidth="40" maxWidth="1000" id="lNw-az-m8v">
|
<tableColumn identifier="SFXIDColumn" width="116" minWidth="40" maxWidth="1000" id="lNw-az-m8v">
|
||||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="ID">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
</tableHeaderCell>
|
</tableHeaderCell>
|
||||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="RNG-D2-ueb">
|
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" allowsUndo="NO" title="Text Cell" id="RNG-D2-ueb">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||||
<prototypeCellViews>
|
<prototypeCellViews>
|
||||||
<tableCellView id="Bld-o1-jXJ">
|
<tableCellView id="XFL-Ls-02w">
|
||||||
<rect key="frame" x="1" y="1" width="116" height="17"/>
|
<rect key="frame" x="1" y="1" width="116" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="ZZj-P8-9ts">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="2PL-fA-QSc">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="100" height="17"/>
|
<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="TAi-Dq-tMT">
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" title="Table View Cell" id="xYV-rG-09O">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
@ -409,39 +331,39 @@
|
||||||
</textField>
|
</textField>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="ZZj-P8-9ts" firstAttribute="leading" secondItem="Bld-o1-jXJ" secondAttribute="leading" constant="2" id="AY8-Jl-YdX"/>
|
<constraint firstAttribute="trailing" secondItem="2PL-fA-QSc" secondAttribute="trailing" constant="18" id="6Rm-bD-4WK"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="ZZj-P8-9ts" secondAttribute="trailing" constant="18" id="IDi-fM-pVu"/>
|
<constraint firstItem="2PL-fA-QSc" firstAttribute="centerY" secondItem="XFL-Ls-02w" secondAttribute="centerY" id="enx-iG-2oB"/>
|
||||||
<constraint firstItem="ZZj-P8-9ts" firstAttribute="centerY" secondItem="Bld-o1-jXJ" secondAttribute="centerY" id="LPm-yn-FQX"/>
|
<constraint firstItem="2PL-fA-QSc" firstAttribute="leading" secondItem="XFL-Ls-02w" secondAttribute="leading" constant="2" id="qeB-0G-dXO"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="textField" destination="ZZj-P8-9ts" id="39a-MV-EbQ"/>
|
<outlet property="textField" destination="2PL-fA-QSc" id="RpZ-Uw-Grp"/>
|
||||||
</connections>
|
</connections>
|
||||||
</tableCellView>
|
</tableCellView>
|
||||||
</prototypeCellViews>
|
</prototypeCellViews>
|
||||||
</tableColumn>
|
</tableColumn>
|
||||||
<tableColumn width="420" minWidth="40" maxWidth="1000" id="cir-wf-zZH">
|
<tableColumn identifier="SFXDetailsColumn" width="420" minWidth="40" maxWidth="1000" id="cir-wf-zZH">
|
||||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Details">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
</tableHeaderCell>
|
</tableHeaderCell>
|
||||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="Emw-gX-CND">
|
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" allowsUndo="NO" title="Text Cell" id="Emw-gX-CND">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||||
<prototypeCellViews>
|
<prototypeCellViews>
|
||||||
<tableCellView id="MSH-I7-WP0">
|
<tableCellView id="gVd-1Z-stf">
|
||||||
<rect key="frame" x="120" y="1" width="420" height="17"/>
|
<rect key="frame" x="120" y="1" width="420" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="sZh-af-mID">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="w19-X3-abH">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="100" height="17"/>
|
<rect key="frame" x="0.0" y="0.0" width="100" height="17"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="96" id="Olp-J5-pIs"/>
|
<constraint firstAttribute="width" constant="96" id="Gae-0I-VGs"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="g74-lI-1lW">
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" title="Table View Cell" id="PxJ-bH-77o">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
@ -449,11 +371,11 @@
|
||||||
</textField>
|
</textField>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="sZh-af-mID" firstAttribute="centerY" secondItem="MSH-I7-WP0" secondAttribute="centerY" id="TR4-l3-M5x"/>
|
<constraint firstItem="w19-X3-abH" firstAttribute="centerY" secondItem="gVd-1Z-stf" secondAttribute="centerY" id="71k-IB-NPp"/>
|
||||||
<constraint firstItem="sZh-af-mID" firstAttribute="leading" secondItem="MSH-I7-WP0" secondAttribute="leading" constant="2" id="txo-P4-p8A"/>
|
<constraint firstItem="w19-X3-abH" firstAttribute="leading" secondItem="gVd-1Z-stf" secondAttribute="leading" constant="2" id="rX3-HS-TGq"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="textField" destination="sZh-af-mID" id="fET-Gy-kz6"/>
|
<outlet property="textField" destination="w19-X3-abH" id="BS3-ol-wil"/>
|
||||||
</connections>
|
</connections>
|
||||||
</tableCellView>
|
</tableCellView>
|
||||||
</prototypeCellViews>
|
</prototypeCellViews>
|
||||||
|
@ -461,13 +383,13 @@
|
||||||
</tableColumns>
|
</tableColumns>
|
||||||
</tableView>
|
</tableView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<nil key="backgroundColor"/>
|
||||||
</clipView>
|
</clipView>
|
||||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="uOf-Jb-IVN">
|
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="uOf-Jb-IVN">
|
||||||
<rect key="frame" x="1" y="119" width="223" height="15"/>
|
<rect key="frame" x="1" y="119" width="223" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="AvT-7G-lW8">
|
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="AvT-7G-lW8">
|
||||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
|
@ -478,24 +400,10 @@
|
||||||
</scrollView>
|
</scrollView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="oAG-fe-WMm" firstAttribute="top" secondItem="4I7-lP-08K" secondAttribute="bottom" constant="3" id="2Ga-AL-Moz"/>
|
<constraint firstItem="4I7-lP-08K" firstAttribute="leading" secondItem="qIJ-rh-cnU" secondAttribute="leading" id="ofT-nM-Uob"/>
|
||||||
<constraint firstItem="AnJ-nZ-Zfp" firstAttribute="leading" secondItem="KBz-ap-rBr" secondAttribute="trailing" constant="29" id="3sF-mo-yXM"/>
|
<constraint firstAttribute="trailing" secondItem="4I7-lP-08K" secondAttribute="trailing" id="weV-m7-oie"/>
|
||||||
<constraint firstItem="4I7-lP-08K" firstAttribute="leading" secondItem="KBz-ap-rBr" secondAttribute="leading" id="BHY-wE-9xs"/>
|
<constraint firstAttribute="bottom" secondItem="4I7-lP-08K" secondAttribute="bottom" id="yOi-OG-adc"/>
|
||||||
<constraint firstItem="KBz-ap-rBr" firstAttribute="centerY" secondItem="3Ss-Wh-6dp" secondAttribute="centerY" id="CqR-JP-dag"/>
|
<constraint firstItem="4I7-lP-08K" firstAttribute="top" secondItem="qIJ-rh-cnU" secondAttribute="top" id="ykR-eE-XY3"/>
|
||||||
<constraint firstItem="4I7-lP-08K" firstAttribute="top" secondItem="qIJ-rh-cnU" secondAttribute="top" id="DKu-qi-8Zi"/>
|
|
||||||
<constraint firstItem="3Ss-Wh-6dp" firstAttribute="leading" secondItem="qIJ-rh-cnU" secondAttribute="leading" constant="29" id="GdU-tv-IPD"/>
|
|
||||||
<constraint firstItem="KBz-ap-rBr" firstAttribute="firstBaseline" secondItem="AnJ-nZ-Zfp" secondAttribute="firstBaseline" id="HTn-NF-EgY"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="KBz-ap-rBr" secondAttribute="bottom" id="IOx-sd-Ta0"/>
|
|
||||||
<constraint firstItem="3Ss-Wh-6dp" firstAttribute="baseline" secondItem="AnJ-nZ-Zfp" secondAttribute="baseline" id="Ipx-yq-qlA"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="oAG-fe-WMm" secondAttribute="trailing" constant="5" id="QMV-Df-EKc"/>
|
|
||||||
<constraint firstItem="3Ss-Wh-6dp" firstAttribute="top" secondItem="4I7-lP-08K" secondAttribute="bottom" id="Qj2-aa-7cc"/>
|
|
||||||
<constraint firstItem="KBz-ap-rBr" firstAttribute="baseline" secondItem="3Ss-Wh-6dp" secondAttribute="baseline" id="W08-Un-JWq"/>
|
|
||||||
<constraint firstItem="4I7-lP-08K" firstAttribute="leading" secondItem="qIJ-rh-cnU" secondAttribute="leading" id="WhF-Wb-PFB"/>
|
|
||||||
<constraint firstItem="AnJ-nZ-Zfp" firstAttribute="centerY" secondItem="oAG-fe-WMm" secondAttribute="centerY" id="Zox-TK-kuL"/>
|
|
||||||
<constraint firstItem="oAG-fe-WMm" firstAttribute="leading" secondItem="3Ss-Wh-6dp" secondAttribute="trailing" constant="5" id="aJS-aa-4eq"/>
|
|
||||||
<constraint firstItem="4I7-lP-08K" firstAttribute="trailing" secondItem="AnJ-nZ-Zfp" secondAttribute="trailing" id="ss6-VM-Yi5"/>
|
|
||||||
<constraint firstItem="oAG-fe-WMm" firstAttribute="centerX" secondItem="AnJ-nZ-Zfp" secondAttribute="centerX" id="z9w-zt-20K"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="4I7-lP-08K" secondAttribute="trailing" id="zdJ-hh-V8T"/>
|
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
</tabViewItem>
|
</tabViewItem>
|
||||||
|
@ -504,74 +412,39 @@
|
||||||
<rect key="frame" x="0.0" y="0.0" width="544" height="367"/>
|
<rect key="frame" x="0.0" y="0.0" width="544" height="367"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="YfR-tZ-Cqm">
|
|
||||||
<rect key="frame" x="0.0" y="-1" width="30" height="32"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="width" constant="30" id="LNb-6x-6BN"/>
|
|
||||||
</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="HJf-MA-3Rg">
|
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
</buttonCell>
|
|
||||||
</button>
|
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5lG-v1-xlR">
|
|
||||||
<rect key="frame" x="29" y="-1" width="31" height="31"/>
|
|
||||||
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Uhf-Ik-kst">
|
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
</buttonCell>
|
|
||||||
</button>
|
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="meL-4m-liG">
|
|
||||||
<rect key="frame" x="59" y="-1" width="485" 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="LJN-Sj-A70">
|
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
</buttonCell>
|
|
||||||
</button>
|
|
||||||
<searchField wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8fs-yS-j3u">
|
|
||||||
<rect key="frame" x="65" y="4" width="474" height="22"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" constant="22" id="e8E-TS-Dd8"/>
|
|
||||||
</constraints>
|
|
||||||
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" usesSingleLineMode="YES" bezelStyle="round" id="qxx-lO-6Nw">
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
</searchFieldCell>
|
|
||||||
</searchField>
|
|
||||||
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aIh-No-CEz">
|
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aIh-No-CEz">
|
||||||
<rect key="frame" x="0.0" y="29" width="544" height="338"/>
|
<rect key="frame" x="0.0" y="1" width="544" height="366"/>
|
||||||
<clipView key="contentView" id="MzV-rp-Rp8">
|
<clipView key="contentView" drawsBackground="NO" id="MzV-rp-Rp8">
|
||||||
<rect key="frame" x="1" y="23" width="542" height="314"/>
|
<rect key="frame" x="1" y="0.0" width="542" height="365"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="fQK-tA-ezw" viewBased="YES" id="Frt-wZ-1ZI">
|
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="fQK-tA-ezw" viewBased="YES" id="Frt-wZ-1ZI">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="542" height="314"/>
|
<rect key="frame" x="0.0" y="0.0" width="542" height="342"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<size key="intercellSpacing" width="3" height="2"/>
|
<size key="intercellSpacing" width="3" height="2"/>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||||
<tableColumns>
|
<tableColumns>
|
||||||
<tableColumn width="116" minWidth="40" maxWidth="1000" id="RF7-J2-oFq">
|
<tableColumn identifier="SampleIDColumn" width="116" minWidth="40" maxWidth="1000" id="RF7-J2-oFq">
|
||||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="ID">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
</tableHeaderCell>
|
</tableHeaderCell>
|
||||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="O7U-y5-ovx">
|
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" allowsUndo="NO" title="Text Cell" id="O7U-y5-ovx">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||||
<prototypeCellViews>
|
<prototypeCellViews>
|
||||||
<tableCellView id="ffN-yY-DyX">
|
<tableCellView id="nAU-e4-oze">
|
||||||
<rect key="frame" x="1" y="1" width="116" height="17"/>
|
<rect key="frame" x="1" y="1" width="116" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="DUu-Bo-MP0">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="tZr-rU-2Pd">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="100" height="17"/>
|
<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="N99-9O-D40">
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" title="Table View Cell" id="AJI-LY-8Wf">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
@ -579,39 +452,39 @@
|
||||||
</textField>
|
</textField>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="DUu-Bo-MP0" firstAttribute="leading" secondItem="ffN-yY-DyX" secondAttribute="leading" constant="2" id="2he-p0-Rsl"/>
|
<constraint firstItem="tZr-rU-2Pd" firstAttribute="leading" secondItem="nAU-e4-oze" secondAttribute="leading" constant="2" id="I9j-sV-Ivw"/>
|
||||||
<constraint firstItem="DUu-Bo-MP0" firstAttribute="centerY" secondItem="ffN-yY-DyX" secondAttribute="centerY" id="YDQ-Wo-FVN"/>
|
<constraint firstAttribute="trailing" secondItem="tZr-rU-2Pd" secondAttribute="trailing" constant="18" id="UmQ-yh-qIc"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="DUu-Bo-MP0" secondAttribute="trailing" constant="18" id="zUo-KU-6TP"/>
|
<constraint firstItem="tZr-rU-2Pd" firstAttribute="centerY" secondItem="nAU-e4-oze" secondAttribute="centerY" id="qfU-4d-RVC"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="textField" destination="DUu-Bo-MP0" id="KVw-BO-rFN"/>
|
<outlet property="textField" destination="tZr-rU-2Pd" id="qXZ-eW-rn8"/>
|
||||||
</connections>
|
</connections>
|
||||||
</tableCellView>
|
</tableCellView>
|
||||||
</prototypeCellViews>
|
</prototypeCellViews>
|
||||||
</tableColumn>
|
</tableColumn>
|
||||||
<tableColumn width="420" minWidth="40" maxWidth="1000" id="MqW-cb-qx7">
|
<tableColumn identifier="SampleDetailsColumn" width="420" minWidth="40" maxWidth="1000" id="MqW-cb-qx7">
|
||||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Details">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
</tableHeaderCell>
|
</tableHeaderCell>
|
||||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="FTl-PH-ryo">
|
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" allowsUndo="NO" title="Text Cell" id="FTl-PH-ryo">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||||
<prototypeCellViews>
|
<prototypeCellViews>
|
||||||
<tableCellView id="Syu-AI-iQO">
|
<tableCellView id="Td7-KD-77Y">
|
||||||
<rect key="frame" x="120" y="1" width="420" height="17"/>
|
<rect key="frame" x="120" y="1" width="420" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="42J-2Q-ggr">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="aa7-sT-ACB">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="100" height="17"/>
|
<rect key="frame" x="0.0" y="0.0" width="100" height="17"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="96" id="0Ia-Hu-xUz"/>
|
<constraint firstAttribute="width" constant="96" id="NiS-2g-Lrp"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="5ml-w5-V8a">
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" title="Table View Cell" id="bTT-92-guS">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
@ -619,11 +492,11 @@
|
||||||
</textField>
|
</textField>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="42J-2Q-ggr" firstAttribute="centerY" secondItem="Syu-AI-iQO" secondAttribute="centerY" id="6ea-XB-hmz"/>
|
<constraint firstItem="aa7-sT-ACB" firstAttribute="leading" secondItem="Td7-KD-77Y" secondAttribute="leading" constant="2" id="CMk-N2-FLW"/>
|
||||||
<constraint firstItem="42J-2Q-ggr" firstAttribute="leading" secondItem="Syu-AI-iQO" secondAttribute="leading" constant="2" id="9Bv-2m-jNN"/>
|
<constraint firstItem="aa7-sT-ACB" firstAttribute="centerY" secondItem="Td7-KD-77Y" secondAttribute="centerY" id="Wi6-jL-iGR"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="textField" destination="42J-2Q-ggr" id="pLh-XE-CfB"/>
|
<outlet property="textField" destination="aa7-sT-ACB" id="Cbv-CJ-AQD"/>
|
||||||
</connections>
|
</connections>
|
||||||
</tableCellView>
|
</tableCellView>
|
||||||
</prototypeCellViews>
|
</prototypeCellViews>
|
||||||
|
@ -631,13 +504,13 @@
|
||||||
</tableColumns>
|
</tableColumns>
|
||||||
</tableView>
|
</tableView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<nil key="backgroundColor"/>
|
||||||
</clipView>
|
</clipView>
|
||||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="MZB-ZS-SbU">
|
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="MZB-ZS-SbU">
|
||||||
<rect key="frame" x="1" y="119" width="223" height="15"/>
|
<rect key="frame" x="1" y="119" width="223" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="X6u-4b-0Ia">
|
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="X6u-4b-0Ia">
|
||||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
|
@ -648,24 +521,10 @@
|
||||||
</scrollView>
|
</scrollView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="YfR-tZ-Cqm" firstAttribute="baseline" secondItem="5lG-v1-xlR" secondAttribute="baseline" id="0yW-5L-6xL"/>
|
<constraint firstAttribute="trailing" secondItem="aIh-No-CEz" secondAttribute="trailing" id="DYN-OA-95T"/>
|
||||||
<constraint firstItem="aIh-No-CEz" firstAttribute="trailing" secondItem="meL-4m-liG" secondAttribute="trailing" id="1KY-Rr-WjB"/>
|
<constraint firstItem="aIh-No-CEz" firstAttribute="top" secondItem="A6d-Tc-9Ch" secondAttribute="top" id="LVF-DP-KHg"/>
|
||||||
<constraint firstItem="aIh-No-CEz" firstAttribute="top" secondItem="A6d-Tc-9Ch" secondAttribute="top" id="2o4-JJ-xTa"/>
|
<constraint firstItem="aIh-No-CEz" firstAttribute="leading" secondItem="A6d-Tc-9Ch" secondAttribute="leading" id="SF5-ox-STl"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="aIh-No-CEz" secondAttribute="trailing" id="4cN-48-TIp"/>
|
<constraint firstItem="aIh-No-CEz" firstAttribute="centerY" secondItem="A6d-Tc-9Ch" secondAttribute="centerY" id="xg8-Qp-9kO"/>
|
||||||
<constraint firstItem="meL-4m-liG" firstAttribute="leading" secondItem="YfR-tZ-Cqm" secondAttribute="trailing" constant="29" id="B2C-oR-2je"/>
|
|
||||||
<constraint firstItem="aIh-No-CEz" firstAttribute="leading" secondItem="A6d-Tc-9Ch" secondAttribute="leading" id="CgO-aA-i0w"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="YfR-tZ-Cqm" secondAttribute="bottom" id="KXP-Wn-AEZ"/>
|
|
||||||
<constraint firstItem="8fs-yS-j3u" firstAttribute="top" secondItem="aIh-No-CEz" secondAttribute="bottom" constant="3" id="Ras-NE-DOd"/>
|
|
||||||
<constraint firstItem="aIh-No-CEz" firstAttribute="leading" secondItem="YfR-tZ-Cqm" secondAttribute="leading" id="WTG-q1-AbI"/>
|
|
||||||
<constraint firstItem="5lG-v1-xlR" firstAttribute="leading" secondItem="A6d-Tc-9Ch" secondAttribute="leading" constant="29" id="Z81-xl-EM4"/>
|
|
||||||
<constraint firstItem="YfR-tZ-Cqm" firstAttribute="centerY" secondItem="5lG-v1-xlR" secondAttribute="centerY" id="hXw-Al-NS4"/>
|
|
||||||
<constraint firstItem="8fs-yS-j3u" firstAttribute="leading" secondItem="5lG-v1-xlR" secondAttribute="trailing" constant="5" id="kCf-4j-RgY"/>
|
|
||||||
<constraint firstItem="YfR-tZ-Cqm" firstAttribute="firstBaseline" secondItem="meL-4m-liG" secondAttribute="firstBaseline" id="kiM-MZ-94m"/>
|
|
||||||
<constraint firstItem="meL-4m-liG" firstAttribute="centerY" secondItem="8fs-yS-j3u" secondAttribute="centerY" id="lO3-6v-BmR"/>
|
|
||||||
<constraint firstItem="5lG-v1-xlR" firstAttribute="baseline" secondItem="meL-4m-liG" secondAttribute="baseline" id="lWj-xA-tcg"/>
|
|
||||||
<constraint firstItem="5lG-v1-xlR" firstAttribute="top" secondItem="aIh-No-CEz" secondAttribute="bottom" id="rwW-Ez-40s"/>
|
|
||||||
<constraint firstItem="8fs-yS-j3u" firstAttribute="centerX" secondItem="meL-4m-liG" secondAttribute="centerX" id="tHD-vu-oEw"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="8fs-yS-j3u" secondAttribute="trailing" constant="5" id="vjS-qe-dVe"/>
|
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
</tabViewItem>
|
</tabViewItem>
|
||||||
|
@ -685,10 +544,10 @@
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
<size key="minSize" width="527" height="365"/>
|
<size key="minSize" width="527" height="365"/>
|
||||||
<size key="maxSize" width="541" height="10000000"/>
|
<size key="maxSize" width="544" height="10000000"/>
|
||||||
<color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<size key="minSize" width="527" height="365"/>
|
<size key="minSize" width="527" height="365"/>
|
||||||
<size key="maxSize" width="541" height="10000000"/>
|
<size key="maxSize" width="544" height="10000000"/>
|
||||||
</textView>
|
</textView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
@ -715,10 +574,10 @@
|
||||||
</tabView>
|
</tabView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<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="QKQ-cu-CcX"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="Kht-FW-Kf6" secondAttribute="trailing" id="JMc-UC-ORE"/>
|
<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="joC-pf-f1v"/>
|
<constraint firstItem="Kht-FW-Kf6" firstAttribute="top" secondItem="9Rk-3e-xVS" secondAttribute="top" id="cHb-PJ-LRW"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="Kht-FW-Kf6" secondAttribute="bottom" id="yTz-NI-FWd"/>
|
<constraint firstItem="Kht-FW-Kf6" firstAttribute="leading" secondItem="9Rk-3e-xVS" secondAttribute="leading" id="qWs-qF-70Y"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<toolbar key="toolbar" implicitIdentifier="B4A5636B-DFED-420B-B2FF-540D729FD569" autosavesConfiguration="NO" allowsUserCustomization="NO" displayMode="iconAndLabel" sizeMode="regular" id="r4I-P0-82j">
|
<toolbar key="toolbar" implicitIdentifier="B4A5636B-DFED-420B-B2FF-540D729FD569" autosavesConfiguration="NO" allowsUserCustomization="NO" displayMode="iconAndLabel" sizeMode="regular" id="r4I-P0-82j">
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
#ifndef __AMUSE_AUDIOUNIT_CONTAININGAPP_HPP__
|
||||||
|
#define __AMUSE_AUDIOUNIT_CONTAININGAPP_HPP__
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
#import "AudioGroupFilePresenter.hpp"
|
||||||
|
#include <amuse/BooBackend.hpp>
|
||||||
|
#include <boo/audiodev/IAudioVoiceEngine.hpp>
|
||||||
|
|
||||||
|
@interface DataOutlineView : NSOutlineView
|
||||||
|
{
|
||||||
|
@public
|
||||||
|
IBOutlet NSButton* removeDataButton;
|
||||||
|
IBOutlet NSMenuItem* deleteMenuItem;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface SamplesTableController : NSObject <NSTableViewDataSource, NSTableViewDelegate>
|
||||||
|
{
|
||||||
|
AudioGroupFilePresenter* presenter;
|
||||||
|
}
|
||||||
|
- (id)initWithAudioGroupPresenter:(AudioGroupFilePresenter*)present;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface SFXTableController : NSObject <NSTableViewDataSource, NSTableViewDelegate>
|
||||||
|
{
|
||||||
|
AudioGroupFilePresenter* presenter;
|
||||||
|
}
|
||||||
|
- (id)initWithAudioGroupPresenter:(AudioGroupFilePresenter*)present;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface AppDelegate : NSObject <NSApplicationDelegate, AudioGroupClient>
|
||||||
|
{
|
||||||
|
IBOutlet NSWindow* mainWindow;
|
||||||
|
IBOutlet NSOutlineView* dataOutline;
|
||||||
|
IBOutlet NSSearchField* dataSearchField;
|
||||||
|
IBOutlet NSTableView* sfxTable;
|
||||||
|
IBOutlet NSTableView* samplesTable;
|
||||||
|
IBOutlet NSTextView* creditsView;
|
||||||
|
|
||||||
|
IBOutlet NSButton* removeDataButton;
|
||||||
|
IBOutlet NSMenuItem* removeDataMenu;
|
||||||
|
|
||||||
|
AudioGroupFilePresenter* groupFilePresenter;
|
||||||
|
|
||||||
|
SamplesTableController* samplesController;
|
||||||
|
SFXTableController* sfxController;
|
||||||
|
|
||||||
|
@public
|
||||||
|
std::unique_ptr<boo::IAudioVoiceEngine> booEngine;
|
||||||
|
std::experimental::optional<amuse::BooBackendVoiceAllocator> amuseAllocator;
|
||||||
|
std::experimental::optional<amuse::Engine> amuseEngine;
|
||||||
|
std::shared_ptr<amuse::Voice> activeSFXVox;
|
||||||
|
}
|
||||||
|
- (BOOL)importURL:(NSURL*)url;
|
||||||
|
- (void)outlineView:(DataOutlineView*)ov selectionChanged:(id)item;
|
||||||
|
- (void)reloadTables;
|
||||||
|
- (void)startSFX:(int)sfxId;
|
||||||
|
- (void)startSample:(int)sampId;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif // __AMUSE_AUDIOUNIT_CONTAININGAPP_HPP__
|
|
@ -2,30 +2,47 @@
|
||||||
#import <AudioUnit/AudioUnit.h>
|
#import <AudioUnit/AudioUnit.h>
|
||||||
#import <CoreAudioKit/AUViewController.h>
|
#import <CoreAudioKit/AUViewController.h>
|
||||||
#import "AudioUnitViewController.hpp"
|
#import "AudioUnitViewController.hpp"
|
||||||
|
#import "AmuseContainingApp.hpp"
|
||||||
|
#include <amuse/amuse.hpp>
|
||||||
|
|
||||||
@interface MainView : NSView
|
@class DataOutlineController;
|
||||||
|
@class SamplesTableController;
|
||||||
|
@class SFXTableController;
|
||||||
|
|
||||||
|
/* Blocks mousedown events (so button may be used as a visual element only) */
|
||||||
|
@interface InactiveButton : NSButton {}
|
||||||
|
@end
|
||||||
|
@implementation InactiveButton
|
||||||
|
- (void)mouseDown:(NSEvent *)theEvent {}
|
||||||
|
@end
|
||||||
|
|
||||||
|
/* Restricts mousedown to checkbox */
|
||||||
|
@interface RestrictedCheckButton : NSButtonCell {}
|
||||||
|
@end
|
||||||
|
@implementation RestrictedCheckButton
|
||||||
|
- (NSCellHitResult)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView
|
||||||
{
|
{
|
||||||
AudioUnitViewController* amuseVC;
|
NSRect restrictFrame = cellFrame;
|
||||||
|
restrictFrame.size.width = 22;
|
||||||
|
if (NSPointInRect([controlView convertPoint:[event locationInWindow] fromView:nil], restrictFrame))
|
||||||
|
return NSCellHitTrackableArea;
|
||||||
|
return NSCellHitNone;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MainView
|
@implementation DataOutlineView
|
||||||
|
- (id)initWithCoder:(NSCoder *)coder
|
||||||
|
{
|
||||||
|
self = [super initWithCoder:coder];
|
||||||
|
[self registerForDraggedTypes:@[NSURLPboardType]];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
- (id)initWithFrame:(NSRect)frameRect
|
- (id)initWithFrame:(NSRect)frameRect
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:frameRect];
|
self = [super initWithFrame:frameRect];
|
||||||
if (!self)
|
[self registerForDraggedTypes:@[NSURLPboardType]];
|
||||||
return nil;
|
|
||||||
amuseVC = [[AudioUnitViewController alloc] initWithNibName:nil bundle:nil];
|
|
||||||
[self addSubview:amuseVC.view];
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)translatesAutoresizingMaskIntoConstraints
|
|
||||||
{
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface MainTabView : NSTabView
|
@interface MainTabView : NSTabView
|
||||||
|
@ -55,22 +72,153 @@
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
|
||||||
|
@implementation SamplesTableController
|
||||||
|
|
||||||
|
- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView
|
||||||
{
|
{
|
||||||
IBOutlet NSWindow* mainWindow;
|
return presenter->m_sampleTableData.size();
|
||||||
IBOutlet NSOutlineView* dataOutline;
|
|
||||||
IBOutlet NSTableView* sfxTable;
|
|
||||||
IBOutlet NSTableView* samplesTable;
|
|
||||||
IBOutlet NSTextView* creditsView;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSView*)tableView:(NSTableView *)tableView viewForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
|
||||||
|
{
|
||||||
|
if (presenter->m_sampleTableData.size() <= row)
|
||||||
|
return nil;
|
||||||
|
NSTableCellView* view = [tableView makeViewWithIdentifier:@"SampleIDColumn" owner:self];
|
||||||
|
AudioGroupSampleToken* sampToken = presenter->m_sampleTableData[row];
|
||||||
|
if ([tableColumn.identifier isEqualToString:@"SampleIDColumn"])
|
||||||
|
view.textField.attributedStringValue = sampToken->m_name;
|
||||||
|
else if ([tableColumn.identifier isEqualToString:@"SampleDetailsColumn"])
|
||||||
|
view.textField.stringValue = @"";
|
||||||
|
else
|
||||||
|
view.textField.attributedStringValue = sampToken->m_name;
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row
|
||||||
|
{
|
||||||
|
if (presenter->m_sampleTableData.size() <= row)
|
||||||
|
return NO;
|
||||||
|
AudioGroupSampleToken* sampToken = presenter->m_sampleTableData[row];
|
||||||
|
if (!sampToken->m_sample)
|
||||||
|
return YES;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
|
||||||
|
{
|
||||||
|
if (presenter->m_sampleTableData.size() <= row)
|
||||||
|
return NO;
|
||||||
|
AudioGroupSampleToken* sampToken = presenter->m_sampleTableData[row];
|
||||||
|
if (!sampToken->m_sample)
|
||||||
|
return NO;
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithAudioGroupPresenter:(AudioGroupFilePresenter*)present
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
presenter = present;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation SFXTableController
|
||||||
|
|
||||||
|
- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView
|
||||||
|
{
|
||||||
|
return presenter->m_sfxTableData.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSView*)tableView:(NSTableView *)tableView viewForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
|
||||||
|
{
|
||||||
|
if (presenter->m_sfxTableData.size() <= row)
|
||||||
|
return nil;
|
||||||
|
NSTableCellView* view = [tableView makeViewWithIdentifier:@"SFXIDColumn" owner:self];
|
||||||
|
AudioGroupSFXToken* sfxToken = presenter->m_sfxTableData[row];
|
||||||
|
if ([tableColumn.identifier isEqualToString:@"SFXIDColumn"])
|
||||||
|
view.textField.attributedStringValue = sfxToken->m_name;
|
||||||
|
else if ([tableColumn.identifier isEqualToString:@"SFXDetailsColumn"])
|
||||||
|
view.textField.stringValue = @"";
|
||||||
|
else
|
||||||
|
view.textField.attributedStringValue = sfxToken->m_name;
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row
|
||||||
|
{
|
||||||
|
if (presenter->m_sfxTableData.size() <= row)
|
||||||
|
return NO;
|
||||||
|
AudioGroupSFXToken* sfxToken = presenter->m_sfxTableData[row];
|
||||||
|
if (!sfxToken->m_sfx)
|
||||||
|
return YES;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
|
||||||
|
{
|
||||||
|
if (presenter->m_sfxTableData.size() <= row)
|
||||||
|
return NO;
|
||||||
|
AudioGroupSFXToken* sfxToken = presenter->m_sfxTableData[row];
|
||||||
|
if (!sfxToken->m_sfx)
|
||||||
|
return NO;
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tableViewSelectionDidChange:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
NSTableView* table = notification.object;
|
||||||
|
NSInteger row = table.selectedRow;
|
||||||
|
if (presenter->m_sfxTableData.size() <= row)
|
||||||
|
return;
|
||||||
|
AudioGroupSFXToken* sfxToken = presenter->m_sfxTableData[row];
|
||||||
|
AppDelegate* delegate = (AppDelegate*)NSApp.delegate;
|
||||||
|
[delegate startSFX:sfxToken->m_loadId];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithAudioGroupPresenter:(AudioGroupFilePresenter*)present
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
presenter = present;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
|
|
||||||
- (void)applicationDidFinishLaunching:(NSNotification*)notification
|
- (void)applicationWillFinishLaunching:(NSNotification*)notification
|
||||||
{
|
{
|
||||||
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints"];
|
booEngine = boo::NewAudioVoiceEngine();
|
||||||
|
amuseAllocator.emplace(*booEngine);
|
||||||
|
amuseEngine.emplace(*amuseAllocator);
|
||||||
|
|
||||||
[mainWindow.toolbar setSelectedItemIdentifier:@"DataTab"];
|
[mainWindow.toolbar setSelectedItemIdentifier:@"DataTab"];
|
||||||
|
|
||||||
|
groupFilePresenter = [[AudioGroupFilePresenter alloc] initWithAudioGroupClient:self];
|
||||||
|
|
||||||
|
dataOutline.dataSource = groupFilePresenter;
|
||||||
|
dataOutline.delegate = groupFilePresenter;
|
||||||
|
[dataOutline reloadItem:nil reloadChildren:YES];
|
||||||
|
|
||||||
|
samplesController = [[SamplesTableController alloc] initWithAudioGroupPresenter:groupFilePresenter];
|
||||||
|
samplesTable.dataSource = samplesController;
|
||||||
|
samplesTable.delegate = samplesController;
|
||||||
|
[samplesTable reloadData];
|
||||||
|
|
||||||
|
sfxController = [[SFXTableController alloc] initWithAudioGroupPresenter:groupFilePresenter];
|
||||||
|
sfxTable.dataSource = sfxController;
|
||||||
|
sfxTable.delegate = sfxController;
|
||||||
|
[sfxTable reloadData];
|
||||||
|
|
||||||
|
[NSTimer scheduledTimerWithTimeInterval:1.0 / 60.0 target:self selector:@selector(pumpTimer:) userInfo:nil repeats:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)pumpTimer:(NSTimer*)timer
|
||||||
|
{
|
||||||
|
amuseEngine->pumpEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
|
||||||
|
@ -78,9 +226,88 @@
|
||||||
return YES;
|
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));
|
||||||
|
if (containerType == amuse::ContainerRegistry::Type::Raw4)
|
||||||
|
name = url.URLByDeletingPathExtension.lastPathComponent.UTF8String;
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startSFX:(int)sfxId
|
||||||
|
{
|
||||||
|
if (activeSFXVox)
|
||||||
|
activeSFXVox->keyOff();
|
||||||
|
activeSFXVox = amuseEngine->fxStart(sfxId, 1.f, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startSample:(int)sampleId
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadTables
|
||||||
|
{
|
||||||
|
[sfxTable reloadData];
|
||||||
|
[samplesTable reloadData];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)filterDataOutline:(id)sender
|
||||||
|
{
|
||||||
|
[groupFilePresenter setSearchFilter:[sender stringValue]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)removeDataItem:(id)sender
|
||||||
|
{
|
||||||
|
[groupFilePresenter removeSelectedItem];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)outlineView:(DataOutlineView *)ov selectionChanged:(id)item
|
||||||
|
{
|
||||||
|
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
|
{
|
||||||
|
removeDataButton.enabled = TRUE;
|
||||||
|
removeDataMenu.enabled = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
removeDataButton.enabled = FALSE;
|
||||||
|
removeDataMenu.enabled = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename
|
||||||
|
{
|
||||||
|
NSURL* url = [NSURL fileURLWithPath:filename isDirectory:NO];
|
||||||
|
return [self importURL:url];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (amuse::Engine&)getAmuseEngine
|
||||||
|
{
|
||||||
|
return *amuseEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -2,36 +2,158 @@
|
||||||
#define __AMUSE_AUDIOUNIT_AUDIOGROUPFILEPRESENTER_HPP__
|
#define __AMUSE_AUDIOUNIT_AUDIOGROUPFILEPRESENTER_HPP__
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "optional.hpp"
|
||||||
|
#include <amuse/amuse.hpp>
|
||||||
|
#include <athena/FileReader.hpp>
|
||||||
|
|
||||||
@class AudioGroupFilePresenter;
|
@class AudioGroupFilePresenter;
|
||||||
|
@class AudioGroupDataToken;
|
||||||
|
@class AudioGroupCollectionToken;
|
||||||
|
@class AudioGroupSFXToken;
|
||||||
|
@class AudioGroupSampleToken;
|
||||||
|
@class AudioGroupToken;
|
||||||
|
|
||||||
|
@protocol AudioGroupClient
|
||||||
|
- (amuse::Engine&)getAmuseEngine;
|
||||||
|
@end
|
||||||
|
|
||||||
struct AudioGroupDataCollection
|
struct AudioGroupDataCollection
|
||||||
{
|
{
|
||||||
NSURL* m_proj = nullptr; /* Only this member set for single-file containers */
|
std::string m_name;
|
||||||
NSURL* m_pool = nullptr;
|
NSURL* m_proj;
|
||||||
NSURL* m_sdir = nullptr;
|
NSURL* m_pool;
|
||||||
NSURL* m_samp = nullptr;
|
NSURL* m_sdir;
|
||||||
|
NSURL* m_samp;
|
||||||
|
NSURL* m_meta;
|
||||||
|
|
||||||
|
AudioGroupDataToken* m_token;
|
||||||
|
|
||||||
|
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.readUint32Little())), absOffs(r.readUint32Little()), active(r.readUint32Little()) {}
|
||||||
|
};
|
||||||
|
std::experimental::optional<MetaData> m_metaData;
|
||||||
|
|
||||||
|
std::experimental::optional<amuse::AudioGroupData> m_loadedData;
|
||||||
|
const amuse::AudioGroup* m_loadedGroup;
|
||||||
|
std::vector<AudioGroupToken*> m_groupTokens;
|
||||||
|
|
||||||
bool invalidateURL(NSURL* url);
|
|
||||||
void moveURL(NSURL* oldUrl, NSURL* newUrl);
|
void moveURL(NSURL* oldUrl, NSURL* newUrl);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> _coordinateRead(AudioGroupFilePresenter* presenter, size_t& szOut, NSURL* url);
|
bool loadProj(AudioGroupFilePresenter* presenter);
|
||||||
|
bool loadPool(AudioGroupFilePresenter* presenter);
|
||||||
|
bool loadSdir(AudioGroupFilePresenter* presenter);
|
||||||
|
bool loadSamp(AudioGroupFilePresenter* presenter);
|
||||||
|
bool loadMeta(AudioGroupFilePresenter* presenter);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> coordinateProjRead(AudioGroupFilePresenter* presenter, size_t& szOut);
|
AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp, NSURL* meta);
|
||||||
std::unique_ptr<uint8_t[]> coordinatePoolRead(AudioGroupFilePresenter* presenter, size_t& szOut);
|
bool isDataComplete() const {return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;}
|
||||||
std::unique_ptr<uint8_t[]> coordinateSdirRead(AudioGroupFilePresenter* presenter, size_t& szOut);
|
bool _attemptLoad(AudioGroupFilePresenter* presenter);
|
||||||
std::unique_ptr<uint8_t[]> coordinateSampRead(AudioGroupFilePresenter* presenter, size_t& szOut);
|
bool _indexData(AudioGroupFilePresenter* presenter);
|
||||||
|
|
||||||
|
void enable(AudioGroupFilePresenter* presenter);
|
||||||
|
void disable(AudioGroupFilePresenter* presenter);
|
||||||
};
|
};
|
||||||
|
|
||||||
@interface AudioGroupFilePresenter : NSObject <NSFilePresenter>
|
struct AudioGroupCollection
|
||||||
{
|
{
|
||||||
NSURL* m_groupURL;
|
NSURL* m_url;
|
||||||
NSOperationQueue* m_dataQueue;
|
|
||||||
std::map<std::string, AudioGroupDataCollection> m_audioGroupCollections;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
AudioGroupCollectionToken* m_token;
|
||||||
|
std::map<std::string, std::unique_ptr<AudioGroupDataCollection>> m_groups;
|
||||||
|
std::vector<std::map<std::string, std::unique_ptr<AudioGroupDataCollection>>::iterator> m_filterGroups;
|
||||||
|
|
||||||
|
AudioGroupCollection(NSURL* url);
|
||||||
|
void addCollection(AudioGroupFilePresenter* presenter,
|
||||||
|
std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||||
|
void update(AudioGroupFilePresenter* presenter);
|
||||||
|
bool doSearch(const std::string& str);
|
||||||
|
bool doActiveFilter();
|
||||||
|
void addSFX(std::vector<AudioGroupSFXToken*>& vecOut);
|
||||||
|
void addSamples(std::vector<AudioGroupSampleToken*>& vecOut);
|
||||||
|
};
|
||||||
|
|
||||||
|
@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 AudioGroupSFXToken : NSObject
|
||||||
|
{
|
||||||
|
@public
|
||||||
|
NSAttributedString* m_name;
|
||||||
|
int m_loadId;
|
||||||
|
const amuse::SFXGroupIndex::SFXEntry* m_sfx;
|
||||||
|
}
|
||||||
|
- (id)initWithName:(NSAttributedString*)name loadId:(int)loadId sfx:(const amuse::SFXGroupIndex::SFXEntry*)sfx;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface AudioGroupSampleToken : NSObject
|
||||||
|
{
|
||||||
|
@public
|
||||||
|
NSAttributedString* m_name;
|
||||||
|
const std::pair<amuse::AudioGroupSampleDirectory::Entry, amuse::AudioGroupSampleDirectory::ADPCMParms>* m_sample;
|
||||||
|
}
|
||||||
|
- (id)initWithName:(NSAttributedString*)name samp:(const std::pair<amuse::AudioGroupSampleDirectory::Entry,
|
||||||
|
amuse::AudioGroupSampleDirectory::ADPCMParms>*)sample;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface AudioGroupToken : NSObject
|
||||||
|
{
|
||||||
|
@public
|
||||||
|
NSString* m_name;
|
||||||
|
int m_id;
|
||||||
|
const amuse::SongGroupIndex* m_song;
|
||||||
|
const amuse::SFXGroupIndex* m_sfx;
|
||||||
|
}
|
||||||
|
- (id)initWithName:(NSString*)name id:(int)gid songGroup:(const amuse::SongGroupIndex*)group;
|
||||||
|
- (id)initWithName:(NSString*)name id:(int)gid sfxGroup:(const amuse::SFXGroupIndex*)group;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface AudioGroupFilePresenter : NSObject <NSFilePresenter, NSOutlineViewDataSource, NSOutlineViewDelegate>
|
||||||
|
{
|
||||||
|
@public
|
||||||
|
id<AudioGroupClient> m_audioGroupClient;
|
||||||
|
NSURL* m_groupURL;
|
||||||
|
std::map<std::string, std::unique_ptr<AudioGroupCollection>> m_audioGroupCollections;
|
||||||
|
std::vector<std::map<std::string, std::unique_ptr<AudioGroupCollection>>::iterator> m_filterAudioGroupCollections;
|
||||||
|
NSOutlineView* m_lastOutlineView;
|
||||||
|
NSString* m_searchStr;
|
||||||
|
|
||||||
|
std::vector<AudioGroupSFXToken*> m_sfxTableData;
|
||||||
|
std::vector<AudioGroupSampleToken*> m_sampleTableData;
|
||||||
|
}
|
||||||
|
- (id)initWithAudioGroupClient:(id<AudioGroupClient>)client;
|
||||||
|
- (BOOL)addCollectionName:(std::string&&)name items:(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&&)collection;
|
||||||
|
- (void)update;
|
||||||
|
- (void)resetIterators;
|
||||||
|
- (void)setSearchFilter:(NSString*)str;
|
||||||
|
- (void)removeSelectedItem;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif // __AMUSE_AUDIOUNIT_AUDIOGROUPFILEPRESENTER_HPP__
|
#endif // __AMUSE_AUDIOUNIT_AUDIOGROUPFILEPRESENTER_HPP__
|
||||||
|
|
|
@ -1,5 +1,75 @@
|
||||||
#include "AudioGroupFilePresenter.hpp"
|
#include "AudioGroupFilePresenter.hpp"
|
||||||
#include <athena/FileReader.hpp>
|
#include <athena/FileReader.hpp>
|
||||||
|
#include <amuse/AudioGroupProject.hpp>
|
||||||
|
#import "AmuseContainingApp.hpp"
|
||||||
|
#import "AudioUnitBackend.hpp"
|
||||||
|
#import "AudioUnitViewController.hpp"
|
||||||
|
|
||||||
|
static std::string StrToLower(const std::string& str)
|
||||||
|
{
|
||||||
|
std::string ret = str;
|
||||||
|
std::transform(ret.begin(), ret.end(), ret.begin(), tolower);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 AudioGroupSFXToken
|
||||||
|
- (id)initWithName:(NSAttributedString*)name loadId:(int)loadId sfx:(const amuse::SFXGroupIndex::SFXEntry*)sfx
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
m_name = name;
|
||||||
|
m_loadId = loadId;
|
||||||
|
m_sfx = sfx;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation AudioGroupSampleToken
|
||||||
|
- (id)initWithName:(NSAttributedString*)name samp:(const std::pair<amuse::AudioGroupSampleDirectory::Entry,
|
||||||
|
amuse::AudioGroupSampleDirectory::ADPCMParms>*)sample
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
m_name = name;
|
||||||
|
m_sample = sample;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation AudioGroupToken
|
||||||
|
- (id)initWithName:(NSString*)name id:(int)gid songGroup:(const amuse::SongGroupIndex*)group
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
m_name = name;
|
||||||
|
m_song = group;
|
||||||
|
m_id = gid;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (id)initWithName:(NSString*)name id:(int)gid sfxGroup:(const amuse::SFXGroupIndex*)group
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
m_name = name;
|
||||||
|
m_sfx = group;
|
||||||
|
m_id = gid;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation AudioGroupFilePresenter
|
@implementation AudioGroupFilePresenter
|
||||||
|
|
||||||
|
@ -10,37 +80,286 @@
|
||||||
|
|
||||||
- (NSOperationQueue*)presentedItemOperationQueue
|
- (NSOperationQueue*)presentedItemOperationQueue
|
||||||
{
|
{
|
||||||
return m_dataQueue;
|
return [NSOperationQueue mainQueue];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioGroupDataCollection::invalidateURL(NSURL* url)
|
AudioGroupCollection::AudioGroupCollection(NSURL* url)
|
||||||
|
: m_url(url), m_token([[AudioGroupCollectionToken alloc] initWithCollection:this]) {}
|
||||||
|
|
||||||
|
void AudioGroupCollection::addCollection(AudioGroupFilePresenter* presenter,
|
||||||
|
std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection)
|
||||||
{
|
{
|
||||||
bool valid = false;
|
for (std::pair<std::string, amuse::IntrusiveAudioGroupData>& pair : collection)
|
||||||
if (m_proj)
|
|
||||||
{
|
{
|
||||||
if ([m_proj isEqual:url])
|
NSURL* collectionUrl = [m_url URLByAppendingPathComponent:@(pair.first.c_str())];
|
||||||
m_proj = nullptr;
|
|
||||||
valid |= m_proj != nullptr;
|
amuse::IntrusiveAudioGroupData& dataIn = pair.second;
|
||||||
|
auto search = m_groups.find(pair.first);
|
||||||
|
if (search == m_groups.end())
|
||||||
|
{
|
||||||
|
search = m_groups.emplace(pair.first,
|
||||||
|
std::make_unique<AudioGroupDataCollection>(pair.first,
|
||||||
|
[collectionUrl URLByAppendingPathComponent:@"proj"],
|
||||||
|
[collectionUrl URLByAppendingPathComponent:@"pool"],
|
||||||
|
[collectionUrl URLByAppendingPathComponent:@"sdir"],
|
||||||
|
[collectionUrl URLByAppendingPathComponent:@"samp"],
|
||||||
|
[collectionUrl URLByAppendingPathComponent:@"meta"])).first;
|
||||||
}
|
}
|
||||||
if (m_pool)
|
|
||||||
{
|
AudioGroupDataCollection& dataCollection = *search->second;
|
||||||
if ([m_pool isEqual:url])
|
dataCollection.m_projData.resize(dataIn.getProjSize());
|
||||||
m_pool = nullptr;
|
memmove(dataCollection.m_projData.data(), dataIn.getProj(), dataIn.getProjSize());
|
||||||
valid |= m_pool != nullptr;
|
|
||||||
|
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);
|
||||||
|
dataCollection._indexData(presenter);
|
||||||
}
|
}
|
||||||
if (m_sdir)
|
|
||||||
{
|
|
||||||
if ([m_sdir isEqual:url])
|
|
||||||
m_sdir = nullptr;
|
|
||||||
valid |= m_sdir != nullptr;
|
|
||||||
}
|
}
|
||||||
if (m_samp)
|
|
||||||
|
void AudioGroupCollection::update(AudioGroupFilePresenter* presenter)
|
||||||
{
|
{
|
||||||
if ([m_samp isEqual:url])
|
NSFileManager* fman = [NSFileManager defaultManager];
|
||||||
m_samp = nullptr;
|
NSArray<NSURL*>* contents =
|
||||||
valid |= m_samp != nullptr;
|
[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,
|
||||||
|
std::make_unique<AudioGroupDataCollection>(nameStr,
|
||||||
|
[path URLByAppendingPathComponent:@"proj"],
|
||||||
|
[path URLByAppendingPathComponent:@"pool"],
|
||||||
|
[path URLByAppendingPathComponent:@"sdir"],
|
||||||
|
[path URLByAppendingPathComponent:@"samp"],
|
||||||
|
[path URLByAppendingPathComponent:@"meta"])).first;
|
||||||
|
search->second->_attemptLoad(presenter);
|
||||||
}
|
}
|
||||||
return valid;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioGroupCollection::doSearch(const std::string& str)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
m_filterGroups.clear();
|
||||||
|
m_filterGroups.reserve(m_groups.size());
|
||||||
|
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
||||||
|
if (str.empty() || StrToLower(it->first).find(str) != std::string::npos)
|
||||||
|
{
|
||||||
|
m_filterGroups.push_back(it);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioGroupCollection::doActiveFilter()
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
m_filterGroups.clear();
|
||||||
|
m_filterGroups.reserve(m_groups.size());
|
||||||
|
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
||||||
|
if (it->second->m_metaData->active)
|
||||||
|
{
|
||||||
|
m_filterGroups.push_back(it);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupCollection::addSFX(std::vector<AudioGroupSFXToken*>& vecOut)
|
||||||
|
{
|
||||||
|
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
||||||
|
{
|
||||||
|
if (!it->second->m_metaData->active)
|
||||||
|
continue;
|
||||||
|
const auto& sfxGroups = it->second->m_loadedGroup->getProj().sfxGroups();
|
||||||
|
std::map<int, const amuse::SFXGroupIndex*> sortGroups;
|
||||||
|
for (const auto& pair : sfxGroups)
|
||||||
|
sortGroups[pair.first] = &pair.second;
|
||||||
|
for (const auto& pair : sortGroups)
|
||||||
|
{
|
||||||
|
NSMutableAttributedString* name = [[NSMutableAttributedString alloc] initWithString:m_url.lastPathComponent attributes:@{NSForegroundColorAttributeName: [NSColor grayColor]}];
|
||||||
|
[name appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" %s (%d)", it->first.c_str(), pair.first]]];
|
||||||
|
vecOut.push_back([[AudioGroupSFXToken alloc] initWithName:name loadId:0 sfx:nil]);
|
||||||
|
std::map<int, const amuse::SFXGroupIndex::SFXEntry*> sortSfx;
|
||||||
|
for (const auto& pair : pair.second->m_sfxEntries)
|
||||||
|
sortSfx[pair.first] = pair.second;
|
||||||
|
for (const auto& sfx : sortSfx)
|
||||||
|
{
|
||||||
|
name = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%d", sfx.first]];
|
||||||
|
vecOut.push_back([[AudioGroupSFXToken alloc] initWithName:name loadId:sfx.first sfx:sfx.second]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupCollection::addSamples(std::vector<AudioGroupSampleToken*>& vecOut)
|
||||||
|
{
|
||||||
|
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
||||||
|
{
|
||||||
|
if (!it->second->m_metaData->active)
|
||||||
|
continue;
|
||||||
|
const auto& samps = it->second->m_loadedGroup->getSdir().sampleEntries();
|
||||||
|
std::map<int, const std::pair<amuse::AudioGroupSampleDirectory::Entry, amuse::AudioGroupSampleDirectory::ADPCMParms>*> sortSamps;
|
||||||
|
for (const auto& pair : samps)
|
||||||
|
sortSamps[pair.first] = &pair.second;
|
||||||
|
|
||||||
|
NSMutableAttributedString* name = [[NSMutableAttributedString alloc] initWithString:m_url.lastPathComponent attributes:@{NSForegroundColorAttributeName: [NSColor grayColor]}];
|
||||||
|
[name appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" %s", it->first.c_str()]]];
|
||||||
|
vecOut.push_back([[AudioGroupSampleToken alloc] initWithName:name samp:nil]);
|
||||||
|
|
||||||
|
for (const auto& pair : sortSamps)
|
||||||
|
{
|
||||||
|
name = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%d", pair.first]];
|
||||||
|
vecOut.push_back([[AudioGroupSampleToken alloc] initWithName:name samp:pair.second]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (m_metaData && m_loadedData && m_loadedGroup)
|
||||||
|
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;
|
||||||
|
|
||||||
|
return _indexData(presenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioGroupDataCollection::_indexData(AudioGroupFilePresenter* presenter)
|
||||||
|
{
|
||||||
|
amuse::Engine& engine = [presenter->m_audioGroupClient getAmuseEngine];
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_loadedGroup = engine.addAudioGroup(*m_loadedData);
|
||||||
|
m_groupTokens.clear();
|
||||||
|
if (m_loadedGroup)
|
||||||
|
{
|
||||||
|
m_groupTokens.reserve(m_loadedGroup->getProj().songGroups().size() +
|
||||||
|
m_loadedGroup->getProj().sfxGroups().size());
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto& songGroups = m_loadedGroup->getProj().songGroups();
|
||||||
|
std::map<int, const amuse::SongGroupIndex*> sortGroups;
|
||||||
|
for (const auto& pair : songGroups)
|
||||||
|
sortGroups[pair.first] = &pair.second;
|
||||||
|
for (const auto& pair : sortGroups)
|
||||||
|
{
|
||||||
|
NSString* name = [NSString stringWithFormat:@"%d", pair.first];
|
||||||
|
m_groupTokens.push_back([[AudioGroupToken alloc] initWithName:name id:pair.first
|
||||||
|
songGroup:pair.second]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto& sfxGroups = m_loadedGroup->getProj().sfxGroups();
|
||||||
|
std::map<int, const amuse::SFXGroupIndex*> sortGroups;
|
||||||
|
for (const auto& pair : sfxGroups)
|
||||||
|
sortGroups[pair.first] = &pair.second;
|
||||||
|
for (const auto& pair : sortGroups)
|
||||||
|
{
|
||||||
|
NSString* name = [NSString stringWithFormat:@"%d", pair.first];
|
||||||
|
m_groupTokens.push_back([[AudioGroupToken alloc] initWithName:name id:pair.first
|
||||||
|
sfxGroup:pair.second]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_loadedData && m_loadedGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupDataCollection::enable(AudioGroupFilePresenter* presenter)
|
||||||
|
{
|
||||||
|
m_metaData->active = true;
|
||||||
|
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter];
|
||||||
|
|
||||||
|
[coord coordinateWritingItemAtURL:m_meta options:0 error:nil
|
||||||
|
byAccessor:^(NSURL* newUrl)
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(newUrl.path.UTF8String, "wb");
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
fwrite(&*m_metaData, 1, sizeof(*m_metaData), fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupDataCollection::disable(AudioGroupFilePresenter* presenter)
|
||||||
|
{
|
||||||
|
m_metaData->active = false;
|
||||||
|
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter];
|
||||||
|
|
||||||
|
[coord coordinateWritingItemAtURL:m_meta options:0 error:nil
|
||||||
|
byAccessor:^(NSURL* newUrl)
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(newUrl.path.UTF8String, "wb");
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
fwrite(&*m_metaData, 1, sizeof(*m_metaData), fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioGroupDataCollection::moveURL(NSURL* oldUrl, NSURL* newUrl)
|
void AudioGroupDataCollection::moveURL(NSURL* oldUrl, NSURL* newUrl)
|
||||||
|
@ -67,119 +386,474 @@ void AudioGroupDataCollection::moveURL(NSURL* oldUrl, NSURL* newUrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> AudioGroupDataCollection::_coordinateRead(AudioGroupFilePresenter* presenter, size_t& szOut, NSURL* url)
|
bool AudioGroupDataCollection::loadProj(AudioGroupFilePresenter* presenter)
|
||||||
{
|
{
|
||||||
|
if (!m_proj)
|
||||||
|
return false;
|
||||||
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter];
|
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter];
|
||||||
if (!coord)
|
if (!coord)
|
||||||
return {};
|
return false;
|
||||||
NSError* err;
|
NSError* err;
|
||||||
__block std::unique_ptr<uint8_t[]> ret;
|
__block std::vector<uint8_t>& ret = m_projData;
|
||||||
__block size_t retSz = 0;
|
[coord coordinateReadingItemAtURL:m_proj
|
||||||
[coord coordinateReadingItemAtURL:url options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err
|
options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err
|
||||||
byAccessor:^(NSURL* newUrl)
|
byAccessor:^(NSURL* newUrl)
|
||||||
{
|
{
|
||||||
athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false);
|
athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false);
|
||||||
if (r.hasError())
|
if (r.hasError())
|
||||||
return;
|
return;
|
||||||
retSz = r.length();
|
size_t len = r.length();
|
||||||
ret = r.readUBytes(retSz);
|
ret.resize(len);
|
||||||
|
r.readUBytesToBuf(ret.data(), len);
|
||||||
}];
|
}];
|
||||||
szOut = retSz;
|
return ret.size();
|
||||||
return std::move(ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> AudioGroupDataCollection::coordinateProjRead(AudioGroupFilePresenter* presenter, size_t& szOut)
|
bool AudioGroupDataCollection::loadPool(AudioGroupFilePresenter* presenter)
|
||||||
{
|
|
||||||
if (!m_proj)
|
|
||||||
return {};
|
|
||||||
return _coordinateRead(presenter, szOut, m_proj);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> AudioGroupDataCollection::coordinatePoolRead(AudioGroupFilePresenter* presenter, size_t& szOut)
|
|
||||||
{
|
{
|
||||||
if (!m_pool)
|
if (!m_pool)
|
||||||
return {};
|
return false;
|
||||||
return _coordinateRead(presenter, szOut, m_pool);
|
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter];
|
||||||
|
if (!coord)
|
||||||
|
return false;
|
||||||
|
NSError* err;
|
||||||
|
__block std::vector<uint8_t>& ret = m_poolData;
|
||||||
|
[coord coordinateReadingItemAtURL:m_pool
|
||||||
|
options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err
|
||||||
|
byAccessor:^(NSURL* newUrl)
|
||||||
|
{
|
||||||
|
athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false);
|
||||||
|
if (r.hasError())
|
||||||
|
return;
|
||||||
|
size_t len = r.length();
|
||||||
|
ret.resize(len);
|
||||||
|
r.readUBytesToBuf(ret.data(), len);
|
||||||
|
}];
|
||||||
|
return ret.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> AudioGroupDataCollection::coordinateSdirRead(AudioGroupFilePresenter* presenter, size_t& szOut)
|
bool AudioGroupDataCollection::loadSdir(AudioGroupFilePresenter* presenter)
|
||||||
{
|
{
|
||||||
if (!m_sdir)
|
if (!m_sdir)
|
||||||
return {};
|
return false;
|
||||||
return _coordinateRead(presenter, szOut, m_sdir);
|
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter];
|
||||||
|
if (!coord)
|
||||||
|
return false;
|
||||||
|
NSError* err;
|
||||||
|
__block std::vector<uint8_t>& ret = m_sdirData;
|
||||||
|
[coord coordinateReadingItemAtURL:m_sdir
|
||||||
|
options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err
|
||||||
|
byAccessor:^(NSURL* newUrl)
|
||||||
|
{
|
||||||
|
athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false);
|
||||||
|
if (r.hasError())
|
||||||
|
return;
|
||||||
|
size_t len = r.length();
|
||||||
|
ret.resize(len);
|
||||||
|
r.readUBytesToBuf(ret.data(), len);
|
||||||
|
}];
|
||||||
|
return ret.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> AudioGroupDataCollection::coordinateSampRead(AudioGroupFilePresenter* presenter, size_t& szOut)
|
bool AudioGroupDataCollection::loadSamp(AudioGroupFilePresenter* presenter)
|
||||||
{
|
{
|
||||||
if (!m_samp)
|
if (!m_samp)
|
||||||
return {};
|
return false;
|
||||||
return _coordinateRead(presenter, szOut, m_samp);
|
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter];
|
||||||
}
|
if (!coord)
|
||||||
|
return false;
|
||||||
- (void)accommodatePresentedSubitemDeletionAtURL:(NSURL*)url completionHandler:(void (^)(NSError* errorOrNil))completionHandler
|
NSError* err;
|
||||||
|
__block std::vector<uint8_t>& ret = m_sampData;
|
||||||
|
[coord coordinateReadingItemAtURL:m_samp
|
||||||
|
options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err
|
||||||
|
byAccessor:^(NSURL* newUrl)
|
||||||
{
|
{
|
||||||
for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ;)
|
athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false);
|
||||||
{
|
if (r.hasError())
|
||||||
std::pair<const std::string, AudioGroupDataCollection>& pair = *it;
|
|
||||||
if (pair.second.invalidateURL(url))
|
|
||||||
{
|
|
||||||
it = m_audioGroupCollections.erase(it);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
completionHandler(nil);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)presentedSubitemDidAppearAtURL:(NSURL*)url
|
|
||||||
{
|
|
||||||
NSString* path = [url path];
|
|
||||||
if (!path)
|
|
||||||
return;
|
return;
|
||||||
|
size_t len = r.length();
|
||||||
|
ret.resize(len);
|
||||||
|
r.readUBytesToBuf(ret.data(), len);
|
||||||
|
}];
|
||||||
|
return ret.size();
|
||||||
|
}
|
||||||
|
|
||||||
NSString* extension = [url pathExtension];
|
bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
||||||
NSString* lastComp = [url lastPathComponent];
|
{
|
||||||
lastComp = [lastComp substringToIndex:[lastComp length] - [extension length]];
|
if (!m_meta)
|
||||||
AudioGroupDataCollection& collection = m_audioGroupCollections[[lastComp UTF8String]];
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
if ([extension isEqualToString:@"pro"] || [extension isEqualToString:@"proj"])
|
- (void)presentedSubitemDidChangeAtURL:(NSURL *)url
|
||||||
{
|
{
|
||||||
collection.m_proj = url;
|
size_t relComps = url.pathComponents.count - m_groupURL.pathComponents.count;
|
||||||
}
|
if (relComps <= 1)
|
||||||
else if ([extension isEqualToString:@"poo"] || [extension isEqualToString:@"pool"])
|
[self update];
|
||||||
{
|
|
||||||
collection.m_pool = url;
|
|
||||||
}
|
|
||||||
else if ([extension isEqualToString:@"sdi"] || [extension isEqualToString:@"sdir"])
|
|
||||||
{
|
|
||||||
collection.m_sdir = url;
|
|
||||||
}
|
|
||||||
else if ([extension isEqualToString:@"sam"] || [extension isEqualToString:@"samp"])
|
|
||||||
{
|
|
||||||
collection.m_samp = url;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
collection.m_proj = url;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)presentedSubitemAtURL:(NSURL*)oldUrl didMoveToURL:(NSURL*)newUrl
|
- (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;
|
for (auto& pair2 : pair.second->m_groups)
|
||||||
pair.second.moveURL(oldUrl, newUrl);
|
{
|
||||||
|
pair2.second->moveURL(oldUrl, newUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (NSInteger)outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(nullable id)item
|
||||||
{
|
{
|
||||||
|
m_lastOutlineView = outlineView;
|
||||||
|
if (!item)
|
||||||
|
return m_filterAudioGroupCollections.size();
|
||||||
|
|
||||||
|
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||||
|
return collection.m_filterGroups.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(nullable id)item
|
||||||
|
{
|
||||||
|
if (!item)
|
||||||
|
{
|
||||||
|
if (index >= m_filterAudioGroupCollections.size())
|
||||||
|
return nil;
|
||||||
|
return m_filterAudioGroupCollections[index]->second->m_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||||
|
if (index >= collection.m_filterGroups.size())
|
||||||
|
return nil;
|
||||||
|
return collection.m_filterGroups[index]->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"])
|
||||||
|
{
|
||||||
|
size_t totalOn = 0;
|
||||||
|
for (auto& pair : collection.m_groups)
|
||||||
|
if (pair.second->m_metaData->active)
|
||||||
|
++totalOn;
|
||||||
|
if (totalOn == 0)
|
||||||
|
return [NSNumber numberWithInt:NSOffState];
|
||||||
|
else if (totalOn == collection.m_groups.size())
|
||||||
|
return [NSNumber numberWithInt:NSOnState];
|
||||||
|
else
|
||||||
|
return [NSNumber numberWithInt:NSMixedState];
|
||||||
|
}
|
||||||
|
else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"])
|
||||||
|
return [NSString stringWithFormat:@"%zu Group File%s",
|
||||||
|
collection.m_groups.size(),
|
||||||
|
collection.m_groups.size() > 1 ? "s" : ""];
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass:[AudioGroupDataToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupDataCollection& data = *((AudioGroupDataToken*)item)->m_collection;
|
||||||
|
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
||||||
|
return [NSNumber numberWithInt:data.m_metaData->active ? NSOnState : NSOffState];
|
||||||
|
else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"])
|
||||||
|
{
|
||||||
|
if (!data.m_loadedGroup)
|
||||||
|
return @"";
|
||||||
|
if (data.m_loadedGroup->getProj().songGroups().size() && data.m_loadedGroup->getProj().sfxGroups().size())
|
||||||
|
return [NSString stringWithFormat:@"%zu Song Group%s, %zu SFX Group%s",
|
||||||
|
data.m_loadedGroup->getProj().songGroups().size(),
|
||||||
|
data.m_loadedGroup->getProj().songGroups().size() > 1 ? "s" : "",
|
||||||
|
data.m_loadedGroup->getProj().sfxGroups().size(),
|
||||||
|
data.m_loadedGroup->getProj().sfxGroups().size() > 1 ? "s" : ""];
|
||||||
|
else if (data.m_loadedGroup->getProj().songGroups().size())
|
||||||
|
return [NSString stringWithFormat:@"%zu Song Group%s",
|
||||||
|
data.m_loadedGroup->getProj().songGroups().size(),
|
||||||
|
data.m_loadedGroup->getProj().songGroups().size() > 1 ? "s" : ""];
|
||||||
|
else if (data.m_loadedGroup->getProj().sfxGroups().size())
|
||||||
|
return [NSString stringWithFormat:@"%zu SFX Group%s",
|
||||||
|
data.m_loadedGroup->getProj().sfxGroups().size(),
|
||||||
|
data.m_loadedGroup->getProj().sfxGroups().size() > 1 ? "s" : ""];
|
||||||
|
else
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(nullable id)object forTableColumn:(nullable NSTableColumn *)tableColumn byItem:(nullable id)item
|
||||||
|
{
|
||||||
|
bool dirty = false;
|
||||||
|
|
||||||
|
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||||
|
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
||||||
|
{
|
||||||
|
NSInteger active = [object integerValue];
|
||||||
|
if (active)
|
||||||
|
for (auto& pair : collection.m_groups)
|
||||||
|
pair.second->enable(self);
|
||||||
|
else
|
||||||
|
for (auto& pair : collection.m_groups)
|
||||||
|
pair.second->disable(self);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass:[AudioGroupDataToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupDataCollection& data = *((AudioGroupDataToken*)item)->m_collection;
|
||||||
|
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
||||||
|
{
|
||||||
|
NSInteger active = [object integerValue];
|
||||||
|
if (active)
|
||||||
|
data.enable(self);
|
||||||
|
else
|
||||||
|
data.disable(self);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirty)
|
||||||
|
[self resetIterators];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)outlineViewSelectionDidChange:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
DataOutlineView* ov = notification.object;
|
||||||
|
id item = [ov itemAtRow:ov.selectedRow];
|
||||||
|
[(AppDelegate*)NSApp.delegate outlineView:ov selectionChanged:item];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id<NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
|
||||||
|
{
|
||||||
|
[outlineView setDropItem:nil dropChildIndex:NSOutlineViewDropOnItemIndex];
|
||||||
|
NSPasteboard* pboard = [info draggingPasteboard];
|
||||||
|
if ([[pboard types] containsObject:NSURLPboardType])
|
||||||
|
return NSDragOperationCopy;
|
||||||
|
return NSDragOperationNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id<NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index
|
||||||
|
{
|
||||||
|
NSPasteboard* pboard = [info draggingPasteboard];
|
||||||
|
if ([[pboard types] containsObject:NSURLPboardType])
|
||||||
|
{
|
||||||
|
NSURL* url = [NSURL URLFromPasteboard:pboard];
|
||||||
|
[(AppDelegate*)NSApp.delegate importURL:url];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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, std::make_unique<AudioGroupCollection>(dir)).first->second;
|
||||||
|
insert.addCollection(self, std::move(collection));
|
||||||
|
|
||||||
|
[coord coordinateWritingItemAtURL:m_groupURL options:0 error:nil
|
||||||
|
byAccessor:^(NSURL* newUrl)
|
||||||
|
{
|
||||||
|
for (std::pair<const std::string, std::unique_ptr<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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[self resetIterators];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)update
|
||||||
|
{
|
||||||
|
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:self];
|
||||||
|
if (!coord)
|
||||||
|
return;
|
||||||
|
NSError* coordErr;
|
||||||
|
__block NSError* managerErr;
|
||||||
|
__block std::map<std::string, std::unique_ptr<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;
|
||||||
|
|
||||||
|
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, std::make_unique<AudioGroupCollection>(path)).first;
|
||||||
|
search->second->update(presenter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[self resetIterators];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resetIterators
|
||||||
|
{
|
||||||
|
if ([(NSObject*)m_audioGroupClient isKindOfClass:[AppDelegate class]])
|
||||||
|
{
|
||||||
|
std::string search;
|
||||||
|
if (m_searchStr)
|
||||||
|
search = m_searchStr.UTF8String;
|
||||||
|
|
||||||
|
m_sfxTableData.clear();
|
||||||
|
m_sampleTableData.clear();
|
||||||
|
m_filterAudioGroupCollections.clear();
|
||||||
|
m_filterAudioGroupCollections.reserve(m_audioGroupCollections.size());
|
||||||
|
for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ; ++it)
|
||||||
|
{
|
||||||
|
it->second->addSFX(m_sfxTableData);
|
||||||
|
it->second->addSamples(m_sampleTableData);
|
||||||
|
if (it->second->doSearch(search) || !m_searchStr || StrToLower(it->first).find(search) != std::string::npos)
|
||||||
|
m_filterAudioGroupCollections.push_back(it);
|
||||||
|
}
|
||||||
|
[m_lastOutlineView reloadItem:nil reloadChildren:YES];
|
||||||
|
[(AppDelegate*)m_audioGroupClient reloadTables];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_sfxTableData.clear();
|
||||||
|
m_sampleTableData.clear();
|
||||||
|
m_filterAudioGroupCollections.clear();
|
||||||
|
m_filterAudioGroupCollections.reserve(m_audioGroupCollections.size());
|
||||||
|
for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ; ++it)
|
||||||
|
{
|
||||||
|
it->second->addSFX(m_sfxTableData);
|
||||||
|
it->second->addSamples(m_sampleTableData);
|
||||||
|
if (it->second->doActiveFilter())
|
||||||
|
m_filterAudioGroupCollections.push_back(it);
|
||||||
|
}
|
||||||
|
[((AmuseAudioUnit*)m_audioGroupClient)->m_viewController->m_groupBrowser loadColumnZero];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSearchFilter:(NSString*)str
|
||||||
|
{
|
||||||
|
m_searchStr = [str lowercaseString];
|
||||||
|
[self resetIterators];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeSelectedItem
|
||||||
|
{
|
||||||
|
id item = [m_lastOutlineView itemAtRow:m_lastOutlineView.selectedRow];
|
||||||
|
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||||
|
NSURL* collectionURL = collection.m_url;
|
||||||
|
NSString* lastComp = collectionURL.lastPathComponent;
|
||||||
|
m_audioGroupCollections.erase(lastComp.UTF8String);
|
||||||
|
[self resetIterators];
|
||||||
|
[[NSFileManager defaultManager] removeItemAtURL:collectionURL error:nil];
|
||||||
|
if (m_audioGroupCollections.empty())
|
||||||
|
[(AppDelegate*)NSApp.delegate outlineView:(DataOutlineView*)m_lastOutlineView selectionChanged:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithAudioGroupClient:(id<AudioGroupClient>)client
|
||||||
|
{
|
||||||
|
m_audioGroupClient = client;
|
||||||
m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.io.github.axiodl.Amuse.AudioGroups"];
|
m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.io.github.axiodl.Amuse.AudioGroups"];
|
||||||
if (!m_groupURL)
|
if (!m_groupURL)
|
||||||
return nil;
|
return nil;
|
||||||
m_dataQueue = [NSOperationQueue new];
|
|
||||||
[NSFileCoordinator addFilePresenter:self];
|
[NSFileCoordinator addFilePresenter:self];
|
||||||
|
[self update];
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,23 +16,16 @@
|
||||||
#include "amuse/IBackendVoice.hpp"
|
#include "amuse/IBackendVoice.hpp"
|
||||||
#include "amuse/IBackendSubmix.hpp"
|
#include "amuse/IBackendSubmix.hpp"
|
||||||
#include "amuse/IBackendVoiceAllocator.hpp"
|
#include "amuse/IBackendVoiceAllocator.hpp"
|
||||||
|
#import "AudioGroupFilePresenter.hpp"
|
||||||
|
|
||||||
|
@class AudioUnitViewController;
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
/** Backend MIDI event reader for controlling sequencer with external hardware / software */
|
|
||||||
class AudioUnitBackendMIDIReader : public BooBackendMIDIReader
|
|
||||||
{
|
|
||||||
friend class AudioUnitBackendVoiceAllocator;
|
|
||||||
public:
|
|
||||||
AudioUnitBackendMIDIReader(Engine& engine)
|
|
||||||
: BooBackendMIDIReader(engine, "AudioUnit MIDI") {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Backend voice allocator implementation for AudioUnit mixer */
|
/** Backend voice allocator implementation for AudioUnit mixer */
|
||||||
class AudioUnitBackendVoiceAllocator : public BooBackendVoiceAllocator
|
class AudioUnitBackendVoiceAllocator : public BooBackendVoiceAllocator
|
||||||
{
|
{
|
||||||
friend class AudioUnitBackendMIDIReader;
|
|
||||||
public:
|
public:
|
||||||
AudioUnitBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine)
|
AudioUnitBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine)
|
||||||
: BooBackendVoiceAllocator(booEngine) {}
|
: BooBackendVoiceAllocator(booEngine) {}
|
||||||
|
@ -42,13 +35,21 @@ void RegisterAudioUnit();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface AmuseAudioUnit : AUAudioUnit
|
@interface AmuseAudioUnit : AUAudioUnit <AudioGroupClient>
|
||||||
{
|
{
|
||||||
|
@public
|
||||||
|
AudioUnitViewController* m_viewController;
|
||||||
std::unique_ptr<boo::IAudioVoiceEngine> m_booBackend;
|
std::unique_ptr<boo::IAudioVoiceEngine> m_booBackend;
|
||||||
std::experimental::optional<amuse::AudioUnitBackendVoiceAllocator> m_voxAlloc;
|
std::experimental::optional<amuse::AudioUnitBackendVoiceAllocator> m_voxAlloc;
|
||||||
std::experimental::optional<amuse::Engine> m_engine;
|
std::experimental::optional<amuse::Engine> m_engine;
|
||||||
|
AudioGroupFilePresenter* m_filePresenter;
|
||||||
|
AUAudioUnitBus* m_outBus;
|
||||||
AUAudioUnitBusArray* m_outs;
|
AUAudioUnitBusArray* m_outs;
|
||||||
}
|
}
|
||||||
|
- (nullable id)initWithComponentDescription:(AudioComponentDescription)componentDescription
|
||||||
|
error:(NSError * __nullable * __nonnull)outError
|
||||||
|
viewController:(AudioUnitViewController* __nonnull)vc;
|
||||||
|
- (void)requestAudioGroup:(AudioGroupToken*)group;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,13 +12,17 @@
|
||||||
|
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
#include "audiodev/AudioVoiceEngine.hpp"
|
#include "audiodev/AudioVoiceEngine.hpp"
|
||||||
|
#import "AudioUnitViewController.hpp"
|
||||||
|
|
||||||
static logvisor::Module Log("amuse::AudioUnitBackend");
|
static logvisor::Module Log("amuse::AudioUnitBackend");
|
||||||
|
|
||||||
struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
{
|
{
|
||||||
|
AudioGroupToken* m_reqGroup = nullptr;
|
||||||
|
AudioGroupToken* m_curGroup = nullptr;
|
||||||
|
std::vector<float> m_interleavedBuf;
|
||||||
std::vector<std::unique_ptr<float[]>> m_renderBufs;
|
std::vector<std::unique_ptr<float[]>> m_renderBufs;
|
||||||
size_t m_frameBytes;
|
size_t m_renderFrames = 0;
|
||||||
AudioBufferList* m_outputData = nullptr;
|
AudioBufferList* m_outputData = nullptr;
|
||||||
|
|
||||||
boo::AudioChannelSet _getAvailableSet()
|
boo::AudioChannelSet _getAvailableSet()
|
||||||
|
@ -31,12 +35,24 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
boo::ReceiveFunctor m_midiReceiver = nullptr;
|
boo::ReceiveFunctor* m_midiReceiver = nullptr;
|
||||||
|
|
||||||
|
struct MIDIIn : public boo::IMIDIIn
|
||||||
|
{
|
||||||
|
MIDIIn(bool virt, boo::ReceiveFunctor&& receiver)
|
||||||
|
: IMIDIIn(virt, std::move(receiver)) {}
|
||||||
|
|
||||||
|
std::string description() const
|
||||||
|
{
|
||||||
|
return "AudioUnit MIDI";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
std::unique_ptr<boo::IMIDIIn> newVirtualMIDIIn(boo::ReceiveFunctor&& receiver)
|
std::unique_ptr<boo::IMIDIIn> newVirtualMIDIIn(boo::ReceiveFunctor&& receiver)
|
||||||
{
|
{
|
||||||
m_midiReceiver = std::move(receiver);
|
std::unique_ptr<boo::IMIDIIn> ret = std::make_unique<MIDIIn>(true, std::move(receiver));
|
||||||
return {};
|
m_midiReceiver = &ret->m_receiver;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<boo::IMIDIOut> newVirtualMIDIOut()
|
std::unique_ptr<boo::IMIDIOut> newVirtualMIDIOut()
|
||||||
|
@ -64,15 +80,23 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool useMIDILock() const {return false;}
|
||||||
|
|
||||||
AudioUnitVoiceEngine()
|
AudioUnitVoiceEngine()
|
||||||
|
{
|
||||||
|
m_mixInfo.m_periodFrames = 512;
|
||||||
|
m_mixInfo.m_sampleRate = 96000.0;
|
||||||
|
m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I;
|
||||||
|
m_mixInfo.m_bitsPerSample = 32;
|
||||||
|
_buildAudioRenderClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _buildAudioRenderClient()
|
||||||
{
|
{
|
||||||
m_mixInfo.m_channels = _getAvailableSet();
|
m_mixInfo.m_channels = _getAvailableSet();
|
||||||
unsigned chCount = ChannelCount(m_mixInfo.m_channels);
|
unsigned chCount = ChannelCount(m_mixInfo.m_channels);
|
||||||
|
|
||||||
m_mixInfo.m_sampleRate = 96000.0;
|
m_5msFrames = m_mixInfo.m_sampleRate * 5 / 1000;
|
||||||
m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I;
|
|
||||||
m_mixInfo.m_bitsPerSample = 32;
|
|
||||||
m_5msFrames = 96000 * 5 / 1000;
|
|
||||||
|
|
||||||
boo::ChannelMap& chMapOut = m_mixInfo.m_channelMap;
|
boo::ChannelMap& chMapOut = m_mixInfo.m_channelMap;
|
||||||
chMapOut.m_channelCount = 2;
|
chMapOut.m_channelCount = 2;
|
||||||
|
@ -81,60 +105,73 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
|
|
||||||
while (chMapOut.m_channelCount < chCount)
|
while (chMapOut.m_channelCount < chCount)
|
||||||
chMapOut.m_channels[chMapOut.m_channelCount++] = boo::AudioChannel::Unknown;
|
chMapOut.m_channels[chMapOut.m_channelCount++] = boo::AudioChannel::Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
m_mixInfo.m_periodFrames = 2400;
|
void _rebuildAudioRenderClient(double sampleRate, size_t periodFrames)
|
||||||
|
{
|
||||||
|
m_mixInfo.m_periodFrames = periodFrames;
|
||||||
|
m_mixInfo.m_sampleRate = sampleRate;
|
||||||
|
_buildAudioRenderClient();
|
||||||
|
|
||||||
m_frameBytes = m_mixInfo.m_periodFrames * m_mixInfo.m_channelMap.m_channelCount * 4;
|
for (boo::AudioVoice* vox : m_activeVoices)
|
||||||
|
vox->_resetSampleRate(vox->m_sampleRateIn);
|
||||||
|
for (boo::AudioSubmix* smx : m_activeSubmixes)
|
||||||
|
smx->_resetOutputSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pumpAndMixVoices()
|
void pumpAndMixVoices()
|
||||||
{
|
{
|
||||||
if (m_renderBufs.size() < m_outputData->mNumberBuffers)
|
_pumpAndMixVoices(m_renderFrames, m_interleavedBuf.data());
|
||||||
m_renderBufs.resize(m_outputData->mNumberBuffers);
|
|
||||||
|
|
||||||
for (int i=0 ; i<m_outputData->mNumberBuffers ; ++i)
|
for (size_t i=0 ; i<m_renderBufs.size() ; ++i)
|
||||||
{
|
{
|
||||||
std::unique_ptr<float[]>& buf = m_renderBufs[i];
|
std::unique_ptr<float[]>& buf = m_renderBufs[i];
|
||||||
AudioBuffer& auBuf = m_outputData->mBuffers[i];
|
AudioBuffer& auBuf = m_outputData->mBuffers[i];
|
||||||
if (!auBuf.mData)
|
if (!auBuf.mData)
|
||||||
{
|
{
|
||||||
buf.reset(new float[auBuf.mDataByteSize]);
|
buf.reset(new float[auBuf.mDataByteSize / 4]);
|
||||||
auBuf.mData = buf.get();
|
auBuf.mData = buf.get();
|
||||||
}
|
}
|
||||||
|
for (size_t f=0 ; f<m_renderFrames ; ++f)
|
||||||
|
{
|
||||||
|
float* bufOut = reinterpret_cast<float*>(auBuf.mData);
|
||||||
|
bufOut[f] = m_interleavedBuf[f*2+i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_pumpAndMixVoices(auBuf.mDataByteSize / 2 / 4, reinterpret_cast<float*>(auBuf.mData));
|
double getCurrentSampleRate() const {return m_mixInfo.m_sampleRate;}
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@implementation AmuseAudioUnit
|
@implementation AmuseAudioUnit
|
||||||
|
- (id)initWithComponentDescription:(AudioComponentDescription)componentDescription
|
||||||
|
error:(NSError * _Nullable *)outError
|
||||||
|
viewController:(AudioUnitViewController*)vc
|
||||||
|
{
|
||||||
|
m_viewController = vc;
|
||||||
|
vc->m_audioUnit = self;
|
||||||
|
self = [super initWithComponentDescription:componentDescription error:outError];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
- (id)initWithComponentDescription:(AudioComponentDescription)componentDescription
|
- (id)initWithComponentDescription:(AudioComponentDescription)componentDescription
|
||||||
options:(AudioComponentInstantiationOptions)options
|
options:(AudioComponentInstantiationOptions)options
|
||||||
error:(NSError * _Nullable *)outError;
|
error:(NSError * _Nullable *)outError
|
||||||
{
|
{
|
||||||
self = [super initWithComponentDescription:componentDescription options:options error:outError];
|
self = [super initWithComponentDescription:componentDescription options:options error:outError];
|
||||||
if (!self)
|
if (!self)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
AUAudioUnitBus* outBus = [[AUAudioUnitBus alloc] initWithFormat:
|
AVAudioFormat* format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:96000.0 channels:2];
|
||||||
[[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32
|
m_outBus = [[AUAudioUnitBus alloc] initWithFormat:format error:outError];
|
||||||
sampleRate:96000.0
|
if (!m_outBus)
|
||||||
channels:2
|
|
||||||
interleaved:TRUE]
|
|
||||||
error:outError];
|
|
||||||
if (!outBus)
|
|
||||||
return nil;
|
return nil;
|
||||||
|
//m_outBus.supportedChannelCounts = @[@1,@2];
|
||||||
|
m_outBus.maximumChannelCount = 2;
|
||||||
|
|
||||||
m_outs = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self busType:AUAudioUnitBusTypeOutput busses:@[outBus]];
|
m_outs = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self
|
||||||
|
busType:AUAudioUnitBusTypeOutput
|
||||||
self.maximumFramesToRender = 2400;
|
busses:@[m_outBus]];
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)allocateRenderResourcesAndReturnError:(NSError * _Nullable *)outError
|
|
||||||
{
|
|
||||||
if (![super allocateRenderResourcesAndReturnError:outError])
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
m_booBackend = std::make_unique<AudioUnitVoiceEngine>();
|
m_booBackend = std::make_unique<AudioUnitVoiceEngine>();
|
||||||
if (!m_booBackend)
|
if (!m_booBackend)
|
||||||
|
@ -146,23 +183,46 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
|
|
||||||
m_voxAlloc.emplace(*m_booBackend);
|
m_voxAlloc.emplace(*m_booBackend);
|
||||||
m_engine.emplace(*m_voxAlloc);
|
m_engine.emplace(*m_voxAlloc);
|
||||||
|
dispatch_sync(dispatch_get_main_queue(),
|
||||||
|
^{
|
||||||
|
m_filePresenter = [[AudioGroupFilePresenter alloc] initWithAudioGroupClient:self];
|
||||||
|
});
|
||||||
|
|
||||||
|
self.maximumFramesToRender = 512;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)requestAudioGroup:(AudioGroupToken*)group
|
||||||
|
{
|
||||||
|
AudioUnitVoiceEngine& voxEngine = static_cast<AudioUnitVoiceEngine&>(*m_booBackend);
|
||||||
|
voxEngine.m_reqGroup = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)allocateRenderResourcesAndReturnError:(NSError **)outError
|
||||||
|
{
|
||||||
|
if (![super allocateRenderResourcesAndReturnError:outError])
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
size_t chanCount = m_outBus.format.channelCount;
|
||||||
|
size_t renderFrames = self.maximumFramesToRender;
|
||||||
|
|
||||||
|
NSLog(@"Alloc Chans: %zu Frames: %zu SampRate: %f", chanCount, renderFrames, m_outBus.format.sampleRate);
|
||||||
|
|
||||||
|
AudioUnitVoiceEngine& voxEngine = static_cast<AudioUnitVoiceEngine&>(*m_booBackend);
|
||||||
|
voxEngine.m_renderFrames = renderFrames;
|
||||||
|
voxEngine.m_interleavedBuf.resize(renderFrames * std::max(2ul, chanCount));
|
||||||
|
voxEngine.m_renderBufs.resize(chanCount);
|
||||||
|
voxEngine._rebuildAudioRenderClient(m_outBus.format.sampleRate, renderFrames);
|
||||||
|
|
||||||
*outError = nil;
|
*outError = nil;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)deallocateRenderResources
|
- (void)deallocateRenderResources
|
||||||
{
|
{
|
||||||
m_engine = std::experimental::nullopt;
|
|
||||||
m_voxAlloc = std::experimental::nullopt;
|
|
||||||
m_booBackend.reset();
|
|
||||||
[super deallocateRenderResources];
|
[super deallocateRenderResources];
|
||||||
}
|
AudioUnitVoiceEngine& voxEngine = static_cast<AudioUnitVoiceEngine&>(*m_booBackend);
|
||||||
|
voxEngine.m_renderBufs.clear();
|
||||||
- (BOOL)renderResourcesAllocated
|
|
||||||
{
|
|
||||||
if (m_engine)
|
|
||||||
return TRUE;
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (AUAudioUnitBusArray*)outputBusses
|
- (AUAudioUnitBusArray*)outputBusses
|
||||||
|
@ -184,11 +244,25 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
{
|
{
|
||||||
__block AudioUnitVoiceEngine& voxEngine = static_cast<AudioUnitVoiceEngine&>(*m_booBackend);
|
__block AudioUnitVoiceEngine& voxEngine = static_cast<AudioUnitVoiceEngine&>(*m_booBackend);
|
||||||
__block amuse::Engine& amuseEngine = *m_engine;
|
__block amuse::Engine& amuseEngine = *m_engine;
|
||||||
|
__block std::shared_ptr<amuse::Sequencer> curSeq;
|
||||||
|
|
||||||
return ^AUAudioUnitStatus(AudioUnitRenderActionFlags* actionFlags, const AudioTimeStamp* timestamp,
|
return ^AUAudioUnitStatus(AudioUnitRenderActionFlags* actionFlags, const AudioTimeStamp* timestamp,
|
||||||
AUAudioFrameCount frameCount, NSInteger outputBusNumber, AudioBufferList* outputData,
|
AUAudioFrameCount frameCount, NSInteger outputBusNumber, AudioBufferList* outputData,
|
||||||
const AURenderEvent* realtimeEventListHead, AURenderPullInputBlock pullInputBlock)
|
const AURenderEvent* realtimeEventListHead, AURenderPullInputBlock pullInputBlock)
|
||||||
{
|
{
|
||||||
|
/* Handle group load request */
|
||||||
|
AudioGroupToken* reqGroup = voxEngine.m_reqGroup;
|
||||||
|
if (voxEngine.m_curGroup != reqGroup)
|
||||||
|
{
|
||||||
|
voxEngine.m_curGroup = reqGroup;
|
||||||
|
if (reqGroup->m_song)
|
||||||
|
{
|
||||||
|
if (curSeq)
|
||||||
|
curSeq->kill();
|
||||||
|
curSeq = amuseEngine.seqPlay(reqGroup->m_id, -1, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Process MIDI events first */
|
/* Process MIDI events first */
|
||||||
if (voxEngine.m_midiReceiver)
|
if (voxEngine.m_midiReceiver)
|
||||||
{
|
{
|
||||||
|
@ -197,18 +271,25 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
{
|
{
|
||||||
if (event->eventType == AURenderEventMIDI)
|
if (event->eventType == AURenderEventMIDI)
|
||||||
{
|
{
|
||||||
voxEngine.m_midiReceiver(std::vector<uint8_t>(std::cbegin(event->data),
|
(*voxEngine.m_midiReceiver)(std::vector<uint8_t>(std::cbegin(event->data),
|
||||||
std::cbegin(event->data) + event->length));
|
std::cbegin(event->data) + event->length),
|
||||||
|
event->eventSampleTime / voxEngine.getCurrentSampleRate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output buffers */
|
/* Output buffers */
|
||||||
|
voxEngine.m_renderFrames = frameCount;
|
||||||
voxEngine.m_outputData = outputData;
|
voxEngine.m_outputData = outputData;
|
||||||
amuseEngine.pumpEngine();
|
amuseEngine.pumpEngine();
|
||||||
return noErr;
|
return noErr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (amuse::Engine&)getAmuseEngine
|
||||||
|
{
|
||||||
|
return *m_engine;
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
|
|
|
@ -2,9 +2,24 @@
|
||||||
#define __AMUSE_AUDIOUNIT_VIEWCONTROLLER_HPP__
|
#define __AMUSE_AUDIOUNIT_VIEWCONTROLLER_HPP__
|
||||||
|
|
||||||
#import <CoreAudioKit/CoreAudioKit.h>
|
#import <CoreAudioKit/CoreAudioKit.h>
|
||||||
|
#import "AudioGroupFilePresenter.hpp"
|
||||||
|
|
||||||
|
@class AmuseAudioUnit;
|
||||||
|
|
||||||
|
@interface GroupBrowserDelegate : NSObject <NSBrowserDelegate>
|
||||||
|
{
|
||||||
|
AmuseAudioUnit* m_audioUnit;
|
||||||
|
}
|
||||||
|
- (id)initWithAudioUnit:(AmuseAudioUnit*)au;
|
||||||
|
@end
|
||||||
|
|
||||||
@interface AudioUnitViewController : AUViewController <AUAudioUnitFactory>
|
@interface AudioUnitViewController : AUViewController <AUAudioUnitFactory>
|
||||||
|
{
|
||||||
|
@public
|
||||||
|
AmuseAudioUnit* m_audioUnit;
|
||||||
|
IBOutlet NSBrowser* m_groupBrowser;
|
||||||
|
GroupBrowserDelegate* m_groupBrowserDelegate;
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif // __AMUSE_AUDIOUNIT_VIEWCONTROLLER_HPP__
|
#endif // __AMUSE_AUDIOUNIT_VIEWCONTROLLER_HPP__
|
||||||
|
|
|
@ -5,73 +5,166 @@
|
||||||
#error ARC Required
|
#error ARC Required
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@interface AudioUnitView : NSView
|
@implementation GroupBrowserDelegate
|
||||||
|
|
||||||
|
- (BOOL)browser:(NSBrowser *)sender isColumnValid:(NSInteger)column
|
||||||
{
|
{
|
||||||
NSButton* m_fileButton;
|
if (column == 0)
|
||||||
|
return YES;
|
||||||
|
else if (column == 1)
|
||||||
|
{
|
||||||
|
AudioGroupCollectionToken* collection = [sender selectedCellInColumn:0];
|
||||||
|
if (collection)
|
||||||
|
return YES;
|
||||||
}
|
}
|
||||||
- (void)clickFileButton;
|
else if (column == 2)
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation AudioUnitView
|
|
||||||
|
|
||||||
- (id)init
|
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:NSMakeRect(0, 0, 200, 300)];
|
AudioGroupDataToken* groupFile = [sender selectedCellInColumn:1];
|
||||||
m_fileButton = [[NSButton alloc] initWithFrame:NSMakeRect(100, 100, 30, 10)];
|
if (groupFile)
|
||||||
m_fileButton.target = self;
|
return YES;
|
||||||
m_fileButton.action = @selector(clickFileButton);
|
}
|
||||||
[self addSubview:m_fileButton];
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)browser:(NSBrowser *)sender numberOfRowsInColumn:(NSInteger)column
|
||||||
|
{
|
||||||
|
if (column == 0)
|
||||||
|
return m_audioUnit->m_filePresenter->m_filterAudioGroupCollections.size();
|
||||||
|
else if (column == 1)
|
||||||
|
{
|
||||||
|
AudioGroupCollectionToken* collection = [sender selectedCellInColumn:0];
|
||||||
|
if (!collection)
|
||||||
|
return 0;
|
||||||
|
return collection->m_collection->m_filterGroups.size();
|
||||||
|
}
|
||||||
|
else if (column == 2)
|
||||||
|
{
|
||||||
|
AudioGroupDataToken* groupFile = [sender selectedCellInColumn:1];
|
||||||
|
if (!groupFile)
|
||||||
|
return 0;
|
||||||
|
const amuse::AudioGroup* audioGroupFile = groupFile->m_collection->m_loadedGroup;
|
||||||
|
return audioGroupFile->getProj().songGroups().size() + audioGroupFile->getProj().sfxGroups().size();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)browser:(NSBrowser *)browser numberOfChildrenOfItem:(id)item
|
||||||
|
{
|
||||||
|
if (!item)
|
||||||
|
return m_audioUnit->m_filePresenter->m_filterAudioGroupCollections.size();
|
||||||
|
else if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupCollectionToken* collection = item;
|
||||||
|
return collection->m_collection->m_filterGroups.size();
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass:[AudioGroupDataToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupDataToken* groupFile = item;
|
||||||
|
const amuse::AudioGroup* audioGroupFile = groupFile->m_collection->m_loadedGroup;
|
||||||
|
return audioGroupFile->getProj().songGroups().size() + audioGroupFile->getProj().sfxGroups().size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)browser:(NSBrowser *)sender titleOfColumn:(NSInteger)column
|
||||||
|
{
|
||||||
|
if (column == 0)
|
||||||
|
return @"Collection";
|
||||||
|
else if (column == 1)
|
||||||
|
return @"File";
|
||||||
|
else if (column == 2)
|
||||||
|
return @"Group";
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)browser:(NSBrowser *)browser child:(NSInteger)index ofItem:(id)item
|
||||||
|
{
|
||||||
|
if (!item)
|
||||||
|
return m_audioUnit->m_filePresenter->m_filterAudioGroupCollections[index]->second->m_token;
|
||||||
|
else if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupCollectionToken* collection = item;
|
||||||
|
return collection->m_collection->m_filterGroups[index]->second->m_token;
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass:[AudioGroupDataToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupDataToken* groupFile = item;
|
||||||
|
return groupFile->m_collection->m_groupTokens[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)browser:(NSBrowser *)browser isLeafItem:(id)item
|
||||||
|
{
|
||||||
|
if ([item isKindOfClass:[AudioGroupToken class]])
|
||||||
|
return YES;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)browser:(NSBrowser *)browser shouldEditItem:(id)item
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)browser:(NSBrowser *)browser objectValueForItem:(id)item
|
||||||
|
{
|
||||||
|
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupCollectionToken* collection = item;
|
||||||
|
return collection->m_collection->m_url.lastPathComponent;
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass:[AudioGroupDataToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupDataToken* groupFile = item;
|
||||||
|
return @(groupFile->m_collection->m_name.c_str());
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass:[AudioGroupToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupToken* group = item;
|
||||||
|
return group->m_name;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSIndexSet *)browser:(NSBrowser *)browser selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes inColumn:(NSInteger)column
|
||||||
|
{
|
||||||
|
if (column == 2)
|
||||||
|
{
|
||||||
|
AudioGroupToken* token = [browser itemAtRow:proposedSelectionIndexes.firstIndex inColumn:column];
|
||||||
|
[m_audioUnit requestAudioGroup:token];
|
||||||
|
}
|
||||||
|
return proposedSelectionIndexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithAudioUnit:(AmuseAudioUnit*)au
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
m_audioUnit = au;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)clickFileButton
|
|
||||||
{
|
|
||||||
NSLog(@"Click");
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface AudioUnitViewController ()
|
@implementation AudioUnitViewController
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation AudioUnitViewController {
|
|
||||||
AUAudioUnit *audioUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) viewDidLoad {
|
- (void) viewDidLoad {
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
if (!audioUnit) {
|
self.preferredContentSize = NSMakeSize(510, 312);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the parameter tree and add observers for any parameters that the UI needs to keep in sync with the AudioUnit
|
// Get the parameter tree and add observers for any parameters that the UI needs to keep in sync with the AudioUnit
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)loadView
|
|
||||||
{
|
|
||||||
self.view = [AudioUnitView new];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSSize)preferredContentSize
|
|
||||||
{
|
|
||||||
return NSMakeSize(200, 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSSize)preferredMaximumSize
|
|
||||||
{
|
|
||||||
return NSMakeSize(200, 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSSize)preferredMinimumSize
|
|
||||||
{
|
|
||||||
return NSMakeSize(200, 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (AUAudioUnit*)createAudioUnitWithComponentDescription:(AudioComponentDescription)desc error:(NSError**)error {
|
- (AUAudioUnit*)createAudioUnitWithComponentDescription:(AudioComponentDescription)desc error:(NSError**)error {
|
||||||
audioUnit = [[AmuseAudioUnit alloc] initWithComponentDescription:desc error:error];
|
m_audioUnit = [[AmuseAudioUnit alloc] initWithComponentDescription:desc error:error viewController:self];
|
||||||
return audioUnit;
|
m_groupBrowserDelegate = [[GroupBrowserDelegate alloc] initWithAudioUnit:m_audioUnit];
|
||||||
|
dispatch_sync(dispatch_get_main_queue(), ^
|
||||||
|
{
|
||||||
|
m_groupBrowser.delegate = m_groupBrowserDelegate;
|
||||||
|
[m_groupBrowser loadColumnZero];
|
||||||
|
});
|
||||||
|
return m_audioUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10116" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10116"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="AudioUnitViewController">
|
||||||
|
<connections>
|
||||||
|
<outlet property="m_groupBrowser" destination="Pbx-jL-10p" id="BEh-LF-c7K"/>
|
||||||
|
<outlet property="view" destination="Pbx-jL-10p" id="dfL-uY-h99"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
|
<browser verticalHuggingPriority="750" allowsExpansionToolTips="YES" enabled="YES" hasHorizontalScroller="YES" allowsEmptySelection="YES" defaultColumnWidth="100" minColumnWidth="100" maxVisibleColumns="3" titled="YES" separatesColumns="YES" allowsTypeSelect="YES" sendsActionOnArrowKeys="YES" columnResizingType="auto" id="Pbx-jL-10p">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="510" height="312"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<point key="canvasLocation" x="313" y="621"/>
|
||||||
|
</browser>
|
||||||
|
</objects>
|
||||||
|
</document>
|
|
@ -21,9 +21,18 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE
|
||||||
if(EXISTS "${PROV_PROFILE}")
|
if(EXISTS "${PROV_PROFILE}")
|
||||||
|
|
||||||
# Extension App
|
# Extension App
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib
|
||||||
|
COMMAND ibtool --errors --warnings --notices --module amuse_au --auto-activate-custom-fonts
|
||||||
|
--target-device mac --minimum-deployment-target 10.11 --output-format human-readable-text --compile
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/AudioUnitViewController.xib
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AudioUnitViewController.xib
|
||||||
|
)
|
||||||
add_executable(amuse-au MACOSX_BUNDLE AudioUnitBackend.hpp AudioUnitBackend.mm
|
add_executable(amuse-au MACOSX_BUNDLE AudioUnitBackend.hpp AudioUnitBackend.mm
|
||||||
AudioUnitViewController.hpp AudioUnitViewController.mm
|
AudioUnitViewController.hpp AudioUnitViewController.mm
|
||||||
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm)
|
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
||||||
|
AudioUnitViewController.nib)
|
||||||
|
|
||||||
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse.AudioUnit")
|
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse.AudioUnit")
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseExtension.entitlements.in
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseExtension.entitlements.in
|
||||||
|
@ -48,7 +57,7 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
||||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
||||||
)
|
)
|
||||||
add_executable(amuse-au-container MACOSX_BUNDLE AmuseContainingApp.mm
|
add_executable(amuse-au-container MACOSX_BUNDLE AmuseContainingApp.hpp AmuseContainingApp.mm
|
||||||
AudioUnitBackend.hpp AudioUnitBackend.mm
|
AudioUnitBackend.hpp AudioUnitBackend.mm
|
||||||
AudioUnitViewController.hpp AudioUnitViewController.mm
|
AudioUnitViewController.hpp AudioUnitViewController.mm
|
||||||
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
||||||
|
@ -57,7 +66,7 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE
|
||||||
AmuseContainingApp.mm AudioGroupFilePresenter.mm
|
AmuseContainingApp.mm AudioGroupFilePresenter.mm
|
||||||
PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||||
target_link_libraries(amuse-au-container amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
|
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")
|
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse")
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainer.entitlements.in
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainer.entitlements.in
|
||||||
|
@ -69,6 +78,9 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE
|
||||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}")
|
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}")
|
||||||
|
|
||||||
add_custom_command(TARGET amuse-au POST_BUILD
|
add_custom_command(TARGET amuse-au POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib"
|
||||||
|
"$<TARGET_FILE_DIR:amuse-au>/../Resources/AudioUnitViewController.nib"
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy "${PROV_PROFILE}" "$<TARGET_FILE_DIR:amuse-au>/../embedded.provisionprofile"
|
COMMAND ${CMAKE_COMMAND} -E copy "${PROV_PROFILE}" "$<TARGET_FILE_DIR:amuse-au>/../embedded.provisionprofile"
|
||||||
COMMAND ${CMAKE_COMMAND} -E remove_directory "$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
|
COMMAND ${CMAKE_COMMAND} -E remove_directory "$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "$<TARGET_FILE_DIR:amuse-au>/../.."
|
COMMAND ${CMAKE_COMMAND} -E copy_directory "$<TARGET_FILE_DIR:amuse-au>/../.."
|
||||||
|
|
|
@ -4,6 +4,17 @@
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>en</string>
|
<string>en</string>
|
||||||
|
<key>CFBundleDocumentTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Viewer</string>
|
||||||
|
<key>LSItemContentTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>public.data</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>amuse-au-container</string>
|
<string>amuse-au-container</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
|
|
|
@ -31,6 +31,7 @@ public:
|
||||||
const unsigned char* getSampleData(uint32_t offset) const;
|
const unsigned char* getSampleData(uint32_t offset) const;
|
||||||
const AudioGroupProject& getProj() const {return m_proj;}
|
const AudioGroupProject& getProj() const {return m_proj;}
|
||||||
const AudioGroupPool& getPool() const {return m_pool;}
|
const AudioGroupPool& getPool() const {return m_pool;}
|
||||||
|
const AudioGroupSampleDirectory& getSdir() const {return m_sdir;}
|
||||||
DataFormat getDataFormat() const {return m_fmt;}
|
DataFormat getDataFormat() const {return m_fmt;}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,29 +12,54 @@ class AudioGroupData
|
||||||
friend class Engine;
|
friend class Engine;
|
||||||
protected:
|
protected:
|
||||||
unsigned char* m_proj;
|
unsigned char* m_proj;
|
||||||
|
size_t m_projSz;
|
||||||
unsigned char* m_pool;
|
unsigned char* m_pool;
|
||||||
|
size_t m_poolSz;
|
||||||
unsigned char* m_sdir;
|
unsigned char* m_sdir;
|
||||||
|
size_t m_sdirSz;
|
||||||
unsigned char* m_samp;
|
unsigned char* m_samp;
|
||||||
|
size_t m_sampSz;
|
||||||
|
|
||||||
DataFormat m_fmt;
|
DataFormat m_fmt;
|
||||||
bool m_absOffs;
|
bool m_absOffs;
|
||||||
|
|
||||||
AudioGroupData(unsigned char* proj, unsigned char* pool,
|
AudioGroupData(unsigned char* proj, size_t projSz,
|
||||||
unsigned char* sdir, unsigned char* samp,
|
unsigned char* pool, size_t poolSz,
|
||||||
|
unsigned char* sdir, size_t sdirSz,
|
||||||
|
unsigned char* samp, size_t sampSz,
|
||||||
DataFormat fmt, bool absOffs)
|
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) {}
|
m_fmt(fmt), m_absOffs(absOffs) {}
|
||||||
public:
|
public:
|
||||||
AudioGroupData(unsigned char* proj, unsigned char* pool,
|
AudioGroupData(unsigned char* proj, size_t projSz,
|
||||||
unsigned char* sdir, unsigned char* samp, GCNDataTag)
|
unsigned char* pool, size_t poolSz,
|
||||||
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp),
|
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) {}
|
m_fmt(DataFormat::GCN), m_absOffs(true) {}
|
||||||
AudioGroupData(unsigned char* proj, unsigned char* pool,
|
AudioGroupData(unsigned char* proj, size_t projSz,
|
||||||
unsigned char* sdir, unsigned char* samp, bool absOffs, N64DataTag)
|
unsigned char* pool, size_t poolSz,
|
||||||
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp),
|
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) {}
|
m_fmt(DataFormat::N64), m_absOffs(absOffs) {}
|
||||||
AudioGroupData(unsigned char* proj, unsigned char* pool,
|
AudioGroupData(unsigned char* proj, size_t projSz,
|
||||||
unsigned char* sdir, unsigned char* samp, bool absOffs, PCDataTag)
|
unsigned char* pool, size_t poolSz,
|
||||||
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp),
|
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) {}
|
m_fmt(DataFormat::PC), m_absOffs(absOffs) {}
|
||||||
|
|
||||||
const unsigned char* getProj() const {return m_proj;}
|
const unsigned char* getProj() const {return m_proj;}
|
||||||
|
@ -42,6 +67,16 @@ public:
|
||||||
const unsigned char* getSdir() const {return m_sdir;}
|
const unsigned char* getSdir() const {return m_sdir;}
|
||||||
const unsigned char* getSamp() const {return m_samp;}
|
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
|
operator bool() const
|
||||||
{
|
{
|
||||||
return m_proj != nullptr && m_pool != nullptr && m_sdir != nullptr && m_samp != nullptr;
|
return m_proj != nullptr && m_pool != nullptr && m_sdir != nullptr && m_samp != nullptr;
|
||||||
|
@ -64,6 +99,8 @@ public:
|
||||||
|
|
||||||
IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other);
|
IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other);
|
||||||
IntrusiveAudioGroupData& operator=(IntrusiveAudioGroupData&& other);
|
IntrusiveAudioGroupData& operator=(IntrusiveAudioGroupData&& other);
|
||||||
|
|
||||||
|
void dangleOwnership() {m_owns = false;}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ public:
|
||||||
AudioGroupSampleDirectory(const unsigned char* data, const unsigned char* sampData,
|
AudioGroupSampleDirectory(const unsigned char* data, const unsigned char* sampData,
|
||||||
bool absOffs, N64DataTag);
|
bool absOffs, N64DataTag);
|
||||||
AudioGroupSampleDirectory(const unsigned char* data, bool absOffs, PCDataTag);
|
AudioGroupSampleDirectory(const unsigned char* data, bool absOffs, PCDataTag);
|
||||||
|
|
||||||
|
const std::unordered_map<uint16_t, std::pair<Entry, ADPCMParms>>& sampleEntries() const {return m_entries;}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include "IBackendVoiceAllocator.hpp"
|
#include "IBackendVoiceAllocator.hpp"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
@ -76,13 +75,14 @@ class BooBackendMIDIReader : public IMIDIReader, public boo::IMIDIReader
|
||||||
std::unique_ptr<boo::IMIDIIn> m_midiIn;
|
std::unique_ptr<boo::IMIDIIn> m_midiIn;
|
||||||
boo::MIDIDecoder m_decoder;
|
boo::MIDIDecoder m_decoder;
|
||||||
|
|
||||||
std::list<std::pair<std::chrono::steady_clock::time_point, std::vector<uint8_t>>> m_queue;
|
bool m_useLock;
|
||||||
|
std::list<std::pair<double, std::vector<uint8_t>>> m_queue;
|
||||||
std::mutex m_midiMutex;
|
std::mutex m_midiMutex;
|
||||||
void _MIDIReceive(std::vector<uint8_t>&& bytes);
|
void _MIDIReceive(std::vector<uint8_t>&& bytes, double time);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~BooBackendMIDIReader();
|
~BooBackendMIDIReader();
|
||||||
BooBackendMIDIReader(Engine& engine, const char* name);
|
BooBackendMIDIReader(Engine& engine, const char* name, bool useLock);
|
||||||
|
|
||||||
std::string description();
|
std::string description();
|
||||||
void pumpReader(double dt);
|
void pumpReader(double dt);
|
||||||
|
|
|
@ -37,6 +37,7 @@ public:
|
||||||
static const char* TypeToName(Type tp);
|
static const char* TypeToName(Type tp);
|
||||||
static Type DetectContainerType(const char* path);
|
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);
|
||||||
|
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);
|
static std::vector<std::pair<std::string, SongData>> LoadSongs(const char* path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Sequencer : public Entity
|
||||||
{
|
{
|
||||||
friend class Engine;
|
friend class Engine;
|
||||||
const SongGroupIndex& m_songGroup; /**< Quick access to song group project index */
|
const SongGroupIndex& m_songGroup; /**< Quick access to song group project index */
|
||||||
const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup */
|
const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup (may be null) */
|
||||||
Submix* m_submix = nullptr; /**< Submix this sequencer outputs to (or NULL for the main output mix) */
|
Submix* m_submix = nullptr; /**< Submix this sequencer outputs to (or NULL for the main output mix) */
|
||||||
|
|
||||||
const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */
|
const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */
|
||||||
|
@ -44,7 +44,7 @@ class Sequencer : public Entity
|
||||||
{
|
{
|
||||||
Sequencer& m_parent;
|
Sequencer& m_parent;
|
||||||
uint8_t m_chanId;
|
uint8_t m_chanId;
|
||||||
const SongGroupIndex::MIDISetup& m_setup;
|
const SongGroupIndex::MIDISetup* m_setup = nullptr; /* Channel defaults to program 0 if null */
|
||||||
const SongGroupIndex::PageEntry* m_page = nullptr;
|
const SongGroupIndex::PageEntry* m_page = nullptr;
|
||||||
~ChannelState();
|
~ChannelState();
|
||||||
ChannelState(Sequencer& parent, uint8_t chanId);
|
ChannelState(Sequencer& parent, uint8_t chanId);
|
||||||
|
@ -79,6 +79,7 @@ class Sequencer : public Entity
|
||||||
|
|
||||||
void _bringOutYourDead();
|
void _bringOutYourDead();
|
||||||
void _destroy();
|
void _destroy();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~Sequencer();
|
~Sequencer();
|
||||||
Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
||||||
|
|
|
@ -15,7 +15,9 @@ IntrusiveAudioGroupData::~IntrusiveAudioGroupData()
|
||||||
}
|
}
|
||||||
|
|
||||||
IntrusiveAudioGroupData::IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other)
|
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;
|
m_owns = other.m_owns;
|
||||||
other.m_owns = false;
|
other.m_owns = false;
|
||||||
|
|
|
@ -145,7 +145,7 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data,
|
||||||
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
|
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
|
||||||
ent.setIntoMusyX2(store.first);
|
ent.setIntoMusyX2(store.first);
|
||||||
|
|
||||||
memcpy(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
|
memmove(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
|
||||||
store.second.swapBigVADPCM();
|
store.second.swapBigVADPCM();
|
||||||
|
|
||||||
cur += 28;
|
cur += 28;
|
||||||
|
@ -161,7 +161,7 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data,
|
||||||
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
|
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
|
||||||
ent.setIntoMusyX2(store.first);
|
ent.setIntoMusyX2(store.first);
|
||||||
|
|
||||||
memcpy(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
|
memmove(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
|
||||||
store.second.swapBigVADPCM();
|
store.second.swapBigVADPCM();
|
||||||
|
|
||||||
cur += 24;
|
cur += 24;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "amuse/Voice.hpp"
|
#include "amuse/Voice.hpp"
|
||||||
#include "amuse/Submix.hpp"
|
#include "amuse/Submix.hpp"
|
||||||
#include "amuse/Engine.hpp"
|
#include "amuse/Engine.hpp"
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
@ -119,8 +120,8 @@ std::string BooBackendMIDIReader::description()
|
||||||
|
|
||||||
BooBackendMIDIReader::~BooBackendMIDIReader() {}
|
BooBackendMIDIReader::~BooBackendMIDIReader() {}
|
||||||
|
|
||||||
BooBackendMIDIReader::BooBackendMIDIReader(Engine& engine, const char* name)
|
BooBackendMIDIReader::BooBackendMIDIReader(Engine& engine, const char* name, bool useLock)
|
||||||
: m_engine(engine), m_decoder(*this)
|
: m_engine(engine), m_decoder(*this), m_useLock(useLock)
|
||||||
{
|
{
|
||||||
BooBackendVoiceAllocator& voxAlloc = static_cast<BooBackendVoiceAllocator&>(engine.getBackend());
|
BooBackendVoiceAllocator& voxAlloc = static_cast<BooBackendVoiceAllocator&>(engine.getBackend());
|
||||||
if (!name)
|
if (!name)
|
||||||
|
@ -130,40 +131,46 @@ BooBackendMIDIReader::BooBackendMIDIReader(Engine& engine, const char* name)
|
||||||
{
|
{
|
||||||
m_midiIn = voxAlloc.m_booEngine.newRealMIDIIn(dev.first.c_str(),
|
m_midiIn = voxAlloc.m_booEngine.newRealMIDIIn(dev.first.c_str(),
|
||||||
std::bind(&BooBackendMIDIReader::_MIDIReceive, this,
|
std::bind(&BooBackendMIDIReader::_MIDIReceive, this,
|
||||||
std::placeholders::_1));
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
if (m_midiIn)
|
if (m_midiIn)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_midiIn = voxAlloc.m_booEngine.newVirtualMIDIIn(std::bind(&BooBackendMIDIReader::_MIDIReceive, this,
|
m_midiIn = voxAlloc.m_booEngine.newVirtualMIDIIn(std::bind(&BooBackendMIDIReader::_MIDIReceive, this,
|
||||||
std::placeholders::_1));
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_midiIn = voxAlloc.m_booEngine.newRealMIDIIn(name,
|
m_midiIn = voxAlloc.m_booEngine.newRealMIDIIn(name,
|
||||||
std::bind(&BooBackendMIDIReader::_MIDIReceive, this,
|
std::bind(&BooBackendMIDIReader::_MIDIReceive, this,
|
||||||
std::placeholders::_1));
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendMIDIReader::_MIDIReceive(std::vector<uint8_t>&& bytes)
|
void BooBackendMIDIReader::_MIDIReceive(std::vector<uint8_t>&& bytes, double time)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lk(m_midiMutex);
|
std::unique_lock<std::mutex> lk(m_midiMutex, std::defer_lock_t{});
|
||||||
m_queue.emplace_back(std::chrono::steady_clock::now(), std::move(bytes));
|
if (m_useLock) lk.lock();
|
||||||
|
m_queue.emplace_back(time, std::move(bytes));
|
||||||
|
#if 0
|
||||||
|
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
|
||||||
|
syslog(LOG_EMERG, "MIDI receive %f\n", time);
|
||||||
|
closelog();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendMIDIReader::pumpReader(double dt)
|
void BooBackendMIDIReader::pumpReader(double dt)
|
||||||
{
|
{
|
||||||
dt += 0.001; /* Add 1ms to ensure consumer keeps up with producer */
|
dt += 0.001; /* Add 1ms to ensure consumer keeps up with producer */
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lk(m_midiMutex);
|
std::unique_lock<std::mutex> lk(m_midiMutex, std::defer_lock_t{});
|
||||||
|
if (m_useLock) lk.lock();
|
||||||
if (m_queue.empty())
|
if (m_queue.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Determine range of buffer updates within this period */
|
/* Determine range of buffer updates within this period */
|
||||||
auto periodEnd = m_queue.cbegin();
|
auto periodEnd = m_queue.cbegin();
|
||||||
std::chrono::steady_clock::time_point startPt = m_queue.front().first;
|
double startPt = m_queue.front().first;
|
||||||
for (; periodEnd != m_queue.cend() ; ++periodEnd)
|
for (; periodEnd != m_queue.cend() ; ++periodEnd)
|
||||||
{
|
{
|
||||||
double delta = std::chrono::duration_cast<std::chrono::microseconds>
|
double delta = periodEnd->first - startPt;
|
||||||
(periodEnd->first - startPt).count() / 1000000.0;
|
|
||||||
if (delta > dt)
|
if (delta > dt)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -174,6 +181,15 @@ void BooBackendMIDIReader::pumpReader(double dt)
|
||||||
/* Dispatch buffers */
|
/* Dispatch buffers */
|
||||||
for (auto it = m_queue.begin() ; it != periodEnd ;)
|
for (auto it = m_queue.begin() ; it != periodEnd ;)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
|
char str[64];
|
||||||
|
sprintf(str, "MIDI %zu %f ", it->second.size(), it->first);
|
||||||
|
for (uint8_t byte : it->second)
|
||||||
|
sprintf(str + strlen(str), "%02X ", byte);
|
||||||
|
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
|
||||||
|
syslog(LOG_EMERG, "%s\n", str);
|
||||||
|
closelog();
|
||||||
|
#endif
|
||||||
m_decoder.receiveBytes(it->second.cbegin(), it->second.cend());
|
m_decoder.receiveBytes(it->second.cbegin(), it->second.cend());
|
||||||
it = m_queue.erase(it);
|
it = m_queue.erase(it);
|
||||||
}
|
}
|
||||||
|
@ -183,12 +199,22 @@ void BooBackendMIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
{
|
{
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
|
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
|
||||||
seq->keyOff(chan, key, velocity);
|
seq->keyOff(chan, key, velocity);
|
||||||
|
#if 0
|
||||||
|
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
|
||||||
|
syslog(LOG_EMERG, "NoteOff %d", key);
|
||||||
|
closelog();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendMIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
void BooBackendMIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
{
|
{
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
|
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
|
||||||
seq->keyOn(chan, key, velocity);
|
seq->keyOn(chan, key, velocity);
|
||||||
|
#if 0
|
||||||
|
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
|
||||||
|
syslog(LOG_EMERG, "NoteOn %d", key);
|
||||||
|
closelog();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendMIDIReader::notePressure(uint8_t /*chan*/, uint8_t /*key*/, uint8_t /*pressure*/)
|
void BooBackendMIDIReader::notePressure(uint8_t /*chan*/, uint8_t /*key*/, uint8_t /*pressure*/)
|
||||||
|
@ -308,7 +334,7 @@ std::vector<std::pair<std::string, std::string>> BooBackendVoiceAllocator::enume
|
||||||
|
|
||||||
std::unique_ptr<IMIDIReader> BooBackendVoiceAllocator::allocateMIDIReader(Engine& engine, const char* name)
|
std::unique_ptr<IMIDIReader> BooBackendVoiceAllocator::allocateMIDIReader(Engine& engine, const char* name)
|
||||||
{
|
{
|
||||||
std::unique_ptr<IMIDIReader> ret = std::make_unique<BooBackendMIDIReader>(engine, name);
|
std::unique_ptr<IMIDIReader> ret = std::make_unique<BooBackendMIDIReader>(engine, name, m_booEngine.useMIDILock());
|
||||||
if (!static_cast<BooBackendMIDIReader&>(*ret).m_midiIn)
|
if (!static_cast<BooBackendMIDIReader&>(*ret).m_midiIn)
|
||||||
return {};
|
return {};
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -49,17 +49,17 @@ const char* ContainerRegistry::TypeToName(Type tp)
|
||||||
case Type::MetroidPrime2:
|
case Type::MetroidPrime2:
|
||||||
return "Metroid Prime 2 (GCN)";
|
return "Metroid Prime 2 (GCN)";
|
||||||
case Type::RogueSquadronPC:
|
case Type::RogueSquadronPC:
|
||||||
return "Star Wars: Rogue Squadron (PC)";
|
return "Star Wars - Rogue Squadron (PC)";
|
||||||
case Type::RogueSquadronN64:
|
case Type::RogueSquadronN64:
|
||||||
return "Star Wars: Rogue Squadron (N64)";
|
return "Star Wars - Rogue Squadron (N64)";
|
||||||
case Type::BattleForNabooPC:
|
case Type::BattleForNabooPC:
|
||||||
return "Star Wars Episode I: Battle for Naboo (PC)";
|
return "Star Wars Episode I - Battle for Naboo (PC)";
|
||||||
case Type::BattleForNabooN64:
|
case Type::BattleForNabooN64:
|
||||||
return "Star Wars Episode I: Battle for Naboo (N64)";
|
return "Star Wars Episode I - Battle for Naboo (N64)";
|
||||||
case Type::RogueSquadron2:
|
case Type::RogueSquadron2:
|
||||||
return "Star Wars: Rogue Squadron 2 (GCN)";
|
return "Star Wars - Rogue Squadron 2 (GCN)";
|
||||||
case Type::RogueSquadron3:
|
case Type::RogueSquadron3:
|
||||||
return "Star Wars: Rogue Squadron 3 (GCN)";
|
return "Star Wars - Rogue Squadron 3 (GCN)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,8 @@ static bool IsSongExtension(const char* path, const char*& dotOut)
|
||||||
|
|
||||||
static bool ValidateMP1(FILE* fp)
|
static bool ValidateMP1(FILE* fp)
|
||||||
{
|
{
|
||||||
FileLength(fp);
|
if (FileLength(fp) > 40 * 1024 * 1024)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
fread(&magic, 1, 4, fp);
|
fread(&magic, 1, 4, fp);
|
||||||
|
@ -228,29 +229,34 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadMP1(FILE
|
||||||
ReadString(fp);
|
ReadString(fp);
|
||||||
std::string name = ReadString(fp);
|
std::string name = ReadString(fp);
|
||||||
|
|
||||||
uint32_t len;
|
uint32_t poolLen;
|
||||||
fread(&len, 1, 4, fp);
|
fread(&poolLen, 1, 4, fp);
|
||||||
len = SBig(len);
|
poolLen = SBig(poolLen);
|
||||||
std::unique_ptr<uint8_t[]> pool(new uint8_t[len]);
|
std::unique_ptr<uint8_t[]> pool(new uint8_t[poolLen]);
|
||||||
fread(pool.get(), 1, len, fp);
|
fread(pool.get(), 1, poolLen, fp);
|
||||||
|
|
||||||
fread(&len, 1, 4, fp);
|
uint32_t projLen;
|
||||||
len = SBig(len);
|
fread(&projLen, 1, 4, fp);
|
||||||
std::unique_ptr<uint8_t[]> proj(new uint8_t[len]);
|
projLen = SBig(projLen);
|
||||||
fread(proj.get(), 1, len, fp);
|
std::unique_ptr<uint8_t[]> proj(new uint8_t[projLen]);
|
||||||
|
fread(proj.get(), 1, projLen, fp);
|
||||||
|
|
||||||
fread(&len, 1, 4, fp);
|
uint32_t sampLen;
|
||||||
len = SBig(len);
|
fread(&sampLen, 1, 4, fp);
|
||||||
std::unique_ptr<uint8_t[]> samp(new uint8_t[len]);
|
sampLen = SBig(sampLen);
|
||||||
fread(samp.get(), 1, len, fp);
|
std::unique_ptr<uint8_t[]> samp(new uint8_t[sampLen]);
|
||||||
|
fread(samp.get(), 1, sampLen, fp);
|
||||||
|
|
||||||
fread(&len, 1, 4, fp);
|
uint32_t sdirLen;
|
||||||
len = SBig(len);
|
fread(&sdirLen, 1, 4, fp);
|
||||||
std::unique_ptr<uint8_t[]> sdir(new uint8_t[len]);
|
sdirLen = SBig(sdirLen);
|
||||||
fread(sdir.get(), 1, len, fp);
|
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(),
|
ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), projLen,
|
||||||
sdir.release(), samp.release(), GCNDataTag{}});
|
pool.release(), poolLen,
|
||||||
|
sdir.release(), sdirLen,
|
||||||
|
samp.release(), sampLen, GCNDataTag{}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FSeek(fp, origPos, SEEK_SET);
|
FSeek(fp, origPos, SEEK_SET);
|
||||||
|
@ -263,7 +269,8 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadMP1(FILE
|
||||||
|
|
||||||
static bool ValidateMP1Songs(FILE* fp)
|
static bool ValidateMP1Songs(FILE* fp)
|
||||||
{
|
{
|
||||||
FileLength(fp);
|
if (FileLength(fp) > 40 * 1024 * 1024)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
fread(&magic, 1, 4, fp);
|
fread(&magic, 1, 4, fp);
|
||||||
|
@ -404,7 +411,8 @@ static std::vector<std::pair<std::string, ContainerRegistry::SongData>> LoadMP1S
|
||||||
|
|
||||||
static bool ValidateMP2(FILE* fp)
|
static bool ValidateMP2(FILE* fp)
|
||||||
{
|
{
|
||||||
FileLength(fp);
|
if (FileLength(fp) > 40 * 1024 * 1024)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
fread(&magic, 1, 4, fp);
|
fread(&magic, 1, 4, fp);
|
||||||
|
@ -529,6 +537,8 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadMP2(FILE
|
||||||
fread(&sampSz, 1, 4, fp);
|
fread(&sampSz, 1, 4, fp);
|
||||||
sampSz = SBig(sampSz);
|
sampSz = SBig(sampSz);
|
||||||
|
|
||||||
|
if (projSz && poolSz && sdirSz && sampSz)
|
||||||
|
{
|
||||||
std::unique_ptr<uint8_t[]> pool(new uint8_t[poolSz]);
|
std::unique_ptr<uint8_t[]> pool(new uint8_t[poolSz]);
|
||||||
fread(pool.get(), 1, poolSz, fp);
|
fread(pool.get(), 1, poolSz, fp);
|
||||||
|
|
||||||
|
@ -541,8 +551,11 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadMP2(FILE
|
||||||
std::unique_ptr<uint8_t[]> samp(new uint8_t[sampSz]);
|
std::unique_ptr<uint8_t[]> samp(new uint8_t[sampSz]);
|
||||||
fread(samp.get(), 1, sampSz, fp);
|
fread(samp.get(), 1, sampSz, fp);
|
||||||
|
|
||||||
ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), pool.release(),
|
ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), projSz,
|
||||||
sdir.release(), samp.release(), GCNDataTag{}});
|
pool.release(), poolSz,
|
||||||
|
sdir.release(), sdirSz,
|
||||||
|
samp.release(), sampSz, GCNDataTag{}});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FSeek(fp, origPos, SEEK_SET);
|
FSeek(fp, origPos, SEEK_SET);
|
||||||
|
@ -589,6 +602,8 @@ static void SwapN64Rom32(void* data, size_t size)
|
||||||
static bool ValidateRS1PC(FILE* fp)
|
static bool ValidateRS1PC(FILE* fp)
|
||||||
{
|
{
|
||||||
size_t endPos = FileLength(fp);
|
size_t endPos = FileLength(fp);
|
||||||
|
if (endPos > 100 * 1024 * 1024)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint32_t fstOff;
|
uint32_t fstOff;
|
||||||
uint32_t fstSz;
|
uint32_t fstSz;
|
||||||
|
@ -640,41 +655,49 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1PC(FI
|
||||||
fread(entries.get(), fstSz, 1, fp);
|
fread(entries.get(), fstSz, 1, fp);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> proj;
|
std::unique_ptr<uint8_t[]> proj;
|
||||||
|
size_t projSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> pool;
|
std::unique_ptr<uint8_t[]> pool;
|
||||||
|
size_t poolSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> sdir;
|
std::unique_ptr<uint8_t[]> sdir;
|
||||||
|
size_t sdirSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> samp;
|
std::unique_ptr<uint8_t[]> samp;
|
||||||
|
size_t sampSz = 0;
|
||||||
|
|
||||||
for (uint32_t i=0 ; i<elemCount ; ++i)
|
for (uint32_t i=0 ; i<elemCount ; ++i)
|
||||||
{
|
{
|
||||||
RS1FSTEntry& entry = entries[i];
|
RS1FSTEntry& entry = entries[i];
|
||||||
if (!strncmp("proj_SND", entry.name, 16))
|
if (!strncmp("proj_SND", entry.name, 16))
|
||||||
{
|
{
|
||||||
|
projSz = entry.decompSz;
|
||||||
proj.reset(new uint8_t[entry.decompSz]);
|
proj.reset(new uint8_t[entry.decompSz]);
|
||||||
FSeek(fp, entry.offset, SEEK_SET);
|
FSeek(fp, entry.offset, SEEK_SET);
|
||||||
fread(proj.get(), 1, entry.decompSz, fp);
|
fread(proj.get(), 1, entry.decompSz, fp);
|
||||||
}
|
}
|
||||||
else if (!strncmp("pool_SND", entry.name, 16))
|
else if (!strncmp("pool_SND", entry.name, 16))
|
||||||
{
|
{
|
||||||
|
poolSz = entry.decompSz;
|
||||||
pool.reset(new uint8_t[entry.decompSz]);
|
pool.reset(new uint8_t[entry.decompSz]);
|
||||||
FSeek(fp, entry.offset, SEEK_SET);
|
FSeek(fp, entry.offset, SEEK_SET);
|
||||||
fread(pool.get(), 1, entry.decompSz, fp);
|
fread(pool.get(), 1, entry.decompSz, fp);
|
||||||
}
|
}
|
||||||
else if (!strncmp("sdir_SND", entry.name, 16))
|
else if (!strncmp("sdir_SND", entry.name, 16))
|
||||||
{
|
{
|
||||||
|
sdirSz = entry.decompSz;
|
||||||
sdir.reset(new uint8_t[entry.decompSz]);
|
sdir.reset(new uint8_t[entry.decompSz]);
|
||||||
FSeek(fp, entry.offset, SEEK_SET);
|
FSeek(fp, entry.offset, SEEK_SET);
|
||||||
fread(sdir.get(), 1, entry.decompSz, fp);
|
fread(sdir.get(), 1, entry.decompSz, fp);
|
||||||
}
|
}
|
||||||
else if (!strncmp("samp_SND", entry.name, 16))
|
else if (!strncmp("samp_SND", entry.name, 16))
|
||||||
{
|
{
|
||||||
|
sampSz = entry.decompSz;
|
||||||
samp.reset(new uint8_t[entry.decompSz]);
|
samp.reset(new uint8_t[entry.decompSz]);
|
||||||
FSeek(fp, entry.offset, SEEK_SET);
|
FSeek(fp, entry.offset, SEEK_SET);
|
||||||
fread(samp.get(), 1, entry.decompSz, fp);
|
fread(samp.get(), 1, entry.decompSz, fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz,
|
||||||
sdir.release(), samp.release(),
|
sdir.release(), sdirSz, samp.release(), sampSz,
|
||||||
false, PCDataTag{}});
|
false, PCDataTag{}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -764,9 +787,13 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
||||||
const RS1FSTEntry* lastEnt = reinterpret_cast<const RS1FSTEntry*>(dataSeg + fstEnd);
|
const RS1FSTEntry* lastEnt = reinterpret_cast<const RS1FSTEntry*>(dataSeg + fstEnd);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> proj;
|
std::unique_ptr<uint8_t[]> proj;
|
||||||
|
size_t projSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> pool;
|
std::unique_ptr<uint8_t[]> pool;
|
||||||
|
size_t poolSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> sdir;
|
std::unique_ptr<uint8_t[]> sdir;
|
||||||
|
size_t sdirSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> samp;
|
std::unique_ptr<uint8_t[]> samp;
|
||||||
|
size_t sampSz = 0;
|
||||||
|
|
||||||
for (; entry != lastEnt ; ++entry)
|
for (; entry != lastEnt ; ++entry)
|
||||||
{
|
{
|
||||||
|
@ -778,7 +805,7 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
||||||
if (ent.compSz == 0xffffffff)
|
if (ent.compSz == 0xffffffff)
|
||||||
{
|
{
|
||||||
proj.reset(new uint8_t[ent.decompSz]);
|
proj.reset(new uint8_t[ent.decompSz]);
|
||||||
memcpy(proj.get(), dataSeg + ent.offset, ent.decompSz);
|
memmove(proj.get(), dataSeg + ent.offset, ent.decompSz);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -786,13 +813,14 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
||||||
uLongf outSz = ent.decompSz;
|
uLongf outSz = ent.decompSz;
|
||||||
uncompress(proj.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
uncompress(proj.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||||
}
|
}
|
||||||
|
projSz = ent.decompSz;
|
||||||
}
|
}
|
||||||
else if (!strncmp("pool_SND", ent.name, 16))
|
else if (!strncmp("pool_SND", ent.name, 16))
|
||||||
{
|
{
|
||||||
if (ent.compSz == 0xffffffff)
|
if (ent.compSz == 0xffffffff)
|
||||||
{
|
{
|
||||||
pool.reset(new uint8_t[ent.decompSz]);
|
pool.reset(new uint8_t[ent.decompSz]);
|
||||||
memcpy(pool.get(), dataSeg + ent.offset, ent.decompSz);
|
memmove(pool.get(), dataSeg + ent.offset, ent.decompSz);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -800,13 +828,14 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
||||||
uLongf outSz = ent.decompSz;
|
uLongf outSz = ent.decompSz;
|
||||||
uncompress(pool.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
uncompress(pool.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||||
}
|
}
|
||||||
|
poolSz = ent.decompSz;
|
||||||
}
|
}
|
||||||
else if (!strncmp("sdir_SND", ent.name, 16))
|
else if (!strncmp("sdir_SND", ent.name, 16))
|
||||||
{
|
{
|
||||||
if (ent.compSz == 0xffffffff)
|
if (ent.compSz == 0xffffffff)
|
||||||
{
|
{
|
||||||
sdir.reset(new uint8_t[ent.decompSz]);
|
sdir.reset(new uint8_t[ent.decompSz]);
|
||||||
memcpy(sdir.get(), dataSeg + ent.offset, ent.decompSz);
|
memmove(sdir.get(), dataSeg + ent.offset, ent.decompSz);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -814,13 +843,14 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
||||||
uLongf outSz = ent.decompSz;
|
uLongf outSz = ent.decompSz;
|
||||||
uncompress(sdir.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
uncompress(sdir.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||||
}
|
}
|
||||||
|
sdirSz = ent.decompSz;
|
||||||
}
|
}
|
||||||
else if (!strncmp("samp_SND", ent.name, 16))
|
else if (!strncmp("samp_SND", ent.name, 16))
|
||||||
{
|
{
|
||||||
if (ent.compSz == 0xffffffff)
|
if (ent.compSz == 0xffffffff)
|
||||||
{
|
{
|
||||||
samp.reset(new uint8_t[ent.decompSz]);
|
samp.reset(new uint8_t[ent.decompSz]);
|
||||||
memcpy(samp.get(), dataSeg + ent.offset, ent.decompSz);
|
memmove(samp.get(), dataSeg + ent.offset, ent.decompSz);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -828,11 +858,12 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
||||||
uLongf outSz = ent.decompSz;
|
uLongf outSz = ent.decompSz;
|
||||||
uncompress(samp.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
uncompress(samp.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||||
}
|
}
|
||||||
|
sampSz = ent.decompSz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz,
|
||||||
sdir.release(), samp.release(),
|
sdir.release(), sdirSz, samp.release(), sampSz,
|
||||||
false, N64DataTag{}});
|
false, N64DataTag{}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,6 +873,8 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
|
||||||
static bool ValidateBFNPC(FILE* fp)
|
static bool ValidateBFNPC(FILE* fp)
|
||||||
{
|
{
|
||||||
size_t endPos = FileLength(fp);
|
size_t endPos = FileLength(fp);
|
||||||
|
if (endPos > 100 * 1024 * 1024)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint32_t fstOff;
|
uint32_t fstOff;
|
||||||
uint32_t fstSz;
|
uint32_t fstSz;
|
||||||
|
@ -893,9 +926,13 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNPC(FI
|
||||||
fread(entries.get(), fstSz, 1, fp);
|
fread(entries.get(), fstSz, 1, fp);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> proj;
|
std::unique_ptr<uint8_t[]> proj;
|
||||||
|
size_t projSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> pool;
|
std::unique_ptr<uint8_t[]> pool;
|
||||||
|
size_t poolSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> sdir;
|
std::unique_ptr<uint8_t[]> sdir;
|
||||||
|
size_t sdirSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> samp;
|
std::unique_ptr<uint8_t[]> samp;
|
||||||
|
size_t sampSz = 0;
|
||||||
|
|
||||||
for (uint32_t i=0 ; i<elemCount ; ++i)
|
for (uint32_t i=0 ; i<elemCount ; ++i)
|
||||||
{
|
{
|
||||||
|
@ -905,29 +942,33 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNPC(FI
|
||||||
proj.reset(new uint8_t[entry.decompSz]);
|
proj.reset(new uint8_t[entry.decompSz]);
|
||||||
FSeek(fp, entry.offset, SEEK_SET);
|
FSeek(fp, entry.offset, SEEK_SET);
|
||||||
fread(proj.get(), 1, entry.decompSz, fp);
|
fread(proj.get(), 1, entry.decompSz, fp);
|
||||||
|
projSz = entry.decompSz;
|
||||||
}
|
}
|
||||||
else if (!strncmp("pool", entry.name, 16))
|
else if (!strncmp("pool", entry.name, 16))
|
||||||
{
|
{
|
||||||
pool.reset(new uint8_t[entry.decompSz]);
|
pool.reset(new uint8_t[entry.decompSz]);
|
||||||
FSeek(fp, entry.offset, SEEK_SET);
|
FSeek(fp, entry.offset, SEEK_SET);
|
||||||
fread(pool.get(), 1, entry.decompSz, fp);
|
fread(pool.get(), 1, entry.decompSz, fp);
|
||||||
|
poolSz = entry.decompSz;
|
||||||
}
|
}
|
||||||
else if (!strncmp("sdir", entry.name, 16))
|
else if (!strncmp("sdir", entry.name, 16))
|
||||||
{
|
{
|
||||||
sdir.reset(new uint8_t[entry.decompSz]);
|
sdir.reset(new uint8_t[entry.decompSz]);
|
||||||
FSeek(fp, entry.offset, SEEK_SET);
|
FSeek(fp, entry.offset, SEEK_SET);
|
||||||
fread(sdir.get(), 1, entry.decompSz, fp);
|
fread(sdir.get(), 1, entry.decompSz, fp);
|
||||||
|
sdirSz = entry.decompSz;
|
||||||
}
|
}
|
||||||
else if (!strncmp("samp", entry.name, 16))
|
else if (!strncmp("samp", entry.name, 16))
|
||||||
{
|
{
|
||||||
samp.reset(new uint8_t[entry.decompSz]);
|
samp.reset(new uint8_t[entry.decompSz]);
|
||||||
FSeek(fp, entry.offset, SEEK_SET);
|
FSeek(fp, entry.offset, SEEK_SET);
|
||||||
fread(samp.get(), 1, entry.decompSz, fp);
|
fread(samp.get(), 1, entry.decompSz, fp);
|
||||||
|
sampSz = entry.decompSz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz,
|
||||||
sdir.release(), samp.release(),
|
sdir.release(), sdirSz, samp.release(), sampSz,
|
||||||
true, PCDataTag{}});
|
true, PCDataTag{}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1017,9 +1058,13 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(F
|
||||||
const RS1FSTEntry* lastEnt = reinterpret_cast<const RS1FSTEntry*>(dataSeg + fstEnd);
|
const RS1FSTEntry* lastEnt = reinterpret_cast<const RS1FSTEntry*>(dataSeg + fstEnd);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> proj;
|
std::unique_ptr<uint8_t[]> proj;
|
||||||
|
size_t projSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> pool;
|
std::unique_ptr<uint8_t[]> pool;
|
||||||
|
size_t poolSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> sdir;
|
std::unique_ptr<uint8_t[]> sdir;
|
||||||
|
size_t sdirSz = 0;
|
||||||
std::unique_ptr<uint8_t[]> samp;
|
std::unique_ptr<uint8_t[]> samp;
|
||||||
|
size_t sampSz = 0;
|
||||||
|
|
||||||
for (; entry != lastEnt ; ++entry)
|
for (; entry != lastEnt ; ++entry)
|
||||||
{
|
{
|
||||||
|
@ -1031,7 +1076,7 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(F
|
||||||
if (ent.compSz == 0xffffffff)
|
if (ent.compSz == 0xffffffff)
|
||||||
{
|
{
|
||||||
proj.reset(new uint8_t[ent.decompSz]);
|
proj.reset(new uint8_t[ent.decompSz]);
|
||||||
memcpy(proj.get(), dataSeg + ent.offset, ent.decompSz);
|
memmove(proj.get(), dataSeg + ent.offset, ent.decompSz);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1039,13 +1084,14 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(F
|
||||||
uLongf outSz = ent.decompSz;
|
uLongf outSz = ent.decompSz;
|
||||||
uncompress(proj.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
uncompress(proj.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||||
}
|
}
|
||||||
|
projSz = ent.decompSz;
|
||||||
}
|
}
|
||||||
else if (!strncmp("pool", ent.name, 16))
|
else if (!strncmp("pool", ent.name, 16))
|
||||||
{
|
{
|
||||||
if (ent.compSz == 0xffffffff)
|
if (ent.compSz == 0xffffffff)
|
||||||
{
|
{
|
||||||
pool.reset(new uint8_t[ent.decompSz]);
|
pool.reset(new uint8_t[ent.decompSz]);
|
||||||
memcpy(pool.get(), dataSeg + ent.offset, ent.decompSz);
|
memmove(pool.get(), dataSeg + ent.offset, ent.decompSz);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1053,13 +1099,14 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(F
|
||||||
uLongf outSz = ent.decompSz;
|
uLongf outSz = ent.decompSz;
|
||||||
uncompress(pool.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
uncompress(pool.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||||
}
|
}
|
||||||
|
poolSz = ent.decompSz;
|
||||||
}
|
}
|
||||||
else if (!strncmp("sdir", ent.name, 16))
|
else if (!strncmp("sdir", ent.name, 16))
|
||||||
{
|
{
|
||||||
if (ent.compSz == 0xffffffff)
|
if (ent.compSz == 0xffffffff)
|
||||||
{
|
{
|
||||||
sdir.reset(new uint8_t[ent.decompSz]);
|
sdir.reset(new uint8_t[ent.decompSz]);
|
||||||
memcpy(sdir.get(), dataSeg + ent.offset, ent.decompSz);
|
memmove(sdir.get(), dataSeg + ent.offset, ent.decompSz);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1067,13 +1114,14 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(F
|
||||||
uLongf outSz = ent.decompSz;
|
uLongf outSz = ent.decompSz;
|
||||||
uncompress(sdir.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
uncompress(sdir.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||||
}
|
}
|
||||||
|
sdirSz = ent.decompSz;
|
||||||
}
|
}
|
||||||
else if (!strncmp("samp", ent.name, 16))
|
else if (!strncmp("samp", ent.name, 16))
|
||||||
{
|
{
|
||||||
if (ent.compSz == 0xffffffff)
|
if (ent.compSz == 0xffffffff)
|
||||||
{
|
{
|
||||||
samp.reset(new uint8_t[ent.decompSz]);
|
samp.reset(new uint8_t[ent.decompSz]);
|
||||||
memcpy(samp.get(), dataSeg + ent.offset, ent.decompSz);
|
memmove(samp.get(), dataSeg + ent.offset, ent.decompSz);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1081,11 +1129,12 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(F
|
||||||
uLongf outSz = ent.decompSz;
|
uLongf outSz = ent.decompSz;
|
||||||
uncompress(samp.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
uncompress(samp.get(), &outSz, dataSeg + ent.offset, ent.compSz);
|
||||||
}
|
}
|
||||||
|
sampSz = ent.decompSz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz,
|
||||||
sdir.release(), samp.release(),
|
sdir.release(), sdirSz, samp.release(), sampSz,
|
||||||
true, N64DataTag{}});
|
true, N64DataTag{}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1164,6 +1213,8 @@ struct RS23SONHead
|
||||||
static bool ValidateRS2(FILE* fp)
|
static bool ValidateRS2(FILE* fp)
|
||||||
{
|
{
|
||||||
size_t endPos = FileLength(fp);
|
size_t endPos = FileLength(fp);
|
||||||
|
if (endPos > 600 * 1024 * 1024)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint64_t fstOff;
|
uint64_t fstOff;
|
||||||
fread(&fstOff, 1, 8, fp);
|
fread(&fstOff, 1, 8, fp);
|
||||||
|
@ -1228,21 +1279,24 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS2(FILE
|
||||||
head.swapBig();
|
head.swapBig();
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> pool(new uint8_t[head.poolLen]);
|
std::unique_ptr<uint8_t[]> pool(new uint8_t[head.poolLen]);
|
||||||
memcpy(pool.get(), audData.get() + head.poolOff, head.poolLen);
|
memmove(pool.get(), audData.get() + head.poolOff, head.poolLen);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> proj(new uint8_t[head.projLen]);
|
std::unique_ptr<uint8_t[]> proj(new uint8_t[head.projLen]);
|
||||||
memcpy(proj.get(), audData.get() + head.projOff, head.projLen);
|
memmove(proj.get(), audData.get() + head.projOff, head.projLen);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> sdir(new uint8_t[head.sdirLen]);
|
std::unique_ptr<uint8_t[]> sdir(new uint8_t[head.sdirLen]);
|
||||||
memcpy(sdir.get(), audData.get() + head.sdirOff, head.sdirLen);
|
memmove(sdir.get(), audData.get() + head.sdirOff, head.sdirLen);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> samp(new uint8_t[head.sampLen]);
|
std::unique_ptr<uint8_t[]> samp(new uint8_t[head.sampLen]);
|
||||||
memcpy(samp.get(), audData.get() + head.sampOff, head.sampLen);
|
memmove(samp.get(), audData.get() + head.sampOff, head.sampLen);
|
||||||
|
|
||||||
|
if (head.projLen && head.poolLen && head.sdirLen && head.sampLen)
|
||||||
|
{
|
||||||
char name[128];
|
char name[128];
|
||||||
snprintf(name, 128, "GroupFile%u", j);
|
snprintf(name, 128, "GroupFile%02u", j);
|
||||||
ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), pool.release(),
|
ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), head.projLen, pool.release(), head.poolLen,
|
||||||
sdir.release(), samp.release(), GCNDataTag{}});
|
sdir.release(), head.sdirLen, samp.release(), head.sampLen, GCNDataTag{}});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1299,9 +1353,9 @@ static std::vector<std::pair<std::string, ContainerRegistry::SongData>> LoadRS2S
|
||||||
sonHead.swapBig();
|
sonHead.swapBig();
|
||||||
|
|
||||||
char name[128];
|
char name[128];
|
||||||
snprintf(name, 128, "GroupFile%u-%u", j, s);
|
snprintf(name, 128, "GroupFile%02u-%u", j, s);
|
||||||
std::unique_ptr<uint8_t[]> song(new uint8_t[sonHead.length]);
|
std::unique_ptr<uint8_t[]> song(new uint8_t[sonHead.length]);
|
||||||
memcpy(song.get(), audData.get() + sonHead.offset, sonHead.length);
|
memmove(song.get(), audData.get() + sonHead.offset, sonHead.length);
|
||||||
ret.emplace_back(name, ContainerRegistry::SongData(std::move(song), sonHead.length,
|
ret.emplace_back(name, ContainerRegistry::SongData(std::move(song), sonHead.length,
|
||||||
sonHead.groupId, sonHead.setupId));
|
sonHead.groupId, sonHead.setupId));
|
||||||
}
|
}
|
||||||
|
@ -1334,6 +1388,8 @@ struct RS3FSTEntry
|
||||||
static bool ValidateRS3(FILE* fp)
|
static bool ValidateRS3(FILE* fp)
|
||||||
{
|
{
|
||||||
size_t endPos = FileLength(fp);
|
size_t endPos = FileLength(fp);
|
||||||
|
if (endPos > 600 * 1024 * 1024)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint64_t fstOff;
|
uint64_t fstOff;
|
||||||
fread(&fstOff, 1, 8, fp);
|
fread(&fstOff, 1, 8, fp);
|
||||||
|
@ -1396,21 +1452,24 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS3(FILE
|
||||||
head.swapBig();
|
head.swapBig();
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> pool(new uint8_t[head.poolLen]);
|
std::unique_ptr<uint8_t[]> pool(new uint8_t[head.poolLen]);
|
||||||
memcpy(pool.get(), audData.get() + head.poolOff, head.poolLen);
|
memmove(pool.get(), audData.get() + head.poolOff, head.poolLen);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> proj(new uint8_t[head.projLen]);
|
std::unique_ptr<uint8_t[]> proj(new uint8_t[head.projLen]);
|
||||||
memcpy(proj.get(), audData.get() + head.projOff, head.projLen);
|
memmove(proj.get(), audData.get() + head.projOff, head.projLen);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> sdir(new uint8_t[head.sdirLen]);
|
std::unique_ptr<uint8_t[]> sdir(new uint8_t[head.sdirLen]);
|
||||||
memcpy(sdir.get(), audData.get() + head.sdirOff, head.sdirLen);
|
memmove(sdir.get(), audData.get() + head.sdirOff, head.sdirLen);
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> samp(new uint8_t[head.sampLen]);
|
std::unique_ptr<uint8_t[]> samp(new uint8_t[head.sampLen]);
|
||||||
memcpy(samp.get(), audData.get() + head.sampOff, head.sampLen);
|
memmove(samp.get(), audData.get() + head.sampOff, head.sampLen);
|
||||||
|
|
||||||
|
if (head.projLen && head.poolLen && head.sdirLen && head.sampLen)
|
||||||
|
{
|
||||||
char name[128];
|
char name[128];
|
||||||
snprintf(name, 128, "GroupFile%u", j);
|
snprintf(name, 128, "GroupFile%02u", j);
|
||||||
ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), pool.release(),
|
ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), head.projLen, pool.release(), head.poolLen,
|
||||||
sdir.release(), samp.release(), GCNDataTag{}});
|
sdir.release(), head.sdirLen, samp.release(), head.sampLen, GCNDataTag{}});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1541,8 +1600,16 @@ ContainerRegistry::Type ContainerRegistry::DetectContainerType(const char* path)
|
||||||
|
|
||||||
std::vector<std::pair<std::string, IntrusiveAudioGroupData>>
|
std::vector<std::pair<std::string, IntrusiveAudioGroupData>>
|
||||||
ContainerRegistry::LoadContainer(const char* path)
|
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;
|
FILE* fp;
|
||||||
|
typeOut = Type::Invalid;
|
||||||
|
|
||||||
/* See if provided file is one of four raw chunks */
|
/* See if provided file is one of four raw chunks */
|
||||||
const char* dot = nullptr;
|
const char* dot = nullptr;
|
||||||
|
@ -1603,49 +1670,50 @@ ContainerRegistry::LoadContainer(const char* path)
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
fp = fopen(projPath, "rb");
|
fp = fopen(projPath, "rb");
|
||||||
size_t fLen = FileLength(fp);
|
size_t projLen = FileLength(fp);
|
||||||
if (!fLen)
|
if (!projLen)
|
||||||
return ret;
|
return ret;
|
||||||
std::unique_ptr<uint8_t[]> proj(new uint8_t[fLen]);
|
std::unique_ptr<uint8_t[]> proj(new uint8_t[projLen]);
|
||||||
fread(proj.get(), 1, fLen, fp);
|
fread(proj.get(), 1, projLen, fp);
|
||||||
|
|
||||||
fp = fopen(poolPath, "rb");
|
fp = fopen(poolPath, "rb");
|
||||||
fLen = FileLength(fp);
|
size_t poolLen = FileLength(fp);
|
||||||
if (!fLen)
|
if (!poolLen)
|
||||||
return ret;
|
return ret;
|
||||||
std::unique_ptr<uint8_t[]> pool(new uint8_t[fLen]);
|
std::unique_ptr<uint8_t[]> pool(new uint8_t[poolLen]);
|
||||||
fread(pool.get(), 1, fLen, fp);
|
fread(pool.get(), 1, poolLen, fp);
|
||||||
|
|
||||||
fp = fopen(sdirPath, "rb");
|
fp = fopen(sdirPath, "rb");
|
||||||
fLen = FileLength(fp);
|
size_t sdirLen = FileLength(fp);
|
||||||
if (!fLen)
|
if (!sdirLen)
|
||||||
return ret;
|
return ret;
|
||||||
std::unique_ptr<uint8_t[]> sdir(new uint8_t[fLen]);
|
std::unique_ptr<uint8_t[]> sdir(new uint8_t[sdirLen]);
|
||||||
fread(sdir.get(), 1, fLen, fp);
|
fread(sdir.get(), 1, sdirLen, fp);
|
||||||
|
|
||||||
fp = fopen(sampPath, "rb");
|
fp = fopen(sampPath, "rb");
|
||||||
fLen = FileLength(fp);
|
size_t sampLen = FileLength(fp);
|
||||||
if (!fLen)
|
if (!sampPath)
|
||||||
return ret;
|
return ret;
|
||||||
std::unique_ptr<uint8_t[]> samp(new uint8_t[fLen]);
|
std::unique_ptr<uint8_t[]> samp(new uint8_t[sampLen]);
|
||||||
fread(samp.get(), 1, fLen, fp);
|
fread(samp.get(), 1, sampLen, fp);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
/* SDIR-based format detection */
|
/* SDIR-based format detection */
|
||||||
if (*reinterpret_cast<uint32_t*>(sdir.get() + 8) == 0x0)
|
if (*reinterpret_cast<uint32_t*>(sdir.get() + 8) == 0x0)
|
||||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen,
|
||||||
sdir.release(), samp.release(),
|
sdir.release(), sdirLen, samp.release(), sampLen,
|
||||||
GCNDataTag{}});
|
GCNDataTag{}});
|
||||||
else if (sdir[9] == 0x0)
|
else if (sdir[9] == 0x0)
|
||||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen,
|
||||||
sdir.release(), samp.release(),
|
sdir.release(), sdirLen, samp.release(), sampLen,
|
||||||
false, N64DataTag{}});
|
false, N64DataTag{}});
|
||||||
else
|
else
|
||||||
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
|
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen,
|
||||||
sdir.release(), samp.release(),
|
sdir.release(), sdirLen, samp.release(), sampLen,
|
||||||
false, PCDataTag{}});
|
false, PCDataTag{}});
|
||||||
|
|
||||||
|
typeOut = Type::Raw4;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1657,6 +1725,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
||||||
{
|
{
|
||||||
auto ret = LoadMP1(fp);
|
auto ret = LoadMP1(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
typeOut = Type::MetroidPrime;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1664,6 +1733,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
||||||
{
|
{
|
||||||
auto ret = LoadMP2(fp);
|
auto ret = LoadMP2(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
typeOut = Type::MetroidPrime2;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1671,6 +1741,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
||||||
{
|
{
|
||||||
auto ret = LoadRS1PC(fp);
|
auto ret = LoadRS1PC(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
typeOut = Type::RogueSquadronPC;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1678,6 +1749,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
||||||
{
|
{
|
||||||
auto ret = LoadRS1N64(fp);
|
auto ret = LoadRS1N64(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
typeOut = Type::RogueSquadronN64;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1685,6 +1757,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
||||||
{
|
{
|
||||||
auto ret = LoadBFNPC(fp);
|
auto ret = LoadBFNPC(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
typeOut = Type::BattleForNabooPC;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1692,6 +1765,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
||||||
{
|
{
|
||||||
auto ret = LoadBFNN64(fp);
|
auto ret = LoadBFNN64(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
typeOut = Type::BattleForNabooN64;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1699,6 +1773,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
||||||
{
|
{
|
||||||
auto ret = LoadRS2(fp);
|
auto ret = LoadRS2(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
typeOut = Type::RogueSquadron2;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1706,6 +1781,7 @@ ContainerRegistry::LoadContainer(const char* path)
|
||||||
{
|
{
|
||||||
auto ret = LoadRS3(fp);
|
auto ret = LoadRS3(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
typeOut = Type::RogueSquadron3;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ unsigned N64MusyXDecompressFrame(int16_t* out, const uint8_t* in,
|
||||||
adpcm_get_predicted_frame(frame, &in[0x0], &in[0x8], rshift);
|
adpcm_get_predicted_frame(frame, &in[0x0], &in[0x8], rshift);
|
||||||
|
|
||||||
procSamples = (remSamples < 2) ? remSamples : 2;
|
procSamples = (remSamples < 2) ? remSamples : 2;
|
||||||
memcpy(out, frame, 2 * procSamples);
|
memmove(out, frame, 2 * procSamples);
|
||||||
samples += procSamples;
|
samples += procSamples;
|
||||||
remSamples -= procSamples;
|
remSamples -= procSamples;
|
||||||
if (samples == lastSample)
|
if (samples == lastSample)
|
||||||
|
@ -124,7 +124,7 @@ unsigned N64MusyXDecompressFrame(int16_t* out, const uint8_t* in,
|
||||||
adpcm_get_predicted_frame(frame, &in[0x4], &in[0x18], rshift);
|
adpcm_get_predicted_frame(frame, &in[0x4], &in[0x18], rshift);
|
||||||
|
|
||||||
procSamples = (remSamples < 2) ? remSamples : 2;
|
procSamples = (remSamples < 2) ? remSamples : 2;
|
||||||
memcpy(out, frame, 2 * procSamples);
|
memmove(out, frame, 2 * procSamples);
|
||||||
samples += procSamples;
|
samples += procSamples;
|
||||||
remSamples -= procSamples;
|
remSamples -= procSamples;
|
||||||
if (samples == lastSample)
|
if (samples == lastSample)
|
||||||
|
@ -145,7 +145,7 @@ unsigned N64MusyXDecompressFrameRanged(int16_t* out, const uint8_t* in,
|
||||||
int16_t final[64];
|
int16_t final[64];
|
||||||
unsigned procSamples = N64MusyXDecompressFrame(final, in, coefs, firstSample + lastSample);
|
unsigned procSamples = N64MusyXDecompressFrame(final, in, coefs, firstSample + lastSample);
|
||||||
unsigned samples = procSamples - firstSample;
|
unsigned samples = procSamples - firstSample;
|
||||||
memcpy(out, final + firstSample, samples * 2);
|
memmove(out, final + firstSample, samples * 2);
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
||||||
m_midiSetup = it->second->data();
|
m_midiSetup = it->second->data();
|
||||||
|
|
||||||
m_submix = m_engine.addSubmix(smx);
|
m_submix = m_engine.addSubmix(smx);
|
||||||
m_submix->makeReverbHi(0.2f, 1.f, 1.f, 0.5f, 0.f, 0.f);
|
m_submix->makeReverbHi(0.2f, 0.65f, 1.f, 0.5f, 0.f, 0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequencer::ChannelState::~ChannelState()
|
Sequencer::ChannelState::~ChannelState()
|
||||||
|
@ -79,27 +79,53 @@ Sequencer::ChannelState::~ChannelState()
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
|
Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
|
||||||
: m_parent(parent), m_chanId(chanId), m_setup(m_parent.m_midiSetup[chanId])
|
: m_parent(parent), m_chanId(chanId)
|
||||||
{
|
{
|
||||||
|
if (m_parent.m_midiSetup)
|
||||||
|
{
|
||||||
|
m_setup = &m_parent.m_midiSetup[chanId];
|
||||||
|
|
||||||
if (chanId == 9)
|
if (chanId == 9)
|
||||||
{
|
{
|
||||||
auto it = m_parent.m_songGroup.m_drumPages.find(m_setup.programNo);
|
auto it = m_parent.m_songGroup.m_drumPages.find(m_setup->programNo);
|
||||||
if (it != m_parent.m_songGroup.m_drumPages.cend())
|
if (it != m_parent.m_songGroup.m_drumPages.cend())
|
||||||
m_page = it->second;
|
m_page = it->second;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto it = m_parent.m_songGroup.m_normPages.find(m_setup.programNo);
|
auto it = m_parent.m_songGroup.m_normPages.find(m_setup->programNo);
|
||||||
if (it != m_parent.m_songGroup.m_normPages.cend())
|
if (it != m_parent.m_songGroup.m_normPages.cend())
|
||||||
m_page = it->second;
|
m_page = it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_curVol = m_setup.volume / 127.f;
|
m_curVol = m_setup->volume / 127.f;
|
||||||
m_curPan = m_setup.panning / 64.f - 1.f;
|
m_curPan = m_setup->panning / 64.f - 1.f;
|
||||||
|
m_ctrlVals[0x5b] = m_setup->reverb;
|
||||||
|
m_ctrlVals[0x5d] = m_setup->chorus;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (chanId == 9)
|
||||||
|
{
|
||||||
|
auto it = m_parent.m_songGroup.m_drumPages.find(0);
|
||||||
|
if (it != m_parent.m_songGroup.m_drumPages.cend())
|
||||||
|
m_page = it->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto it = m_parent.m_songGroup.m_normPages.find(0);
|
||||||
|
if (it != m_parent.m_songGroup.m_normPages.cend())
|
||||||
|
m_page = it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curVol = 1.f;
|
||||||
|
m_curPan = 0.f;
|
||||||
|
m_ctrlVals[0x5b] = 0;
|
||||||
|
m_ctrlVals[0x5d] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
m_ctrlVals[7] = 127;
|
m_ctrlVals[7] = 127;
|
||||||
m_ctrlVals[10] = 64;
|
m_ctrlVals[10] = 64;
|
||||||
m_ctrlVals[0x5b] = m_setup.reverb;
|
|
||||||
m_ctrlVals[0x5d] = m_setup.chorus;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::advance(double dt)
|
void Sequencer::advance(double dt)
|
||||||
|
|
|
@ -503,7 +503,7 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
|
||||||
{
|
{
|
||||||
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
|
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
|
||||||
remCount = std::min(samplesRem, m_lastSamplePos - m_curSamplePos);
|
remCount = std::min(samplesRem, m_lastSamplePos - m_curSamplePos);
|
||||||
memcpy(data, pcm + m_curSamplePos, remCount * sizeof(int16_t));
|
memmove(data, pcm + m_curSamplePos, remCount * sizeof(int16_t));
|
||||||
decSamples = remCount;
|
decSamples = remCount;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -568,7 +568,7 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
|
||||||
{
|
{
|
||||||
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
|
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
|
||||||
remCount = std::min(samplesRem, m_lastSamplePos - m_curSamplePos);
|
remCount = std::min(samplesRem, m_lastSamplePos - m_curSamplePos);
|
||||||
memcpy(data, pcm + m_curSamplePos, remCount * sizeof(int16_t));
|
memmove(data, pcm + m_curSamplePos, remCount * sizeof(int16_t));
|
||||||
decSamples = remCount;
|
decSamples = remCount;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue