RAM2118 commited on
Commit
6f415b4
·
verified ·
1 Parent(s): 33f4cd8

Fix crash: Editor is thin — no threads, no scan ownership, just reads Processor state

Browse files
Files changed (1) hide show
  1. Source/PluginBridgeEditor.cpp +30 -63
Source/PluginBridgeEditor.cpp CHANGED
@@ -5,48 +5,35 @@ PluginBridgeEditor::PluginBridgeEditor(PluginBridgeProcessor& p)
5
  {
6
  setSize(360, 220);
7
 
8
- // Register formats for scanning
9
- #if JUCE_PLUGINHOST_VST3
10
- scanFormatManager.addFormat(new juce::VST3PluginFormat());
11
- #endif
12
- #if JUCE_PLUGINHOST_AU
13
- scanFormatManager.addFormat(new juce::AudioUnitPluginFormat());
14
- #endif
15
-
16
- // Title
17
  titleLabel.setText("PluginBridge", juce::dontSendNotification);
18
  titleLabel.setFont(juce::FontOptions(22.0f));
19
  titleLabel.setJustificationType(juce::Justification::centred);
20
  titleLabel.setColour(juce::Label::textColourId, juce::Colours::white);
21
  addAndMakeVisible(titleLabel);
22
 
23
- // MCP status
24
  statusLabel.setText("MCP: starting...", juce::dontSendNotification);
25
  statusLabel.setFont(juce::FontOptions(12.0f));
26
  statusLabel.setJustificationType(juce::Justification::centred);
27
  addAndMakeVisible(statusLabel);
28
 
29
- // Port
30
  portLabel.setText("", juce::dontSendNotification);
31
  portLabel.setFont(juce::FontOptions(10.0f));
32
  portLabel.setJustificationType(juce::Justification::centred);
33
  portLabel.setColour(juce::Label::textColourId, juce::Colour(0xff888888));
34
  addAndMakeVisible(portLabel);
35
 
36
- // Plugin name display
37
  pluginLabel.setText("No plugin loaded", juce::dontSendNotification);
38
  pluginLabel.setFont(juce::FontOptions(13.0f));
39
  pluginLabel.setJustificationType(juce::Justification::centred);
40
  pluginLabel.setColour(juce::Label::textColourId, juce::Colour(0xffaaaaaa));
41
  addAndMakeVisible(pluginLabel);
42
 
43
- // Plugin selector button
44
- pluginButton.onClick = [this]() { scanAndShowMenu(); };
45
  pluginButton.setColour(juce::TextButton::buttonColourId, juce::Colour(0xff2d2d44));
46
  pluginButton.setColour(juce::TextButton::textColourOffId, juce::Colours::white);
47
  addAndMakeVisible(pluginButton);
48
 
49
- startTimerHz(2);
50
  }
51
 
52
  PluginBridgeEditor::~PluginBridgeEditor()
@@ -76,6 +63,7 @@ void PluginBridgeEditor::resized()
76
 
77
  void PluginBridgeEditor::timerCallback()
78
  {
 
79
  if (processorRef.isMcpServerRunning())
80
  {
81
  statusLabel.setText("MCP: running", juce::dontSendNotification);
@@ -90,6 +78,7 @@ void PluginBridgeEditor::timerCallback()
90
  portLabel.setText("", juce::dontSendNotification);
91
  }
92
 
 
93
  auto& mgr = processorRef.getHostedPluginManager();
94
  if (mgr.isLoaded())
95
  {
@@ -102,74 +91,52 @@ void PluginBridgeEditor::timerCallback()
102
  {
103
  pluginLabel.setText("No plugin loaded", juce::dontSendNotification);
104
  pluginLabel.setColour(juce::Label::textColourId, juce::Colour(0xff888888));
105
- pluginButton.setButtonText("Select Plugin...");
 
 
 
 
 
 
 
 
 
 
 
 
106
  }
107
  }
108
 
109
- void PluginBridgeEditor::scanAndShowMenu()
110
  {
111
- // If already scanned, just show menu immediately
112
- if (scanComplete)
113
  {
 
114
  showPluginMenu();
115
- return;
116
  }
117
-
118
- // If currently scanning, ignore click
119
- if (scanning)
120
- return;
121
-
122
- // Scan in background thread
123
- scanning = true;
124
- pluginButton.setButtonText("Scanning...");
125
- pluginButton.setEnabled(false);
126
-
127
- auto* thisPtr = this;
128
- std::thread([thisPtr]()
129
  {
130
- for (int i = 0; i < thisPtr->scanFormatManager.getNumFormats(); ++i)
131
- {
132
- auto* format = thisPtr->scanFormatManager.getFormat(i);
133
- auto searchPaths = format->getDefaultLocationsToSearch();
134
-
135
- juce::PluginDirectoryScanner scanner(
136
- thisPtr->knownPlugins,
137
- *format,
138
- searchPaths,
139
- true,
140
- juce::File()
141
- );
142
-
143
- juce::String pluginName;
144
- while (scanner.scanNextFile(false, pluginName)) {}
145
- }
146
-
147
- // Back to message thread to show menu
148
- juce::MessageManager::callAsync([thisPtr]()
149
- {
150
- thisPtr->scanning = false;
151
- thisPtr->scanComplete = true;
152
- thisPtr->pluginButton.setEnabled(true);
153
- thisPtr->pluginButton.setButtonText("Select Plugin...");
154
- thisPtr->showPluginMenu();
155
- });
156
- }).detach();
157
  }
158
 
159
  void PluginBridgeEditor::showPluginMenu()
160
  {
161
- juce::PopupMenu menu;
162
- auto types = knownPlugins.getTypes();
163
 
164
  if (types.isEmpty())
165
  {
 
166
  menu.addItem(-1, "(No plugins found)", false);
167
  menu.showMenuAsync(juce::PopupMenu::Options().withTargetComponent(&pluginButton),
168
  [](int) {});
169
  return;
170
  }
171
 
172
- // Group by manufacturer as submenus
 
173
  juce::StringArray manufacturers;
174
  for (const auto& desc : types)
175
  {
@@ -199,7 +166,7 @@ void PluginBridgeEditor::showPluginMenu()
199
 
200
  void PluginBridgeEditor::loadPluginByIndex(int index)
201
  {
202
- auto types = knownPlugins.getTypes();
203
  if (index >= 0 && index < types.size())
204
  {
205
  const auto& desc = types[index];
 
5
  {
6
  setSize(360, 220);
7
 
 
 
 
 
 
 
 
 
 
8
  titleLabel.setText("PluginBridge", juce::dontSendNotification);
9
  titleLabel.setFont(juce::FontOptions(22.0f));
10
  titleLabel.setJustificationType(juce::Justification::centred);
11
  titleLabel.setColour(juce::Label::textColourId, juce::Colours::white);
12
  addAndMakeVisible(titleLabel);
13
 
 
14
  statusLabel.setText("MCP: starting...", juce::dontSendNotification);
15
  statusLabel.setFont(juce::FontOptions(12.0f));
16
  statusLabel.setJustificationType(juce::Justification::centred);
17
  addAndMakeVisible(statusLabel);
18
 
 
19
  portLabel.setText("", juce::dontSendNotification);
20
  portLabel.setFont(juce::FontOptions(10.0f));
21
  portLabel.setJustificationType(juce::Justification::centred);
22
  portLabel.setColour(juce::Label::textColourId, juce::Colour(0xff888888));
23
  addAndMakeVisible(portLabel);
24
 
 
25
  pluginLabel.setText("No plugin loaded", juce::dontSendNotification);
26
  pluginLabel.setFont(juce::FontOptions(13.0f));
27
  pluginLabel.setJustificationType(juce::Justification::centred);
28
  pluginLabel.setColour(juce::Label::textColourId, juce::Colour(0xffaaaaaa));
29
  addAndMakeVisible(pluginLabel);
30
 
31
+ pluginButton.onClick = [this]() { pluginButtonClicked(); };
 
32
  pluginButton.setColour(juce::TextButton::buttonColourId, juce::Colour(0xff2d2d44));
33
  pluginButton.setColour(juce::TextButton::textColourOffId, juce::Colours::white);
34
  addAndMakeVisible(pluginButton);
35
 
36
+ startTimerHz(4);
37
  }
38
 
39
  PluginBridgeEditor::~PluginBridgeEditor()
 
63
 
64
  void PluginBridgeEditor::timerCallback()
65
  {
66
+ // MCP status
67
  if (processorRef.isMcpServerRunning())
68
  {
69
  statusLabel.setText("MCP: running", juce::dontSendNotification);
 
78
  portLabel.setText("", juce::dontSendNotification);
79
  }
80
 
81
+ // Plugin status
82
  auto& mgr = processorRef.getHostedPluginManager();
83
  if (mgr.isLoaded())
84
  {
 
91
  {
92
  pluginLabel.setText("No plugin loaded", juce::dontSendNotification);
93
  pluginLabel.setColour(juce::Label::textColourId, juce::Colour(0xff888888));
94
+ if (!processorRef.isScanning())
95
+ pluginButton.setButtonText("Select Plugin...");
96
+ }
97
+
98
+ // Update button during scan
99
+ if (processorRef.isScanning())
100
+ {
101
+ pluginButton.setButtonText("Scanning...");
102
+ pluginButton.setEnabled(false);
103
+ }
104
+ else
105
+ {
106
+ pluginButton.setEnabled(true);
107
  }
108
  }
109
 
110
+ void PluginBridgeEditor::pluginButtonClicked()
111
  {
112
+ if (processorRef.isScanComplete())
 
113
  {
114
+ // Scan done — show menu immediately
115
  showPluginMenu();
 
116
  }
117
+ else if (!processorRef.isScanning())
 
 
 
 
 
 
 
 
 
 
 
118
  {
119
+ // Start scan (owned by Processor — safe even if editor closes)
120
+ processorRef.startPluginScan();
121
+ // Timer will update button text to "Scanning..." and show menu when done
122
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  }
124
 
125
  void PluginBridgeEditor::showPluginMenu()
126
  {
127
+ const auto& types = processorRef.getScannedPlugins();
 
128
 
129
  if (types.isEmpty())
130
  {
131
+ juce::PopupMenu menu;
132
  menu.addItem(-1, "(No plugins found)", false);
133
  menu.showMenuAsync(juce::PopupMenu::Options().withTargetComponent(&pluginButton),
134
  [](int) {});
135
  return;
136
  }
137
 
138
+ // Group by manufacturer
139
+ juce::PopupMenu menu;
140
  juce::StringArray manufacturers;
141
  for (const auto& desc : types)
142
  {
 
166
 
167
  void PluginBridgeEditor::loadPluginByIndex(int index)
168
  {
169
+ const auto& types = processorRef.getScannedPlugins();
170
  if (index >= 0 && index < types.size())
171
  {
172
  const auto& desc = types[index];