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

Fix crash: Scan plugins on message thread via Timer (one per tick), not background thread"

Browse files
Files changed (1) hide show
  1. Source/PluginBridgeProcessor.cpp +57 -31
Source/PluginBridgeProcessor.cpp CHANGED
@@ -1,6 +1,5 @@
1
  #include "PluginBridgeProcessor.h"
2
  #include "PluginBridgeEditor.h"
3
- #include <thread>
4
 
5
  PluginBridgeProcessor::PluginBridgeProcessor()
6
  : AudioProcessor(BusesProperties()
@@ -14,6 +13,7 @@ PluginBridgeProcessor::PluginBridgeProcessor()
14
  PluginBridgeProcessor::~PluginBridgeProcessor()
15
  {
16
  mcpServer.stop();
 
17
  }
18
 
19
  void PluginBridgeProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
@@ -90,43 +90,69 @@ void PluginBridgeProcessor::startPluginScan()
90
 
91
  scanning.store(true);
92
 
93
- // Detached thread is safe here because Processor outlives Editor
94
- // and scannedPlugins is only written by this thread, read by message thread after scanComplete=true
95
- std::thread([this]()
 
 
 
 
 
 
 
 
 
 
96
  {
97
- juce::AudioPluginFormatManager formatManager;
98
- #if JUCE_PLUGINHOST_VST3
99
- formatManager.addFormat(new juce::VST3PluginFormat());
100
- #endif
101
- #if JUCE_PLUGINHOST_AU
102
- formatManager.addFormat(new juce::AudioUnitPluginFormat());
103
- #endif
 
 
 
 
 
 
 
104
 
105
- juce::KnownPluginList pluginList;
106
 
107
- for (int i = 0; i < formatManager.getNumFormats(); ++i)
108
- {
109
- auto* format = formatManager.getFormat(i);
110
- auto searchPaths = format->getDefaultLocationsToSearch();
111
-
112
- juce::PluginDirectoryScanner scanner(
113
- pluginList,
114
- *format,
115
- searchPaths,
116
- true,
117
- juce::File()
118
- );
119
-
120
- juce::String pluginName;
121
- while (scanner.scanNextFile(false, pluginName)) {}
122
- }
123
 
124
- // Copy results (safe — Editor only reads after scanComplete is true)
125
- scannedPlugins = pluginList.getTypes();
 
 
 
 
 
126
  scanning.store(false);
127
  scanComplete.store(true);
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
- }).detach();
 
 
 
 
 
130
  }
131
 
132
  // JUCE plugin entry point
 
1
  #include "PluginBridgeProcessor.h"
2
  #include "PluginBridgeEditor.h"
 
3
 
4
  PluginBridgeProcessor::PluginBridgeProcessor()
5
  : AudioProcessor(BusesProperties()
 
13
  PluginBridgeProcessor::~PluginBridgeProcessor()
14
  {
15
  mcpServer.stop();
16
+ stopTimer();
17
  }
18
 
19
  void PluginBridgeProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
 
90
 
91
  scanning.store(true);
92
 
93
+ // Initialize scanner on message thread
94
+ scanFormatManager = std::make_unique<juce::AudioPluginFormatManager>();
95
+ #if JUCE_PLUGINHOST_VST3
96
+ scanFormatManager->addFormat(new juce::VST3PluginFormat());
97
+ #endif
98
+ #if JUCE_PLUGINHOST_AU
99
+ scanFormatManager->addFormat(new juce::AudioUnitPluginFormat());
100
+ #endif
101
+
102
+ scanList = std::make_unique<juce::KnownPluginList>();
103
+
104
+ // Build file list to scan
105
+ for (int i = 0; i < scanFormatManager->getNumFormats(); ++i)
106
  {
107
+ auto* format = scanFormatManager->getFormat(i);
108
+ auto paths = format->getDefaultLocationsToSearch();
109
+
110
+ // Use a temporary scanner just to get the file list
111
+ juce::PluginDirectoryScanner tempScanner(
112
+ *scanList, *format, paths, true, juce::File());
113
+
114
+ // We'll use the scanner directly — start it
115
+ scanners.add(new ScannerState{
116
+ std::make_unique<juce::PluginDirectoryScanner>(
117
+ *scanList, *format, paths, true, juce::File()),
118
+ false
119
+ });
120
+ }
121
 
122
+ currentScannerIndex = 0;
123
 
124
+ // Use Timer to scan one file per tick on the message thread
125
+ startTimerHz(30); // 30 files per second — responsive UI
126
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
+ void PluginBridgeProcessor::timerCallback()
129
+ {
130
+ if (currentScannerIndex >= scanners.size())
131
+ {
132
+ // All scanners done
133
+ stopTimer();
134
+ scannedPlugins = scanList->getTypes();
135
  scanning.store(false);
136
  scanComplete.store(true);
137
+ scanners.clear();
138
+ scanFormatManager.reset();
139
+ scanList.reset();
140
+ return;
141
+ }
142
+
143
+ auto* state = scanners[currentScannerIndex];
144
+ if (state->done)
145
+ {
146
+ currentScannerIndex++;
147
+ return;
148
+ }
149
 
150
+ juce::String pluginName;
151
+ if (!state->scanner->scanNextFile(true, pluginName))
152
+ {
153
+ state->done = true;
154
+ currentScannerIndex++;
155
+ }
156
  }
157
 
158
  // JUCE plugin entry point