2023-01-15 17:01:27 +00:00
# include "FileParser.h"
2023-02-05 17:39:02 +00:00
# include <numbers>
2025-01-05 15:55:53 +00:00
# include "../PluginProcessor.h"
2023-01-15 17:01:27 +00:00
2025-04-04 10:28:13 +00:00
FileParser : : FileParser ( OscirenderAudioProcessor & p , std : : function < void ( int , juce : : String , juce : : String ) > errorCallback )
: errorCallback ( errorCallback ) , audioProcessor ( p ) { }
2023-01-15 17:01:27 +00:00
2025-04-24 16:13:45 +00:00
// Helper function to show file size warning
void FileParser : : showFileSizeWarning ( juce : : String fileName , int64_t totalBytes , int64_t mbLimit ,
juce : : String fileType , std : : function < void ( ) > callback ) {
if ( totalBytes < = mbLimit * 1024 * 1024 ) {
callback ( ) ;
return ;
}
const double fileSizeMB = totalBytes / ( 1024.0 * 1024.0 ) ;
2025-05-12 19:55:10 +00:00
juce : : String message = " The " + fileType + " file ' " + fileName + " ' you're trying to open is " + juce : : String ( fileSizeMB , 2 ) + " MB in size, and may time a long time to open. \n \n Would you like to continue loading it? " ;
2025-04-24 16:13:45 +00:00
juce : : MessageManager : : callAsync ( [ this , message , callback ] ( ) {
juce : : AlertWindow : : showOkCancelBox (
juce : : AlertWindow : : WarningIcon ,
" Large File " ,
message ,
" Continue " ,
" Cancel " ,
nullptr ,
juce : : ModalCallbackFunction : : create ( [ this , callback ] ( int result ) {
juce : : SpinLock : : ScopedLockType scope ( lock ) ;
if ( result = = 1 ) { // 1 = OK button pressed
callback ( ) ;
} else {
disable ( ) ; // Mark this parser as inactive
// Notify the processor to remove this parser
juce : : MessageManager : : callAsync ( [ this ] {
juce : : SpinLock : : ScopedLockType lock1 ( audioProcessor . parsersLock ) ;
juce : : SpinLock : : ScopedLockType lock2 ( audioProcessor . effectsLock ) ;
audioProcessor . removeParser ( this ) ;
} ) ;
}
} )
) ;
} ) ;
}
2025-04-04 10:28:13 +00:00
void FileParser : : parse ( juce : : String fileId , juce : : String fileName , juce : : String extension , std : : unique_ptr < juce : : InputStream > stream , juce : : Font font ) {
2023-07-11 21:28:54 +00:00
juce : : SpinLock : : ScopedLockType scope ( lock ) ;
2023-09-14 19:21:08 +00:00
if ( extension = = " .lua " & & lua ! = nullptr & & lua - > isFunctionValid ( ) ) {
fallbackLuaScript = lua - > getScript ( ) ;
}
2023-02-05 00:43:57 +00:00
object = nullptr ;
svg = nullptr ;
2023-04-04 15:17:37 +00:00
text = nullptr ;
2024-04-15 19:54:25 +00:00
gpla = nullptr ;
2023-04-04 15:17:37 +00:00
lua = nullptr ;
2024-05-11 22:10:54 +00:00
img = nullptr ;
2024-08-22 15:59:21 +00:00
wav = nullptr ;
2023-02-05 00:43:57 +00:00
2023-01-15 22:34:02 +00:00
if ( extension = = " .obj " ) {
2025-04-04 10:28:13 +00:00
const int64_t fileSize = stream - > getTotalLength ( ) ;
juce : : String objContent = stream - > readEntireStreamAsString ( ) ;
2025-04-24 16:13:45 +00:00
showFileSizeWarning ( fileName , fileSize , 1 , " OBJ " , [ this , objContent ] ( ) {
2025-04-04 10:28:13 +00:00
object = std : : make_shared < WorldObject > ( objContent . toStdString ( ) ) ;
2025-04-24 16:13:45 +00:00
isAnimatable = false ;
sampleSource = false ;
} ) ;
2023-02-05 00:43:57 +00:00
} else if ( extension = = " .svg " ) {
2023-02-05 19:36:50 +00:00
svg = std : : make_shared < SvgParser > ( stream - > readEntireStreamAsString ( ) ) ;
2023-02-05 20:36:51 +00:00
} else if ( extension = = " .txt " ) {
2025-05-08 21:10:34 +00:00
text = std : : make_shared < TextParser > ( stream - > readEntireStreamAsString ( ) , audioProcessor . font ) ;
2023-04-04 15:17:37 +00:00
} else if ( extension = = " .lua " ) {
2024-05-11 22:10:54 +00:00
lua = std : : make_shared < LuaParser > ( fileId , stream - > readEntireStreamAsString ( ) , errorCallback , fallbackLuaScript ) ;
2024-04-15 19:54:25 +00:00
} else if ( extension = = " .gpla " ) {
2025-01-21 21:34:25 +00:00
juce : : MemoryBlock buffer { } ;
int bytesRead = stream - > readIntoMemoryBlock ( buffer ) ;
if ( bytesRead < 8 ) return ;
char * gplaData = ( char * ) buffer . getData ( ) ;
const char tag [ ] = " GPLA " ;
bool isBinary = true ;
for ( int i = 0 ; i < 8 ; i + + ) {
isBinary = isBinary & & tag [ i ] = = gplaData [ i ] ;
}
if ( isBinary ) {
gpla = std : : make_shared < LineArtParser > ( gplaData , bytesRead ) ;
2025-02-03 18:30:14 +00:00
} else {
2025-01-21 21:34:25 +00:00
stream - > setPosition ( 0 ) ;
gpla = std : : make_shared < LineArtParser > ( stream - > readEntireStreamAsString ( ) ) ;
}
2025-04-21 17:05:04 +00:00
} else if ( extension = = " .gif " | | extension = = " .png " | | extension = = " .jpg " | | extension = = " .jpeg " | | extension = = " .mp4 " | | extension = = " .mov " ) {
2024-05-11 22:10:54 +00:00
juce : : MemoryBlock buffer { } ;
int bytesRead = stream - > readIntoMemoryBlock ( buffer ) ;
2025-04-24 16:13:45 +00:00
showFileSizeWarning ( fileName , bytesRead , 20 , ( extension = = " .mp4 " | | extension = = " .mov " ) ? " video " : " image " ,
[ this , buffer , extension ] ( ) {
img = std : : make_shared < ImageParser > ( audioProcessor , extension , buffer ) ;
isAnimatable = extension = = " .gif " | | extension = = " .mp4 " | | extension = = " .mov " ;
sampleSource = true ;
}
) ;
2025-02-03 18:30:14 +00:00
} else if ( extension = = " .wav " | | extension = = " .aiff " | | extension = = " .flac " | | extension = = " .ogg " | | extension = = " .mp3 " ) {
2025-01-07 17:51:08 +00:00
wav = std : : make_shared < WavParser > ( audioProcessor ) ;
2025-04-24 16:13:45 +00:00
if ( ! wav - > parse ( std : : move ( stream ) ) ) {
juce : : MessageManager : : callAsync ( [ this , fileName ] {
juce : : AlertWindow : : showMessageBoxAsync ( juce : : AlertWindow : : AlertIconType : : WarningIcon ,
" Error Loading " + fileName ,
" The audio file ' " + fileName + " ' could not be loaded. " ) ;
} ) ;
}
2023-01-15 22:34:02 +00:00
}
2023-07-01 14:29:53 +00:00
2025-04-21 17:05:04 +00:00
isAnimatable = gpla ! = nullptr | | ( img ! = nullptr & & ( extension = = " .gif " | | extension = = " .mp4 " | | extension = = " .mov " ) ) ;
2024-08-22 15:59:21 +00:00
sampleSource = lua ! = nullptr | | img ! = nullptr | | wav ! = nullptr ;
2023-01-15 17:01:27 +00:00
}
2025-04-23 14:26:33 +00:00
std : : vector < std : : unique_ptr < osci : : Shape > > FileParser : : nextFrame ( ) {
2025-04-24 16:13:45 +00:00
juce : : SpinLock : : ScopedLockType scope ( lock ) ;
if ( object ! = nullptr ) {
return object - > draw ( ) ;
} else if ( svg ! = nullptr ) {
return svg - > draw ( ) ;
} else if ( text ! = nullptr ) {
return text - > draw ( ) ;
} else if ( gpla ! = nullptr ) {
return gpla - > draw ( ) ;
}
auto tempShapes = std : : vector < std : : unique_ptr < osci : : Shape > > ( ) ;
// return a square
tempShapes . push_back ( std : : make_unique < osci : : Line > ( osci : : Point ( - 0.5 , - 0.5 , 0 ) , osci : : Point ( 0.5 , - 0.5 , 0 ) ) ) ;
tempShapes . push_back ( std : : make_unique < osci : : Line > ( osci : : Point ( 0.5 , - 0.5 , 0 ) , osci : : Point ( 0.5 , 0.5 , 0 ) ) ) ;
tempShapes . push_back ( std : : make_unique < osci : : Line > ( osci : : Point ( 0.5 , 0.5 , 0 ) , osci : : Point ( - 0.5 , 0.5 , 0 ) ) ) ;
tempShapes . push_back ( std : : make_unique < osci : : Line > ( osci : : Point ( - 0.5 , 0.5 , 0 ) , osci : : Point ( - 0.5 , - 0.5 , 0 ) ) ) ;
return tempShapes ;
2023-01-15 17:01:27 +00:00
}
2025-04-23 14:26:33 +00:00
osci : : Point FileParser : : nextSample ( lua_State * & L , LuaVariables & vars ) {
2025-04-24 16:13:45 +00:00
juce : : SpinLock : : ScopedLockType scope ( lock ) ;
if ( lua ! = nullptr ) {
auto values = lua - > run ( L , vars ) ;
if ( values . size ( ) = = 2 ) {
return osci : : Point ( values [ 0 ] , values [ 1 ] , 0 ) ;
} else if ( values . size ( ) > 2 ) {
return osci : : Point ( values [ 0 ] , values [ 1 ] , values [ 2 ] ) ;
}
} else if ( img ! = nullptr ) {
return img - > getSample ( ) ;
} else if ( wav ! = nullptr ) {
2024-08-22 15:59:21 +00:00
return wav - > getSample ( ) ;
}
2024-02-22 14:28:09 +00:00
2025-04-24 16:13:45 +00:00
return osci : : Point ( ) ;
2023-07-01 14:29:53 +00:00
}
bool FileParser : : isSample ( ) {
2025-04-24 16:13:45 +00:00
return sampleSource ;
2023-07-01 14:29:53 +00:00
}
2023-01-15 17:01:27 +00:00
bool FileParser : : isActive ( ) {
2025-04-24 16:13:45 +00:00
return active ;
2023-01-15 17:01:27 +00:00
}
void FileParser : : disable ( ) {
2025-04-24 16:13:45 +00:00
active = false ;
2023-01-15 17:01:27 +00:00
}
void FileParser : : enable ( ) {
2025-04-24 16:13:45 +00:00
active = true ;
2023-01-15 17:01:27 +00:00
}
2023-07-04 13:58:36 +00:00
std : : shared_ptr < WorldObject > FileParser : : getObject ( ) {
2025-04-24 16:13:45 +00:00
return object ;
2023-07-04 13:58:36 +00:00
}
std : : shared_ptr < SvgParser > FileParser : : getSvg ( ) {
2025-04-24 16:13:45 +00:00
return svg ;
2023-07-04 13:58:36 +00:00
}
std : : shared_ptr < TextParser > FileParser : : getText ( ) {
2025-04-24 16:13:45 +00:00
return text ;
2023-07-04 13:58:36 +00:00
}
2024-04-15 19:54:25 +00:00
std : : shared_ptr < LineArtParser > FileParser : : getLineArt ( ) {
2025-04-24 16:13:45 +00:00
return gpla ;
2024-04-15 19:54:25 +00:00
}
2023-07-04 13:58:36 +00:00
std : : shared_ptr < LuaParser > FileParser : : getLua ( ) {
2025-04-24 16:13:45 +00:00
return lua ;
2023-07-04 13:58:36 +00:00
}
2024-05-11 22:10:54 +00:00
std : : shared_ptr < ImageParser > FileParser : : getImg ( ) {
2025-04-24 16:13:45 +00:00
return img ;
2024-06-01 20:50:56 +00:00
}
2024-08-22 15:59:21 +00:00
std : : shared_ptr < WavParser > FileParser : : getWav ( ) {
return wav ;
}
2025-04-22 18:13:41 +00:00
int FileParser : : getNumFrames ( ) {
if ( gpla ! = nullptr ) {
return gpla - > numFrames ;
} else if ( img ! = nullptr ) {
return img - > getNumFrames ( ) ;
}
return 1 ; // Default to 1 frame for non-animatable content
}
int FileParser : : getCurrentFrame ( ) {
if ( gpla ! = nullptr ) {
return gpla - > frameNumber ;
} else if ( img ! = nullptr ) {
return img - > getCurrentFrame ( ) ;
}
return 0 ; // Default to frame 0 for non-animatable content
}
void FileParser : : setFrame ( int frame ) {
if ( gpla ! = nullptr ) {
gpla - > setFrame ( frame ) ;
} else if ( img ! = nullptr ) {
img - > setFrame ( frame ) ;
}
}