@@ -18,21 +18,17 @@ if not reaper.ImGui_CreateContext then
1818 return
1919end
2020
21- local ctx = reaper .ImGui_CreateContext (' ReaPyTapeSim3 ' )
21+ local ctx = reaper .ImGui_CreateContext (' Analog Tape Simulator ' )
2222
2323-- Variables
2424local age = 50.0
2525local tape_type_idx = 1 -- 1 = A, 2 = B
26-
2726local format_list = {" WAV" , " MP3" }
2827local format_idx = 1 -- 1 = WAV, 2 = MP3
29-
3028local sr_list = {" 44100" , " 48000" , " 88200" , " 96000" }
3129local sr_idx = 2 -- default 48000
32-
3330local bd_list = {" 16" , " 24" , " 32" }
3431local bd_idx = 2 -- default 24
35-
3632local br_list = {" 128k" , " 192k" , " 256k" , " 320k" }
3733local br_idx = 4 -- default 320k
3834
@@ -45,19 +41,15 @@ local processing_frames = 0
4541-- Locate python script
4642local script_path = debug.getinfo (1 , " S" ).source :match (" @?(.*[\\ /])" )
4743if not script_path then script_path = " " end
48- local py_script = script_path .. " tape_sim3 .py"
44+ local py_script = script_path .. " tape_sim .py"
4945
5046-- DSP Processing Execute
5147function ExecuteProcessing ()
5248 local ext = format_idx == 1 and " wav" or " mp3"
5349 local out_file = input_file .. " _taped." .. ext
5450
55- -- Delete any old render sitting there to ensure we check for a fresh file later
56- if reaper .file_exists (out_file ) then
57- os.remove (out_file )
58- end
51+ if reaper .file_exists (out_file ) then os.remove (out_file ) end
5952
60- -- Format CLI command
6153 local cmd = string.format (' python "%s" -i "%s" -o "%s" -a %f -t %s --out-format %s --samplerate %s' ,
6254 py_script , input_file , out_file , age , tape_type_idx == 1 and " A" or " B" , ext , sr_list [sr_idx ])
6355
@@ -67,90 +59,86 @@ function ExecuteProcessing()
6759 cmd = cmd .. string.format (' --bitrate %s' , br_list [br_idx ])
6860 end
6961
70- -- Run processing and capture all stdout/stderr to log errors
7162 local handle = io.popen (cmd .. ' 2>&1' )
7263 local result = " "
7364 if handle then
7465 result = handle :read (" *a" )
7566 handle :close ()
7667 end
7768
78- -- ERROR CHECKING: Did Python actually create the file?
7969 if not reaper .file_exists (out_file ) then
80- reaper .ShowConsoleMsg (" --- TAPE SIMULATOR PYTHON ERROR ---\n\n " )
81- reaper .ShowConsoleMsg (" Command run:\n " .. cmd .. " \n\n " )
82- reaper .ShowConsoleMsg (" Output/Error Log:\n " .. (result or " None" ) .. " \n " )
83- reaper .ShowMessageBox (" Processing failed!\n\n The audio file was not created. This usually means Python, FFmpeg, or a required package (numpy, scipy, soundfile) is missing or errored.\n\n Check the REAPER Console for the exact crash log." , " Processing Error" , 0 )
84-
70+ reaper .ShowConsoleMsg (" --- TAPE SIM ERROR ---\n " .. (result or " " ) .. " \n " )
71+ reaper .ShowMessageBox (" Processing failed! Check Console for logs." , " Error" , 0 )
8572 processing = false
8673 return
8774 end
8875
89- -- Handle output to Reaper depending on source
9076 if target_item and reaper .ValidatePtr (target_item , " MediaItem*" ) then
91- -- Apply strictly to timeline clip (Take addition)
9277 local take = reaper .AddTakeToMediaItem (target_item )
9378 local src = reaper .PCM_Source_CreateFromFile (out_file )
9479 reaper .SetMediaItemTake_Source (take , src )
9580 reaper .SetActiveTake (take )
9681 reaper .UpdateItemInProject (target_item )
9782 else
98- -- Create completely new track (For Drag/Drop or Browsed Files)
9983 reaper .InsertTrackAtIndex (0 , true )
10084 local track = reaper .GetTrack (0 , 0 )
10185 reaper .GetSetMediaTrackInfo_String (track , " P_NAME" , " Tape Sim Output" , true )
10286 local item = reaper .AddMediaItemToTrack (track )
10387 reaper .SetMediaItemInfo_Value (item , " D_POSITION" , 0 )
104-
10588 local take = reaper .AddTakeToMediaItem (item )
10689 local src = reaper .PCM_Source_CreateFromFile (out_file )
10790 reaper .SetMediaItemTake_Source (take , src )
108-
10991 local length = reaper .GetMediaSourceLength (src )
11092 reaper .SetMediaItemInfo_Value (item , " D_LENGTH" , length )
11193 reaper .UpdateItemInProject (item )
11294 end
11395
114- reaper .Main_OnCommand (40047 , 0 ) -- Peaks: Build any missing peaks
96+ reaper .Main_OnCommand (40047 , 0 )
11597 reaper .UpdateArrange ()
11698
11799 input_file = " "
118100 target_item = nil
119101end
120102
121103function DrawUI ()
122- local visible , open = reaper .ImGui_Begin (ctx , ' ReaPyTapeSim3 ' , true , reaper .ImGui_WindowFlags_AlwaysAutoResize ())
104+ local visible , open = reaper .ImGui_Begin (ctx , ' Tape Simulator Offline Processor ' , true , reaper .ImGui_WindowFlags_AlwaysAutoResize ())
123105 if not visible then return open end
124106
125107 -- 1. DROP / BROWSE AREA
108+ -- We push color, draw button, handle dragdrop, THEN pop color.
126109 reaper .ImGui_PushStyleColor (ctx , reaper .ImGui_Col_Button (), 0x333333FF )
127110
128- local btn_text = input_file == " " and " Click to Browse File \n\n (or Drag & Drop File Here) " or " File Loaded:\n " .. input_file :match (" ([^\\ /]+)$" )
111+ local btn_text = input_file == " " and " Click to Browse\n OR \n [ DRAG AUDIO FILE HERE ] " or " File Loaded:\n " .. input_file :match (" ([^\\ /]+)$" )
129112
130- -- Opens File Explorer on click
131- if reaper .ImGui_Button (ctx , btn_text , 350 , 70 ) then
113+ -- Main Button
114+ if reaper .ImGui_Button (ctx , btn_text , 350 , 80 ) then
132115 local retval , filename = reaper .GetUserFileNameForRead (" " , " Select Audio File" , " " )
133116 if retval then
134117 input_file = filename
135- target_item = nil -- FORCE New track creation
118+ target_item = nil
136119 end
137120 end
138- reaper .ImGui_PopStyleColor (ctx )
139121
140- -- Handle Native Drag & Drop from OS / Media Explorer
122+ -- Drag & Drop Handler (Must be immediately after the target item)
141123 if reaper .ImGui_BeginDragDropTarget (ctx ) then
142124 local rv , payload = reaper .ImGui_AcceptDragDropPayload (ctx , ' DND_FILES' )
143125 if rv then
144- for file in payload :gmatch (" (.-)%z" ) do
126+ -- DND_FILES returns paths separated by \0
127+ local file_found = false
128+ for file in payload :gmatch (" [^%z]+" ) do
129+ -- Accept the first file found
145130 input_file = file
146- target_item = nil -- FORCE New track creation
147- break
131+ target_item = nil
132+ file_found = true
133+ break
148134 end
149135 end
150136 reaper .ImGui_EndDragDropTarget (ctx )
151137 end
152138
153- -- Dedicated button for Reaper Selected Items (Updates Item in Place)
139+ reaper .ImGui_PopStyleColor (ctx ) -- Pop color AFTER drag logic
140+
141+ -- Helper for Timeline Items
154142 if reaper .ImGui_Button (ctx , " Grab Selected Item from REAPER Timeline" , 350 , 25 ) then
155143 local item = reaper .GetSelectedMediaItem (0 , 0 )
156144 if item then
@@ -160,9 +148,11 @@ function DrawUI()
160148 local path = reaper .GetMediaSourceFileName (src , " " )
161149 if path ~= " " then
162150 input_file = path
163- target_item = item -- Registers specific clip
151+ target_item = item
164152 end
165153 end
154+ else
155+ reaper .ShowMessageBox (" No item selected in timeline!" , " Selection Error" , 0 )
166156 end
167157 end
168158
@@ -217,10 +207,8 @@ function DrawUI()
217207
218208 -- 4. PROCESSING LOGIC
219209 if processing then
220- reaper .ImGui_Text (ctx , " Processing... Please wait. REAPER may freeze briefly. " )
210+ reaper .ImGui_Text (ctx , " Processing... Please wait." )
221211 processing_frames = processing_frames + 1
222-
223- -- Delay execution so UI physically renders the text first
224212 if processing_frames > 2 then
225213 ExecuteProcessing ()
226214 processing = false
@@ -239,19 +227,15 @@ function DrawUI()
239227 end
240228 end
241229
242- if process_triggered and not processing then
243- processing = true
244- end
230+ if process_triggered and not processing then processing = true end
245231
246232 reaper .ImGui_End (ctx )
247233 return open
248234end
249235
250236function loop ()
251237 local open = DrawUI ()
252- if open then
253- reaper .defer (loop )
254- end
238+ if open then reaper .defer (loop ) end
255239end
256240
257- reaper .defer (loop )
241+ reaper .defer (loop )
0 commit comments