REW Beta Release Trying to write some macros...

moedra

Member
Thread Starter
Joined
Mar 1, 2021
Posts
148
Hi John. I need some help. I am not a coder, but I am trying to enlist the help of Gemini to write some macros for REW using the API and I am hitting a wall where REW will not release the data needed to make the macros function properly. The hard part is that I don't understand Python code or the API and therefore cannot troubleshoot. I've had Gemini scan this entire forum for anything that can be of assistance, and although we've learned a lot, this macro still doesn't fully work the way it's meant to (hands-free). Gemini even tried having the entire thing done in Python code, but REW won't release the measurement data, and it won't save out files in the scripts, so data cannot be extracted that way either...

In this first macro (of maybe four or five), I want to:
1. take the main measurements, which I'm calling Measurement-L and Measurement-R, and smooth them to 1/6
2. copy them via response copy, resulting in Measurement-L-copy and Measurement-R-copy
3. smooth both copies to 1/12
4. generate RMS Average measurement of Measurement-L and Measurement-L-copy, resulting in RMS Average 1
5. generate RMS Average measurement of Measurement-R and Measurement-R-copy, resulting in RMS Average 2
6. export RMS Average 1 as text, with no smoothing, max frequency capped to 22kHz, to filename Main-L.txt
7. export RMS Average 2 as text, with no smoothing, max frequency capped to 22kHz, to filename Main-R.txt
8. import Main-L and Main-R back into REW
9. generate minimum phase copies (new measurement versions) of Main-L and Main-R, resulting in Main-L-MP and Main-R-MP
10. delete/remove the copies and the RMS averages, as they are not needed any further

The objective of this macro is to have Main-L, Main-L-MP, Main-R, and Main-R-MP prepared for further operations in the following regard:
• They contain the relative smoothing value of 1/9, yet they are not smoothed as far as REW is concerned.
• The raw data is "smoothed", so subsequent arithmetic can be performed on the smoothed data rather than the original raw measurement data.
Of course, if 1/9 were an option I'd just smooth to that and be done with it, but this is great exercise to have a macro do, so I'm doing it!

The problem is that not all of these steps work correctly, and Gemini is having a hard time figuring out how to get the API to do what is being asked. Here's breakdown of what is and isn't working:
1. works great. 1/6 smoothed L and R
2. response copy works great
3. this works. same as step 1
4 and 5. This does not work. In the script I have resorted to having Gemini code this as a user step, so I have to generate the RMS average measurements manually
6 and 7. This does not work either. We've been able to get the parameters set but REW will not export any files. This has become another manual operation.
8. same as the last step, REW will not import the files I made (Main-L.txt and Main-R.txt). Another manual operation. The script waits for me to import the files, then continues.
9. this step works
10. this does not work properly. Seemingly random measurements got removed and so this, too, has become a manual operation

So, the macro has too many user prompts, and the solution is simply a matter of getting REW to generate the average measurements and export/import the files so that the macro can be completely hands-free. The idea is to make this automatic so that it's faster, and also easier for someone who has no patience to do everything manually!
And I like the idea of making macros, since the later steps of my overall procedure are full of time-consuming arithmetic functions that have to executed in sequence for both speakers' measurements.

The script for "macro 1" is here.
For reference, "V3.1 minimum phase logic" refers to the version of the script in which we successfully got it to generate the minimum phase versions we asked for, so we made it a point to use that code because it was proven to work.

======================

import urllib.request
import json
import time

REW_URL = "http://127.0.0.1:4735"

def send_rew_request(endpoint, data=None, method='POST'):
url = f"{REW_URL}{endpoint}"
headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
try:
req_data = json.dumps(data).encode('utf-8') if data else None
req = urllib.request.Request(url, data=req_data, headers=headers, method=method)
with urllib.request.urlopen(req) as response:
return json.loads(response.read().decode('utf-8'))
except Exception: return None

def get_id(name):
# Quick check for ID
data = send_rew_request("/measurements", method='GET') or {}
for m_id, m_info in data.items():
if m_info.get('title') == name: return m_id
return None

def run_prep(name):
print(f" [+] Prepping {name} (Smooth 1/6 + Copy + Smooth 1/12)...")
sid = get_id(name)
if not sid:
print(f" [!] Error: {name} not found.")
return

# 1. Smooth Source to 1/6
send_rew_request(f"/measurements/{sid}/command", {"command": "Smooth", "parameters": [["smoothing", "1/6"]]})

# 2. Create Copy
send_rew_request(f"/measurements/{sid}/command", {"command": "Response copy"})
time.sleep(1) # Short pause to let copy register

# 3. Find and Smooth Copy to 1/12
# We check standard name variations for the copy
cid = get_id(f"{name}-copy") or get_id("Response copy") or get_id(f"{name} copy")
if cid:
send_rew_request(f"/measurements/{cid}/command", {"command": "Smooth", "parameters": [["smoothing", "1/12"]]})
else:
print(f" [!] Warning: Could not auto-smooth the copy for {name}. Please check it.")

def wait_for_import_and_finalize(target_name):
print(f"\n [...] Watching for '{target_name}' to appear in REW...")

# INFINITE LOOP: This prevents the script from failing if you take your time.
found_id = None
while not found_id:
found_id = get_id(target_name)
if not found_id:
time.sleep(2) # Poll every 2 seconds

print(f" [+] {target_name} detected! Applying V3.1 Minimum Phase logic...")

# THE PROVEN V3.1 COMMAND
send_rew_request(f"/measurements/{found_id}/command", {
"command": "Minimum phase version",
"parameters": [
["append lf tail", "false"], ["append hf tail", "false"],
["include cal", "false"], ["replicate data", "false"],
["apply frequency warping to hf tail", "false"]
]
})

# Verify it worked
time.sleep(1)
print(f" [√] {target_name} processing complete.")

if __name__ == "__main__":
print("--- PHASE 1: AUTOMATED PREP ---")
run_prep("Measurement-L")
run_prep("Measurement-R")

print("\n" + "="*60)
print(" PHASE 2: MANUAL INTERVENTION (The Missing Link)")
print(" 1. Go to 'All SPL' tab.")
print(" 2. Average 'Measurement-L' + Copy -> Export/Import as 'Main-L'")
print(" 3. Average 'Measurement-R' + Copy -> Export/Import as 'Main-R'")
print(" (The script is strictly waiting for 'Main-L' and 'Main-R' to appear)")
print("="*60)

# These functions will block (wait) until they see the files.
# They effectively act as the "Second Half" of the automation.
wait_for_import_and_finalize("Main-L")
wait_for_import_and_finalize("Main-R")

print("\nMacro 1 Complete. Safe to manually delete temp copies/averages.")
 
Last edited:
This may or may not help, but I don't have any other reference. Here is the terminal readout of the latest few iterations I've run on v10 of the script, along with Gemini's diagnosis below them. The latest version of said script is at the bottom. I am trying to get the steps to work one at a time systematically today rather than have the whole sequence in there at once. Are the issues evident here by chance? I think Gemini is also systematically trying to figure out how to make this work, so it's interesting to watch.

Oh, and I've implemented a color-coding scheme for left and right channels now. Fun.


PS C:\REW_Projects\REW-FilterGen-Scripts> python rew_filtergen_macro1_v10.py
--- Macro 1 v10.05 (Indentation Fixed + Data Retries) ---

--- Processing L Channel ---
[+] Data Bridge: Fetching curves for Main-L...
[...] Data for ID 1 not ready yet, retrying (1/5)...
[...] Data for ID 1 not ready yet, retrying (2/5)...
[...] Data for ID 1 not ready yet, retrying (3/5)...
[...] Data for ID 1 not ready yet, retrying (4/5)...
[...] Data for ID 1 not ready yet, retrying (5/5)...
[...] Data for ID 3 not ready yet, retrying (1/5)...
[...] Data for ID 3 not ready yet, retrying (2/5)...
[...] Data for ID 3 not ready yet, retrying (3/5)...
[...] Data for ID 3 not ready yet, retrying (4/5)...
[...] Data for ID 3 not ready yet, retrying (5/5)...
[!] Error: Failed to pull data from REW for Main-L.

--- Processing R Channel ---
[+] Data Bridge: Fetching curves for Main-R...
[...] Data for ID 2 not ready yet, retrying (1/5)...
[...] Data for ID 2 not ready yet, retrying (2/5)...
[...] Data for ID 2 not ready yet, retrying (3/5)...
[...] Data for ID 2 not ready yet, retrying (4/5)...
[...] Data for ID 2 not ready yet, retrying (5/5)...
[...] Data for ID 4 not ready yet, retrying (1/5)...
[...] Data for ID 4 not ready yet, retrying (2/5)...
[...] Data for ID 4 not ready yet, retrying (3/5)...
[...] Data for ID 4 not ready yet, retrying (4/5)...
[...] Data for ID 4 not ready yet, retrying (5/5)...
[!] Error: Failed to pull data from REW for Main-R.
PS C:\REW_Projects\REW-FilterGen-Scripts> python rew_filtergen_macro1_v10.py^C
PS C:\REW_Projects\REW-FilterGen-Scripts> python rew_filtergen_macro1_v10.py
PS C:\REW_Projects\REW-FilterGen-Scripts> python rew_filtergen_macro1_v10.py
PS C:\REW_Projects\REW-FilterGen-Scripts> python rew_filtergen_macro1_v10.py
PS C:\REW_Projects\REW-FilterGen-Scripts> python rew_filtergen_macro1_v10.py
--- Macro 1 v10.08 (Pre-Flight Audit) ---

--- Processing L Channel ---
[+] Bridging data for Main-L...

--- Processing R Channel ---
[+] Bridging data for Main-R...
PS C:\REW_Projects\REW-FilterGen-Scripts> python rew_filtergen_macro1_v10.py
--- Macro 1 v10.08 (Pre-Flight Audit) ---

--- Processing L Channel ---
[+] Bridging data for Main-L...

--- Processing R Channel ---
[+] Bridging data for Main-R...
PS C:\REW_Projects\REW-FilterGen-Scripts> python rew_filtergen_macro1_v10.py
--- Macro 1 v10.09 (Sidebar Refresh Logic) ---

--- Processing L Channel ---

--- Processing R Channel ---
PS C:\REW_Projects\REW-FilterGen-Scripts> python rew_filtergen_macro1_v10.py
--- Macro 1 v10.10 (Full Debug Mode) ---

>>> STARTING L CHANNEL <<<
[+] Triggering Text Export for ID: 1...
[DEBUG ERROR] API Request failed on /measurements/1/command: HTTP Error 400: Bad Request
[...] Waiting for file (1/5)...
[...] Waiting for file (2/5)...
[...] Waiting for file (3/5)...
[...] Waiting for file (4/5)...
[...] Waiting for file (5/5)...
[!] ERROR: REW failed to write the export file to C:\REW_Projects\temp_api_export.txt
[+] Triggering Text Export for ID: 3...
[DEBUG ERROR] API Request failed on /measurements/3/command: HTTP Error 400: Bad Request
[...] Waiting for file (1/5)...
[...] Waiting for file (2/5)...
[...] Waiting for file (3/5)...
[...] Waiting for file (4/5)...
[...] Waiting for file (5/5)...
[!] ERROR: REW failed to write the export file to C:\REW_Projects\temp_api_export.txt

>>> STARTING R CHANNEL <<<
[+] Triggering Text Export for ID: 2...
[DEBUG ERROR] API Request failed on /measurements/2/command: HTTP Error 400: Bad Request
[...] Waiting for file (1/5)...
[...] Waiting for file (2/5)...
[...] Waiting for file (3/5)...
[...] Waiting for file (4/5)...
[...] Waiting for file (5/5)...
[!] ERROR: REW failed to write the export file to C:\REW_Projects\temp_api_export.txt
[+] Triggering Text Export for ID: 4...
[DEBUG ERROR] API Request failed on /measurements/4/command: HTTP Error 400: Bad Request
[...] Waiting for file (1/5)...
[...] Waiting for file (2/5)...
[...] Waiting for file (3/5)...
[...] Waiting for file (4/5)...
[...] Waiting for file (5/5)...
[!] ERROR: REW failed to write the export file to C:\REW_Projects\temp_api_export.txt
PS C:\REW_Projects\REW-FilterGen-Scripts> python rew_filtergen_macro1_v10.py
--- Macro 1 v10.11 (API Syntax Fix) ---

>>> PROCESSING L SPEAKER <<<
[API ERROR] POST /measurements/1/command: HTTP Error 400: Bad Request
[+] Exporting ID 1 to C:/REW_Projects/temp_api_export.txt...
[API ERROR] POST /measurements/1/command: HTTP Error 400: Bad Request
[+] Exporting ID 3 to C:/REW_Projects/temp_api_export.txt...
[API ERROR] POST /measurements/3/command: HTTP Error 400: Bad Request

>>> PROCESSING R SPEAKER <<<
[API ERROR] POST /measurements/2/command: HTTP Error 400: Bad Request
[+] Exporting ID 2 to C:/REW_Projects/temp_api_export.txt...
[API ERROR] POST /measurements/2/command: HTTP Error 400: Bad Request
[+] Exporting ID 4 to C:/REW_Projects/temp_api_export.txt...
[API ERROR] POST /measurements/4/command: HTTP Error 400: Bad Request


=========================
Gemini's feedback on the above terminal results:


It sounds like we’ve hit a wall where the REW API is accepting our commands but refusing to actually "commit" the data to the UI. Based on forum discussions regarding the REW API, sometimes the import command requires a specific data structure or a "refresh" trigger to appear in the sidebar.

Let's try v10.09. In this version, I’ve adjusted the import payload to include the unit (SPL) and added a "Selection" trigger. Sometimes REW won't show a measurement in the sidebar until you tell the API to "Select" it.

Macro 1: v10.09 (Import Payload Fix + Selection Trigger)​

One more possibility:​

If the file temp_api_export.txt is being created but the import still isn't showing up, it might be that REW's API for import is restricted in the Free tier or specific builds.

Watch your REW screen as the script runs:

  1. Do you see the "Measurement-L-copy" appear and then disappear?
  2. Does a "Exporting" dialog box flash on screen?
If the copies appear and disappear, but "Main" never shows up, we may need to try importing the file using a command-line flag rather than a JSON body.

--------------------------------------------
If the script isn't giving feedback and the measurements aren't appearing, it usually means the script is crashing silently or hitting an "Except: pass" block without telling us why.

Let’s move to v10.10. I have stripped out the "silent" error handling and replaced it with High-Visibility Debugging. This version will print every single interaction to the terminal. If it fails, it will tell us the exact line and error.

I have also added a "Safe Import" check. If REW rejects the data upload, we'll see the raw error code.

Macro 1: v10.10 (High-Visibility Debugging)​

What to watch for in the terminal:​

  1. "API Request failed": This means the connection to REW dropped.
  2. "Waiting for file": If it counts to 5 and fails, REW is ignoring the "Export" command.
  3. "REW rejected the data import": This means our data format is wrong for your specific REW version.
------------------------------------
That HTTP Error 400: Bad Request means REW is receiving the command but rejecting the way the parameters are structured. Specifically, REW's API may be very picky about how file paths are passed in JSON.

The API expects the parameters to be an array of arrays, and it seems that it often dislikes single backslashes in Windows paths (e.g., C:\Projects).

Let’s move to v10.11. I have sanitized the path to use forward slashes (which REW may prefer) and simplified the parameter structure to match the exact syntax REW requires for file exports.

Macro 1: v10.11 (Path Sanitization + API Syntax Fix)​

Why this should fix the 400 Error:​

  • Forward Slashes: REW interprets C:/Path much better than C:\Path via JSON, as backslashes often act as escape characters.
  • Double Nesting: In the parameters, REW specifically looks for [ ["key", "value"] ]. Missing one set of brackets triggers a "Bad Request."
  • File Size Check: It ensures the file is actually on the disk and contains data before trying to read it.

--------------------------------------------



=========================
rew_filtergen_macro1_v10.py
Macro 1 v10.11 (API Syntax Fix)
=========================

import urllib.request
import json
import time
import os
import numpy as np

# --- CONFIGURATION ---
REW_URL = "http://127.0.0.1:4735"
# We use forward slashes to avoid "Bad Request" errors in the API
TEMP_EXPORT = "C:/REW_Projects/temp_api_export.txt"

COLOR_RED, COLOR_ORANGE = 16711680, 16747520
COLOR_GREEN, COLOR_BLUE = 65280, 49151

def send_rew_request(endpoint, data=None, method='POST'):
url = f"{REW_URL}{endpoint}"
headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
try:
req_data = json.dumps(data).encode('utf-8') if data else None
req = urllib.request.Request(url, data=req_data, headers=headers, method=method)
with urllib.request.urlopen(req) as response:
return json.loads(response.read().decode('utf-8'))
except Exception as e:
# If this prints, REW is rejecting the command structure
print(f" [API ERROR] {method} {endpoint}: {e}")
return None

def force_export_and_read(m_id):
if os.path.exists(TEMP_EXPORT):
os.remove(TEMP_EXPORT)

# v10.11 Fix: Exact parameter nesting REW expects
print(f" [+] Exporting ID {m_id} to {TEMP_EXPORT}...")
payload = {
"command": "Export measurement as text",
"parameters": [ ["filename", TEMP_EXPORT] ]
}

send_rew_request(f"/measurements/{m_id}/command", payload)

# Wait for file arrival
for i in range(5):
if os.path.exists(TEMP_EXPORT):
# Check if file is actually written (not 0 bytes)
if os.path.getsize(TEMP_EXPORT) > 0:
print(f" [√] File ready.")
break
time.sleep(1)

if os.path.exists(TEMP_EXPORT):
try:
data = np.genfromtxt(TEMP_EXPORT, comments='*', invalid_raise=False)
return data[:, 0], data[:, 1]
except Exception as e:
print(f" [!] Parse Error: {e}")
return None, None

def run_channel(side):
src, cpy, target = (f"Measurement-{side}", f"Measurement-{side}-copy", f"Main-{side}")
s_col, t_col = (COLOR_RED, COLOR_ORANGE) if side == "L" else (COLOR_GREEN, COLOR_BLUE)

print(f"\n>>> PROCESSING {side} SPEAKER <<<")

# 1. Identify IDs
m_list = send_rew_request("/measurements", method='GET') or {}
sid = next((k for k, v in m_list.items() if v.get('title') == src), None)

if not sid:
print(f" [!] {src} not found.")
return

# 2. Prep & Copy
send_rew_request(f"/measurements/{sid}/command", {"command": "Smooth", "parameters": [["smoothing", "1/6"]]})
send_rew_request(f"/measurements/{sid}/command", {"command": "Set color", "parameters": [["color", s_col]]})
send_rew_request(f"/measurements/{sid}/command", {"command": "Response copy"})

time.sleep(3)
m_list = send_rew_request("/measurements", method='GET') or {}
cid = next((k for k, v in m_list.items() if v.get('title') == cpy), None)

if cid:
send_rew_request(f"/measurements/{cid}/command", {"command": "Smooth", "parameters": [["smoothing", "1/12"]]})

# 3. Data Bridge via Export
f1, s1 = force_export_and_read(sid)
f2, s2 = force_export_and_read(cid)

if s1 is not None and s2 is not None:
# RMS Math
avg = 20 * np.log10(np.sqrt((10**(s1/20)**2 + 10**(s2/20)**2) / 2))

# 4. Import Back to REW
print(f" [+] Uploading {target}...")
send_rew_request("/measurements/import", data={
"name": target, "freq": f1.tolist(), "spl": avg.tolist(), "unit": "dB"
})

time.sleep(2)
m_list = send_rew_request("/measurements", method='GET') or {}
mid = next((k for k, v in m_list.items() if v.get('title') == target), None)

if mid:
send_rew_request(f"/measurements/{mid}/command", {"command": "Set color", "parameters": [["color", t_col]]})
send_rew_request(f"/measurements/{mid}/command", {"command": "Minimum phase version", "parameters": [["append lf tail", "false"], ["append hf tail", "false"]]})
print(f" [√] {target} Generation Complete.")
send_rew_request(f"/measurements/{cid}", method='DELETE')
else:
print(f" [!] Error: REW did not name the copy '{cpy}'")

if __name__ == "__main__":
print("--- Macro 1 v10.11 (API Syntax Fix) ---")
run_channel("L")
run_channel("R")
 
Last edited:
Back
Top