NAM A2 Calibration
This commit is contained in:
+3
-1
@@ -33,7 +33,9 @@
|
|||||||
"logLevel": 3,
|
"logLevel": 3,
|
||||||
|
|
||||||
/* Maximum filesize to allow when uploading */
|
/* Maximum filesize to allow when uploading */
|
||||||
"maxUploadSize": 536870912 // 512MiB
|
"maxUploadSize": 536870912, // 512MiB
|
||||||
|
|
||||||
|
/* false-> Download A1 models; true -> Download A2 models */
|
||||||
|
"tone3000A2Models": true
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -101,6 +101,7 @@ JSON_MAP_REFERENCE(PiPedalConfiguration, threads)
|
|||||||
JSON_MAP_REFERENCE(PiPedalConfiguration, logLevel)
|
JSON_MAP_REFERENCE(PiPedalConfiguration, logLevel)
|
||||||
JSON_MAP_REFERENCE(PiPedalConfiguration, logHttpRequests)
|
JSON_MAP_REFERENCE(PiPedalConfiguration, logHttpRequests)
|
||||||
JSON_MAP_REFERENCE(PiPedalConfiguration, maxUploadSize)
|
JSON_MAP_REFERENCE(PiPedalConfiguration, maxUploadSize)
|
||||||
|
JSON_MAP_REFERENCE(PiPedalConfiguration, tone3000A2Models)
|
||||||
JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointGateway)
|
JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointGateway)
|
||||||
JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointServerAddress)
|
JSON_MAP_REFERENCE(PiPedalConfiguration, accessPointServerAddress)
|
||||||
JSON_MAP_REFERENCE(PiPedalConfiguration, isVst3Enabled)
|
JSON_MAP_REFERENCE(PiPedalConfiguration, isVst3Enabled)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ private:
|
|||||||
bool logHttpRequests_ = false;
|
bool logHttpRequests_ = false;
|
||||||
int logLevel_ = 0;
|
int logLevel_ = 0;
|
||||||
uint64_t maxUploadSize_ = 1024*1024;
|
uint64_t maxUploadSize_ = 1024*1024;
|
||||||
|
bool tone3000A2Models_ = true;
|
||||||
std::string accessPointGateway_;
|
std::string accessPointGateway_;
|
||||||
std::string accessPointServerAddress_;
|
std::string accessPointServerAddress_;
|
||||||
bool isVst3Enabled_ = true;
|
bool isVst3Enabled_ = true;
|
||||||
@@ -67,6 +68,7 @@ public:
|
|||||||
bool GetMLock() const { return mlock_; }
|
bool GetMLock() const { return mlock_; }
|
||||||
uint64_t GetMaxUploadSize() const { return maxUploadSize_; }
|
uint64_t GetMaxUploadSize() const { return maxUploadSize_; }
|
||||||
|
|
||||||
|
bool GetTone3000A2Models() const { return tone3000A2Models_; }
|
||||||
LogLevel GetLogLevel() const { return (LogLevel)this->logLevel_; }
|
LogLevel GetLogLevel() const { return (LogLevel)this->logLevel_; }
|
||||||
|
|
||||||
bool LogHttpRequests() const { return this->logHttpRequests_; }
|
bool LogHttpRequests() const { return this->logHttpRequests_; }
|
||||||
|
|||||||
@@ -364,6 +364,8 @@ namespace pipedal
|
|||||||
|
|
||||||
void Init(const PiPedalConfiguration &configuration);
|
void Init(const PiPedalConfiguration &configuration);
|
||||||
|
|
||||||
|
const PiPedalConfiguration &Configuration() const { return configuration; }
|
||||||
|
|
||||||
void LoadLv2PluginInfo();
|
void LoadLv2PluginInfo();
|
||||||
void Load();
|
void Load();
|
||||||
|
|
||||||
|
|||||||
@@ -1315,12 +1315,14 @@ static std::string StripPortNumber(const std::string &fromAddress)
|
|||||||
class InterceptConfig : public RequestHandler
|
class InterceptConfig : public RequestHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
PiPedalModel&model;
|
||||||
uint64_t maxUploadSize;
|
uint64_t maxUploadSize;
|
||||||
int portNumber;
|
int portNumber;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InterceptConfig(int portNumber, uint64_t maxUploadSize)
|
InterceptConfig(PiPedalModel&model,int portNumber, uint64_t maxUploadSize)
|
||||||
: RequestHandler("/var/config.json"),
|
: RequestHandler("/var/config.json"),
|
||||||
|
model(model),
|
||||||
maxUploadSize(maxUploadSize),
|
maxUploadSize(maxUploadSize),
|
||||||
portNumber(portNumber)
|
portNumber(portNumber)
|
||||||
{
|
{
|
||||||
@@ -1337,6 +1339,7 @@ public:
|
|||||||
<< "\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize
|
<< "\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize
|
||||||
<< ", \"enable_auto_update\": " << (ENABLE_AUTO_UPDATE ? " true" : "false")
|
<< ", \"enable_auto_update\": " << (ENABLE_AUTO_UPDATE ? " true" : "false")
|
||||||
<< ", \"has_wifi_device\": " << (HotspotManager::HasWifiDevice() ? " true" : "false")
|
<< ", \"has_wifi_device\": " << (HotspotManager::HasWifiDevice() ? " true" : "false")
|
||||||
|
<< ", \"tone3000_A2_models\": " << (model.Configuration().GetTone3000A2Models() ? " true" : "false")
|
||||||
<< " }";
|
<< " }";
|
||||||
|
|
||||||
return s.str();
|
return s.str();
|
||||||
@@ -1396,7 +1399,7 @@ void pipedal::ConfigureWebServer(
|
|||||||
int port,
|
int port,
|
||||||
size_t maxUploadSize)
|
size_t maxUploadSize)
|
||||||
{
|
{
|
||||||
std::shared_ptr<RequestHandler> interceptConfig{new InterceptConfig(port, maxUploadSize)};
|
std::shared_ptr<RequestHandler> interceptConfig{new InterceptConfig(model,port, maxUploadSize)};
|
||||||
server.AddRequestHandler(interceptConfig);
|
server.AddRequestHandler(interceptConfig);
|
||||||
|
|
||||||
std::shared_ptr<DownloadIntercept> downloadIntercept = std::make_shared<DownloadIntercept>(&model);
|
std::shared_ptr<DownloadIntercept> downloadIntercept = std::make_shared<DownloadIntercept>(&model);
|
||||||
|
|||||||
@@ -1,4 +1,17 @@
|
|||||||
Benchmark Results:
|
A2 Questions
|
||||||
|
|
||||||
|
Does A2 support Callibration?
|
||||||
|
input_level_dbu, output_level_dbu accessors on NeuralAmpModelerCore DSP
|
||||||
|
slimmable_weights accessors on NeuralAmpModelerCore DSP
|
||||||
|
standard values for slimmable_weights?
|
||||||
|
|
||||||
|
Implement NAM Model Weight selection UI
|
||||||
|
|
||||||
|
NAM INput VU is f*ed up.
|
||||||
|
|
||||||
|
File Player Underrun is NOT CPU use related. There's an underrun somewhere.
|
||||||
|
|
||||||
|
Update Pi 4 Benchmark Results:
|
||||||
|
|
||||||
The benchmark is to run TooB Neural Amp Modeler with an A1 model to generate 100s of audio. Lower times are better.
|
The benchmark is to run TooB Neural Amp Modeler with an A1 model to generate 100s of audio. Lower times are better.
|
||||||
|
|
||||||
|
|||||||
@@ -6,5 +6,7 @@
|
|||||||
"fakeAndroid": false,
|
"fakeAndroid": false,
|
||||||
"ui_plugins": [],
|
"ui_plugins": [],
|
||||||
"enable_auto_update": true,
|
"enable_auto_update": true,
|
||||||
"has_wifi_device": false
|
"has_wifi_device": false,
|
||||||
|
"tone3000_A2_models": true,
|
||||||
|
"end": true
|
||||||
}
|
}
|
||||||
@@ -949,7 +949,7 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
return scale_point.label;
|
return scale_point.label;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "#invalid";
|
return value.toString();
|
||||||
} else if (this.integer_property) {
|
} else if (this.integer_property) {
|
||||||
return value.toFixed(0);
|
return value.toFixed(0);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1316,6 +1316,7 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
maxFileUploadSize: number = 512 * 1024 * 1024;
|
maxFileUploadSize: number = 512 * 1024 * 1024;
|
||||||
maxPresetUploadSize: number = 1024 * 1024;
|
maxPresetUploadSize: number = 1024 * 1024;
|
||||||
debug: boolean = false;
|
debug: boolean = false;
|
||||||
|
tone3000_A2_models: boolean = true;
|
||||||
enableAutoUpdate: boolean = false;
|
enableAutoUpdate: boolean = false;
|
||||||
|
|
||||||
|
|
||||||
@@ -1326,6 +1327,7 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
let response: Response = await fetch(myRequest);
|
let response: Response = await fetch(myRequest);
|
||||||
let data = await response.json();
|
let data = await response.json();
|
||||||
|
|
||||||
|
this.tone3000_A2_models = data.tone3000_A2_models ?? true;
|
||||||
this.enableAutoUpdate = !!data.enable_auto_update;
|
this.enableAutoUpdate = !!data.enable_auto_update;
|
||||||
this.hasWifiDevice.set(!!data.has_wifi_device);
|
this.hasWifiDevice.set(!!data.has_wifi_device);
|
||||||
if (data.max_upload_size) {
|
if (data.max_upload_size) {
|
||||||
|
|||||||
@@ -154,6 +154,66 @@ export type PluginControlState = {
|
|||||||
previewValue?: string;
|
previewValue?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface CustomPluginControlProps extends WithStyles<typeof pluginControlStyles> {
|
||||||
|
title: string;
|
||||||
|
isSelect?: boolean;
|
||||||
|
isButton?: boolean;
|
||||||
|
item_width?: number;
|
||||||
|
mainControl: React.ReactNode;
|
||||||
|
editControl?: React.ReactNode;
|
||||||
|
};
|
||||||
|
export interface CustomPluginControlState {
|
||||||
|
|
||||||
|
};
|
||||||
|
const CustomPluginControl =
|
||||||
|
withStyles(
|
||||||
|
class extends Component<CustomPluginControlProps, CustomPluginControlState> {
|
||||||
|
constructor(props: CustomPluginControlProps) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
let classes = withStyles.getClasses(this.props);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classes.controlFrame}
|
||||||
|
style={{ width: this.props.item_width }}
|
||||||
|
>
|
||||||
|
{/* TITLE SECTION */}
|
||||||
|
<div className={classes.titleSection}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
alignSelf: "stretch", marginBottom: 8, marginLeft: this.props.isSelect ? 8 : 0, marginRight: 0
|
||||||
|
|
||||||
|
}}>
|
||||||
|
<Typography variant="caption" display="block" noWrap style={{
|
||||||
|
width: "100%",
|
||||||
|
textAlign: this.props.isSelect ? "left" : "center"
|
||||||
|
}}> {this.props.isButton ? "\u00A0" : this.props.title}</Typography>
|
||||||
|
</div>
|
||||||
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
|
<div className={classes.midSection}>
|
||||||
|
{this.props.mainControl}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* LABEL/EDIT SECTION*/}
|
||||||
|
<div className={classes.editSection} >
|
||||||
|
{this.props.editControl}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return (<div />);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
pluginControlStyles
|
||||||
|
);
|
||||||
|
|
||||||
|
export { CustomPluginControl };
|
||||||
|
|
||||||
|
|
||||||
const PluginControl =
|
const PluginControl =
|
||||||
withTheme(withStyles(
|
withTheme(withStyles(
|
||||||
class extends Component<PluginControlProps, PluginControlState> {
|
class extends Component<PluginControlProps, PluginControlState> {
|
||||||
@@ -490,7 +550,7 @@ const PluginControl =
|
|||||||
let tapTime = e.timeStamp;
|
let tapTime = e.timeStamp;
|
||||||
let dT = tapTime - this.lastTapMs;
|
let dT = tapTime - this.lastTapMs;
|
||||||
|
|
||||||
|
|
||||||
this.lastTapMs = tapTime;
|
this.lastTapMs = tapTime;
|
||||||
|
|
||||||
if (dT < 500) {
|
if (dT < 500) {
|
||||||
@@ -521,7 +581,7 @@ const PluginControl =
|
|||||||
let ms = e.timeStamp - this.tapStartMs;
|
let ms = e.timeStamp - this.tapStartMs;
|
||||||
if (ms < 200) {
|
if (ms < 200) {
|
||||||
this.onPointerTap(e);
|
this.onPointerTap(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// prevent click from firing on other elements
|
// prevent click from firing on other elements
|
||||||
// when the pointer goes up0.
|
// when the pointer goes up0.
|
||||||
@@ -619,7 +679,7 @@ const PluginControl =
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.setState({ previewValue: undefined});
|
this.setState({ previewValue: undefined });
|
||||||
}
|
}
|
||||||
previewInputValue(value: number, commitValue: boolean) {
|
previewInputValue(value: number, commitValue: boolean) {
|
||||||
let range = this.valueToRange(value);
|
let range = this.valueToRange(value);
|
||||||
@@ -688,7 +748,7 @@ const PluginControl =
|
|||||||
this.setState({ previewValue: undefined });
|
this.setState({ previewValue: undefined });
|
||||||
} else {
|
} else {
|
||||||
this.setState({ previewValue: v });
|
this.setState({ previewValue: v });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let selectElement = this.selectRef.current;
|
let selectElement = this.selectRef.current;
|
||||||
if (selectElement) {
|
if (selectElement) {
|
||||||
@@ -890,7 +950,7 @@ const PluginControl =
|
|||||||
|
|
||||||
private defaultStep(min: number, max: number): number {
|
private defaultStep(min: number, max: number): number {
|
||||||
let range = Math.abs(max - min);
|
let range = Math.abs(max - min);
|
||||||
if (range <= 1) return 0.01;
|
if (range <= 1) return 0.01;
|
||||||
if (range <= 10) return 0.1;
|
if (range <= 10) return 0.1;
|
||||||
if (range <= 100) return 1;
|
if (range <= 100) return 1;
|
||||||
if (range <= 1000) return 10;
|
if (range <= 1000) return 10;
|
||||||
@@ -1056,7 +1116,7 @@ const PluginControl =
|
|||||||
)
|
)
|
||||||
: (isGraphicEq) ? (
|
: (isGraphicEq) ? (
|
||||||
<div style={{ flex: "0 1 auto" }}>
|
<div style={{ flex: "0 1 auto" }}>
|
||||||
|
|
||||||
<ControlTooltip uiControl={control} valueTooltip={this.state.previewValue}>
|
<ControlTooltip uiControl={control} valueTooltip={this.state.previewValue}>
|
||||||
<GraphicEqCtl
|
<GraphicEqCtl
|
||||||
imgRef={this.imgRef}
|
imgRef={this.imgRef}
|
||||||
@@ -1076,7 +1136,7 @@ const PluginControl =
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ flex: "0 1 auto" }}>
|
<div style={{ flex: "0 1 auto" }}>
|
||||||
<ControlTooltip uiControl={control}
|
<ControlTooltip uiControl={control}
|
||||||
valueTooltip={this.state.previewValue}>
|
valueTooltip={this.state.previewValue}>
|
||||||
<DialIcon ref={this.imgRef}
|
<DialIcon ref={this.imgRef}
|
||||||
style={{
|
style={{
|
||||||
@@ -1110,7 +1170,7 @@ const PluginControl =
|
|||||||
error={this.state.error}
|
error={this.state.error}
|
||||||
inputProps={{
|
inputProps={{
|
||||||
className: "scrollMod",
|
className: "scrollMod",
|
||||||
type: isMobileDevice()? "text": "number",
|
type: isMobileDevice() ? "text" : "number",
|
||||||
inputMode: "numeric",
|
inputMode: "numeric",
|
||||||
|
|
||||||
min: this.props.uiControl?.min_value,
|
min: this.props.uiControl?.min_value,
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ import { UiPlugin, UiControl, UiFileProperty, UiFrequencyPlot, ScalePoint } from
|
|||||||
import {
|
import {
|
||||||
Pedalboard, PedalboardItem, ControlValue
|
Pedalboard, PedalboardItem, ControlValue
|
||||||
} from './Pedalboard';
|
} from './Pedalboard';
|
||||||
import PluginControl from './PluginControl';
|
import PluginControl, {CustomPluginControl} from './PluginControl';
|
||||||
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||||
import SideChainSelectControl, {SideChainSelectDialog} from './SideChainSelectControl';
|
import SideChainSelectControl, { SideChainSelectDialog } from './SideChainSelectControl';
|
||||||
import VuMeter from './VuMeter';
|
import VuMeter from './VuMeter';
|
||||||
import { nullCast } from './Utility'
|
import { nullCast } from './Utility'
|
||||||
import { PiPedalStateError } from './PiPedalError';
|
import { PiPedalStateError } from './PiPedalError';
|
||||||
@@ -66,6 +66,7 @@ const LANDSCAPE_HEIGHT_BREAK = 500;
|
|||||||
|
|
||||||
export interface ICustomizationHost {
|
export interface ICustomizationHost {
|
||||||
makeStandardControl(uiControl: UiControl, controlValues: ControlValue[]): ReactNode;
|
makeStandardControl(uiControl: UiControl, controlValues: ControlValue[]): ReactNode;
|
||||||
|
makeCustomControl(title: string, mainControl: ReactNode, editControl?: ReactNode): ReactNode;
|
||||||
renderControlGroup(controlGroup: ControlGroup, key: string): ReactNode;
|
renderControlGroup(controlGroup: ControlGroup, key: string): ReactNode;
|
||||||
isLandscapeGrid(): boolean;
|
isLandscapeGrid(): boolean;
|
||||||
}
|
}
|
||||||
@@ -379,6 +380,7 @@ type PluginControlViewState = {
|
|||||||
sidechainDialogOpen: boolean
|
sidechainDialogOpen: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const PluginControlView =
|
const PluginControlView =
|
||||||
withTheme(withStyles(
|
withTheme(withStyles(
|
||||||
class extends ResizeResponsiveComponent<PluginControlViewProps, PluginControlViewState> {
|
class extends ResizeResponsiveComponent<PluginControlViewProps, PluginControlViewState> {
|
||||||
@@ -495,6 +497,7 @@ const PluginControlView =
|
|||||||
}
|
}
|
||||||
private ixKey: number = 1;
|
private ixKey: number = 1;
|
||||||
|
|
||||||
|
|
||||||
makeStandardControl(uiControl: UiControl, controlValues: ControlValue[]): ReactNode {
|
makeStandardControl(uiControl: UiControl, controlValues: ControlValue[]): ReactNode {
|
||||||
let symbol = uiControl.symbol;
|
let symbol = uiControl.symbol;
|
||||||
if (!uiControl.is_input) {
|
if (!uiControl.is_input) {
|
||||||
@@ -882,7 +885,7 @@ const PluginControlView =
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleSelectSidechainInput() {
|
handleSelectSidechainInput() {
|
||||||
this.setState({sidechainDialogOpen: true});
|
this.setState({ sidechainDialogOpen: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
handleModGuiFileProperty(instanceId: number, filePropertyUri: string, selectedFile: string) {
|
handleModGuiFileProperty(instanceId: number, filePropertyUri: string, selectedFile: string) {
|
||||||
@@ -963,7 +966,9 @@ const PluginControlView =
|
|||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
makeCustomControl(title: string, mainControl: ReactNode, editControl?: ReactNode): ReactNode {
|
||||||
|
return (<CustomPluginControl title={title} mainControl={mainControl} editControl={editControl} />);
|
||||||
|
}
|
||||||
renderPiPedalControl(pedalboardItem?: PedalboardItem): ReactNode {
|
renderPiPedalControl(pedalboardItem?: PedalboardItem): ReactNode {
|
||||||
this.controlKeyIndex = 0;
|
this.controlKeyIndex = 0;
|
||||||
|
|
||||||
@@ -1115,12 +1120,12 @@ const PluginControlView =
|
|||||||
)}
|
)}
|
||||||
{this.state.sidechainDialogOpen && (
|
{this.state.sidechainDialogOpen && (
|
||||||
<SideChainSelectDialog open={this.state.sidechainDialogOpen}
|
<SideChainSelectDialog open={this.state.sidechainDialogOpen}
|
||||||
onClose={()=>{ this.setState({sidechainDialogOpen: false});}}
|
onClose={() => { this.setState({ sidechainDialogOpen: false }); }}
|
||||||
selectItems={this.getSidechainSelectItems()}
|
selectItems={this.getSidechainSelectItems()}
|
||||||
selectedInstanceId={this.props.item.sideChainInputId}
|
selectedInstanceId={this.props.item.sideChainInputId}
|
||||||
onChanged={(instanceId: number) => {
|
onChanged={(instanceId: number) => {
|
||||||
this.model.setPedalboardSideChainInput(this.props.item.instanceId, instanceId);
|
this.model.setPedalboardSideChainInput(this.props.item.instanceId, instanceId);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{/* xxx: I don't think we need this anyore. */}
|
{/* xxx: I don't think we need this anyore. */}
|
||||||
@@ -1142,3 +1147,5 @@ const PluginControlView =
|
|||||||
|
|
||||||
export default PluginControlView;
|
export default PluginControlView;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ const THROTTLING_TRIGGGER_LEVEL = Math.floor(ALLOWED_DOWNLOADS_PER_MINUTE/2);
|
|||||||
|
|
||||||
class DownloadThrottler {
|
class DownloadThrottler {
|
||||||
|
|
||||||
private throttleActive: boolean = false;
|
|
||||||
private fifo: number[] = [];
|
private fifo: number[] = [];
|
||||||
private downloadCount: number = 0;
|
private downloadCount: number = 0;
|
||||||
|
|
||||||
@@ -39,11 +38,7 @@ class DownloadThrottler {
|
|||||||
this.fifo.shift();
|
this.fifo.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.fifo.length > THROTTLING_TRIGGGER_LEVEL) {
|
this.downloadCount = this.fifo.length;
|
||||||
this.throttleActive = true;
|
|
||||||
} else {
|
|
||||||
this.throttleActive = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
getThrottleDelay(now : number = Date.now()): number {
|
getThrottleDelay(now : number = Date.now()): number {
|
||||||
while (this.fifo.length > 0 && this.fifo[0] + 60000 <= now) {
|
while (this.fifo.length > 0 && this.fifo[0] + 60000 <= now) {
|
||||||
@@ -264,7 +259,7 @@ export class Tone3000DownloadHandler {
|
|||||||
let models: Model[] = [];
|
let models: Model[] = [];
|
||||||
let architectureFilter: number | undefined = undefined;
|
let architectureFilter: number | undefined = undefined;
|
||||||
// Take A2 models only for NAM downloads, and only if the tone actually has A2 models.
|
// Take A2 models only for NAM downloads, and only if the tone actually has A2 models.
|
||||||
if (downloadType === Tone3000DownloadType.Nam && !!tone.a2_models_count) {
|
if (downloadType === Tone3000DownloadType.Nam && !!tone.a2_models_count && this.model.tone3000_A2_models) {
|
||||||
architectureFilter = 2; // NAM models only
|
architectureFilter = 2; // NAM models only
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,14 +27,20 @@ import { withStyles } from "tss-react/mui";
|
|||||||
|
|
||||||
import IControlViewFactory from './IControlViewFactory';
|
import IControlViewFactory from './IControlViewFactory';
|
||||||
import { PiPedalModelFactory, PiPedalModel, ListenHandle, State } from "./PiPedalModel";
|
import { PiPedalModelFactory, PiPedalModel, ListenHandle, State } from "./PiPedalModel";
|
||||||
import { PedalboardItem,ControlValue } from './Pedalboard';
|
import { PedalboardItem, ControlValue } from './Pedalboard';
|
||||||
import PluginControlView, { ICustomizationHost, ControlGroup, ControlViewCustomization } from './PluginControlView';
|
import PluginControlView, { ICustomizationHost, ControlGroup, ControlViewCustomization } from './PluginControlView';
|
||||||
import { UiPlugin,UiControl, ControlType } from './Lv2Plugin';
|
import { UiPlugin, UiControl, ControlType } from './Lv2Plugin';
|
||||||
|
import Select from '@mui/material/Select/Select';
|
||||||
|
import MenuItem from '@mui/material/MenuItem/MenuItem';
|
||||||
|
import { CustomPluginControl } from './PluginControl';
|
||||||
|
|
||||||
|
|
||||||
const TOOB_NAM__MODEL_METADATA = "http://two-play.com/plugins/toob-nam#model_metadata";
|
const TOOB_NAM__MODEL_METADATA_URI = "http://two-play.com/plugins/toob-nam#model_metadata";
|
||||||
|
const TOOB_NAM__MODEL_WEIGHT_URI = "http://two-play.com/plugins/toob-nam#modelWeight";
|
||||||
|
|
||||||
// offset 0: an integer with the folloing bits set.
|
// offset 0: an integer with the folloing bits set.
|
||||||
|
// Must match ToobAmp/src/NeuralAmpModeler_Lv2Extensions.hpp enum TOOB_NAM_METADATA_OFFSETS
|
||||||
|
const MAX_SLIMMABLE_WEIGHTS = 16;
|
||||||
class TOOB_NAM_METADATA_OFFSETS {
|
class TOOB_NAM_METADATA_OFFSETS {
|
||||||
static readonly flags = 0;
|
static readonly flags = 0;
|
||||||
static readonly preset_version = 1;
|
static readonly preset_version = 1;
|
||||||
@@ -42,7 +48,11 @@ class TOOB_NAM_METADATA_OFFSETS {
|
|||||||
static readonly gain = 3;
|
static readonly gain = 3;
|
||||||
static readonly input_level_dbu = 4;
|
static readonly input_level_dbu = 4;
|
||||||
static readonly output_level_dbu = 5;
|
static readonly output_level_dbu = 5;
|
||||||
static readonly max_medatadata = 6;
|
static readonly is_a2 = 6;
|
||||||
|
static readonly model_weight = 7;
|
||||||
|
static readonly slimmable_weights_size = 8;
|
||||||
|
static readonly slimmable_weights = 9;
|
||||||
|
static readonly max_medatadata = TOOB_NAM_METADATA_OFFSETS.slimmable_weights + MAX_SLIMMABLE_WEIGHTS;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -55,10 +65,9 @@ class TOOB_NAM_METADATA_FLAGS {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class ModelMetadata {
|
class ModelMetadata {
|
||||||
constructor(metadataValues?: number[])
|
constructor(metadataValues?: number[]) {
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
if (metadataValues) {
|
if (metadataValues) {
|
||||||
let flags = metadataValues[TOOB_NAM_METADATA_OFFSETS.flags];
|
let flags = metadataValues[TOOB_NAM_METADATA_OFFSETS.flags];
|
||||||
this.hasModel = (flags & TOOB_NAM_METADATA_FLAGS.has_model) !== 0;
|
this.hasModel = (flags & TOOB_NAM_METADATA_FLAGS.has_model) !== 0;
|
||||||
@@ -72,6 +81,12 @@ class ModelMetadata {
|
|||||||
this.inputlevelDBU = metadataValues[TOOB_NAM_METADATA_OFFSETS.input_level_dbu];
|
this.inputlevelDBU = metadataValues[TOOB_NAM_METADATA_OFFSETS.input_level_dbu];
|
||||||
this.outputlevelDBU = metadataValues[TOOB_NAM_METADATA_OFFSETS.output_level_dbu];
|
this.outputlevelDBU = metadataValues[TOOB_NAM_METADATA_OFFSETS.output_level_dbu];
|
||||||
this.preset_version = metadataValues[TOOB_NAM_METADATA_OFFSETS.preset_version];
|
this.preset_version = metadataValues[TOOB_NAM_METADATA_OFFSETS.preset_version];
|
||||||
|
this.isA2 = metadataValues[TOOB_NAM_METADATA_OFFSETS.is_a2] !== 0;
|
||||||
|
this.modelWeight = metadataValues[TOOB_NAM_METADATA_OFFSETS.model_weight];
|
||||||
|
let slimmableWeightsSize = metadataValues[TOOB_NAM_METADATA_OFFSETS.slimmable_weights_size];
|
||||||
|
for (let i = 0; i < slimmableWeightsSize && i < 16; ++i) {
|
||||||
|
this.slimmable_weights.push(metadataValues[TOOB_NAM_METADATA_OFFSETS.slimmable_weights + i]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.hasModel = false;
|
this.hasModel = false;
|
||||||
this.hasLoudness = false;
|
this.hasLoudness = false;
|
||||||
@@ -84,11 +99,16 @@ class ModelMetadata {
|
|||||||
this.inputlevelDBU = 0;
|
this.inputlevelDBU = 0;
|
||||||
this.outputlevelDBU = 0;
|
this.outputlevelDBU = 0;
|
||||||
this.preset_version = 1;
|
this.preset_version = 1;
|
||||||
|
this.modelWeight = -1;
|
||||||
|
this.isA2 = false;
|
||||||
|
this.slimmable_weights = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preset_version: number;
|
preset_version: number;
|
||||||
|
isA2: boolean = false;
|
||||||
|
modelWeight: number = 1.0;
|
||||||
|
slimmable_weights: number[] = [];
|
||||||
hasModel: boolean;
|
hasModel: boolean;
|
||||||
hasLoudness: boolean;
|
hasLoudness: boolean;
|
||||||
hasGain: boolean;
|
hasGain: boolean;
|
||||||
@@ -100,6 +120,10 @@ class ModelMetadata {
|
|||||||
inputlevelDBU: number;
|
inputlevelDBU: number;
|
||||||
outputlevelDBU: number;
|
outputlevelDBU: number;
|
||||||
|
|
||||||
|
hasSlimmableWeights(): boolean {
|
||||||
|
return this.slimmable_weights.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -114,8 +138,10 @@ interface ToobNamViewProps extends WithStyles<typeof styles> {
|
|||||||
interface ToobNamViewState {
|
interface ToobNamViewState {
|
||||||
showEqSection: boolean;
|
showEqSection: boolean;
|
||||||
enableCalibration: boolean;
|
enableCalibration: boolean;
|
||||||
|
showCalibration: boolean;
|
||||||
enableOutputNormalization: boolean;
|
enableOutputNormalization: boolean;
|
||||||
modelMetadata: ModelMetadata;
|
modelMetadata: ModelMetadata;
|
||||||
|
modelWeight: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ToobNamView =
|
const ToobNamView =
|
||||||
@@ -133,18 +159,18 @@ const ToobNamView =
|
|||||||
this.model = PiPedalModelFactory.getInstance();
|
this.model = PiPedalModelFactory.getInstance();
|
||||||
this.state = {
|
this.state = {
|
||||||
showEqSection: false,
|
showEqSection: false,
|
||||||
|
showCalibration: false,
|
||||||
enableCalibration: false,
|
enableCalibration: false,
|
||||||
enableOutputNormalization: false,
|
enableOutputNormalization: false,
|
||||||
modelMetadata: new ModelMetadata()
|
modelMetadata: new ModelMetadata(),
|
||||||
|
modelWeight: -1
|
||||||
}
|
}
|
||||||
let pluginInfo: UiPlugin | null = this.model.getUiPlugin(this.props.item.uri);
|
let pluginInfo: UiPlugin | null = this.model.getUiPlugin(this.props.item.uri);
|
||||||
if (pluginInfo === null)
|
if (pluginInfo === null) {
|
||||||
{
|
|
||||||
throw new Error("Plugin not fouund.");
|
throw new Error("Plugin not fouund.");
|
||||||
}
|
}
|
||||||
let inputCalibrationControl = pluginInfo.getControl("inputCalibrationMode");
|
let inputCalibrationControl = pluginInfo.getControl("inputCalibrationMode");
|
||||||
if (!inputCalibrationControl)
|
if (!inputCalibrationControl) {
|
||||||
{
|
|
||||||
throw new Error("Control not found.");
|
throw new Error("Control not found.");
|
||||||
}
|
}
|
||||||
let patchedInputControl = new UiControl().deserialize(inputCalibrationControl);
|
let patchedInputControl = new UiControl().deserialize(inputCalibrationControl);
|
||||||
@@ -152,14 +178,13 @@ const ToobNamView =
|
|||||||
this.patchedInputControl = patchedInputControl
|
this.patchedInputControl = patchedInputControl
|
||||||
|
|
||||||
let outputCalibrationControl = pluginInfo.getControl("outputCalibration");
|
let outputCalibrationControl = pluginInfo.getControl("outputCalibration");
|
||||||
if (!outputCalibrationControl)
|
if (!outputCalibrationControl) {
|
||||||
{
|
|
||||||
throw new Error("Control not found.");
|
throw new Error("Control not found.");
|
||||||
}
|
}
|
||||||
let patchedOutputControl = new UiControl().deserialize(outputCalibrationControl);
|
let patchedOutputControl = new UiControl().deserialize(outputCalibrationControl);
|
||||||
patchedOutputControl.controlType = ControlType.Select;
|
patchedOutputControl.controlType = ControlType.Select;
|
||||||
this.noCalibrationOutputControl = patchedOutputControl
|
this.noCalibrationOutputControl = patchedOutputControl
|
||||||
this.noCalibrationOutputControl.scale_points.splice(1,1);
|
this.noCalibrationOutputControl.scale_points.splice(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private patchedInputControl: UiControl;
|
private patchedInputControl: UiControl;
|
||||||
@@ -171,7 +196,7 @@ const ToobNamView =
|
|||||||
disableControl(control: React.ReactNode, key: string) {
|
disableControl(control: React.ReactNode, key: string) {
|
||||||
return (
|
return (
|
||||||
<div style={{ opacity: 0.3, pointerEvents: "none" }}
|
<div style={{ opacity: 0.3, pointerEvents: "none" }}
|
||||||
key={key}
|
key={key}
|
||||||
|
|
||||||
onPointerDownCapture={(e) => {
|
onPointerDownCapture={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -189,42 +214,94 @@ const ToobNamView =
|
|||||||
|
|
||||||
modifyControls(host: ICustomizationHost, controls: (React.ReactNode | ControlGroup)[]): (React.ReactNode | ControlGroup)[] {
|
modifyControls(host: ICustomizationHost, controls: (React.ReactNode | ControlGroup)[]): (React.ReactNode | ControlGroup)[] {
|
||||||
let EqPos = 7;
|
let EqPos = 7;
|
||||||
let CalibrationGroupPos = 8;
|
const CalibrationGroupPos = 8;
|
||||||
|
const ModelSizeControlPos = 9;
|
||||||
|
const ModelWeightControlPos = 10;
|
||||||
|
|
||||||
|
|
||||||
let calibrationGroup = controls[CalibrationGroupPos] as ControlGroup;
|
let calibrationGroup = controls[CalibrationGroupPos] as ControlGroup;
|
||||||
|
|
||||||
calibrationGroup.controls[0] = host.makeStandardControl(this.patchedInputControl,this.props.item.controlValues);
|
|
||||||
|
|
||||||
if (this.state.enableCalibration)
|
if (this.state.showCalibration) {
|
||||||
{
|
calibrationGroup.controls[0] = host.makeStandardControl(this.patchedInputControl, this.props.item.controlValues);
|
||||||
calibrationGroup.controls[0] = host.makeStandardControl(this.patchedInputControl,this.props.item.controlValues);
|
|
||||||
|
|
||||||
} else {
|
if (this.state.enableCalibration) {
|
||||||
calibrationGroup.controls[0] = host.makeStandardControl(this.patchedInputControl,
|
calibrationGroup.controls[0] = host.makeStandardControl(this.patchedInputControl, this.props.item.controlValues);
|
||||||
[ new ControlValue("inputCalibrationMode",0.0)]
|
|
||||||
);
|
|
||||||
calibrationGroup.controls[0] = this.disableControl(calibrationGroup.controls[0], "cg_01d");
|
|
||||||
calibrationGroup.controls[1] = this.disableControl(calibrationGroup.controls[1], "cg_02d");
|
|
||||||
|
|
||||||
if (this.state.enableOutputNormalization)
|
|
||||||
{
|
|
||||||
calibrationGroup.controls[2] = host.makeStandardControl(this.noCalibrationOutputControl, this.props.item.controlValues);
|
|
||||||
} else {
|
} else {
|
||||||
let tControl: UiControl = this.noCalibrationOutputControl.clone();
|
calibrationGroup.controls[0] = host.makeStandardControl(this.patchedInputControl,
|
||||||
tControl.symbol = "_disabled_output";
|
[new ControlValue("inputCalibrationMode", 0.0)]
|
||||||
calibrationGroup.controls[2] = host.makeStandardControl(
|
);
|
||||||
tControl,
|
calibrationGroup.controls[0] = this.disableControl(calibrationGroup.controls[0], "cg_01d");
|
||||||
[ new ControlValue("_disabled_output",2.0)]);
|
calibrationGroup.controls[1] = this.disableControl(calibrationGroup.controls[1], "cg_02d");
|
||||||
calibrationGroup.controls[2] = this.disableControl(calibrationGroup.controls[2], "cg_03d");
|
|
||||||
|
|
||||||
|
if (this.state.enableOutputNormalization) {
|
||||||
|
calibrationGroup.controls[2] = host.makeStandardControl(this.noCalibrationOutputControl, this.props.item.controlValues);
|
||||||
|
} else {
|
||||||
|
let tControl: UiControl = this.noCalibrationOutputControl.clone();
|
||||||
|
tControl.symbol = "_disabled_output";
|
||||||
|
calibrationGroup.controls[2] = host.makeStandardControl(
|
||||||
|
tControl,
|
||||||
|
[new ControlValue("_disabled_output", 2.0)]);
|
||||||
|
calibrationGroup.controls[2] = this.disableControl(calibrationGroup.controls[2], "cg_03d");
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
controls[CalibrationGroupPos] = null;
|
||||||
}
|
}
|
||||||
|
controls[ModelSizeControlPos] = null;
|
||||||
|
controls[ModelWeightControlPos] = null;
|
||||||
if (!this.state.showEqSection) {
|
if (!this.state.showEqSection) {
|
||||||
controls.splice(EqPos, 1);
|
controls.splice(EqPos, 1);
|
||||||
}
|
}
|
||||||
|
if (this.state.modelMetadata.hasSlimmableWeights()) {
|
||||||
|
controls.splice(3, 0, this.MakeModelWeightSelector(host));
|
||||||
|
}
|
||||||
return controls;
|
return controls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModelWeightToString(weight: number): string {
|
||||||
|
switch (weight) {
|
||||||
|
case 1.0: return "Standard";
|
||||||
|
case 0.5: return "Lite";
|
||||||
|
case 0.25: return "Feather";
|
||||||
|
default: return weight.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectModelWeight(weight: number) {
|
||||||
|
this.setState({ modelWeight: weight });
|
||||||
|
this.model.setPatchProperty(this.props.instanceId, TOOB_NAM__MODEL_WEIGHT_URI, weight);
|
||||||
|
|
||||||
|
}
|
||||||
|
MakeModelWeightSelector(host: ICustomizationHost): React.ReactNode {
|
||||||
|
if ((this.state.modelMetadata.modelWeight === undefined || this.state.modelMetadata.modelWeight || this.state.modelMetadata.hasSlimmableWeights()) === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let selectControl = (
|
||||||
|
<Select key="model_weight_control" variant="standard" size="small" value={this.state.modelMetadata.modelWeight}
|
||||||
|
onChange={(e) => { this.SelectModelWeight(Number(e.target.value)) }}
|
||||||
|
style={{ marginLeft: 4, marginRight: 4, width: 140, fontSize: 12, marginTop: 4 }}
|
||||||
|
>
|
||||||
|
{this.state.modelMetadata.slimmable_weights.map((weight, index) => {
|
||||||
|
return (
|
||||||
|
<MenuItem key={weight.toString()} value={weight}
|
||||||
|
style={{ fontSize: 14 }}
|
||||||
|
>
|
||||||
|
{this.ModelWeightToString(weight)}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div style={{ marginLeft: 12 }}>
|
||||||
|
<CustomPluginControl title="Model Weight" mainControl={selectControl} isSelect={true} />
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
||||||
private handleConnectionStateChanged(state: State) {
|
private handleConnectionStateChanged(state: State) {
|
||||||
if (state === State.Ready) {
|
if (state === State.Ready) {
|
||||||
this.unsubscribeFromMetadata();
|
this.unsubscribeFromMetadata();
|
||||||
@@ -235,11 +312,16 @@ const ToobNamView =
|
|||||||
handleModelMetadata(atomData: any) {
|
handleModelMetadata(atomData: any) {
|
||||||
if (atomData && atomData.otype_ === "Vector" && atomData.value) {
|
if (atomData && atomData.otype_ === "Vector" && atomData.value) {
|
||||||
let metadata = new ModelMetadata(atomData.value as number[]);
|
let metadata = new ModelMetadata(atomData.value as number[]);
|
||||||
this.setState({
|
metadata.hasInputLevelDBU || metadata.hasOutputLevelDBU
|
||||||
|
this.setState({
|
||||||
modelMetadata: metadata,
|
modelMetadata: metadata,
|
||||||
showEqSection: metadata.preset_version === 0,
|
showEqSection: metadata.preset_version === 0,
|
||||||
|
showCalibration: (
|
||||||
|
metadata.hasInputLevelDBU || metadata.hasOutputLevelDBU ||
|
||||||
|
(metadata.hasLoudness && metadata.hasGain)) && metadata.hasModel,
|
||||||
enableCalibration: metadata.hasInputLevelDBU && metadata.hasModel,
|
enableCalibration: metadata.hasInputLevelDBU && metadata.hasModel,
|
||||||
enableOutputNormalization: metadata.hasLoudness && metadata.hasModel
|
enableOutputNormalization: metadata.hasLoudness && metadata.hasModel,
|
||||||
|
modelWeight: metadata.modelWeight
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,13 +330,13 @@ const ToobNamView =
|
|||||||
this.subscribedId = this.props.instanceId;
|
this.subscribedId = this.props.instanceId;
|
||||||
this.listenHandle = this.model.monitorPatchProperty(
|
this.listenHandle = this.model.monitorPatchProperty(
|
||||||
this.props.instanceId,
|
this.props.instanceId,
|
||||||
TOOB_NAM__MODEL_METADATA,
|
TOOB_NAM__MODEL_METADATA_URI,
|
||||||
(instanceId, propertyUri, atomData) => {
|
(instanceId, propertyUri, atomData) => {
|
||||||
this.handleModelMetadata(atomData);
|
this.handleModelMetadata(atomData);
|
||||||
});
|
});
|
||||||
this.model.getPatchProperty(
|
this.model.getPatchProperty(
|
||||||
this.props.instanceId,
|
this.props.instanceId,
|
||||||
TOOB_NAM__MODEL_METADATA
|
TOOB_NAM__MODEL_METADATA_URI
|
||||||
).then((atomData) => {
|
).then((atomData) => {
|
||||||
this.handleModelMetadata(atomData);
|
this.handleModelMetadata(atomData);
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user