# ------------------------------------------------------------------ # AGENTE 5: MULTI-PARAMETER AUTOMATION HANDLER # ------------------------------------------------------------------ def _cmd_add_parameter_automation(self, track_index, parameter_name, points, device_name="", clip_index=None, send_index=None, **kw): """Add automation envelope to track parameters (volume, pan, device params, sends). Agente 5: Exposes multi-parameter automation via LiveBridge or direct API. Supports track-level automation (volume, pan, sends) and clip/device automation. Args: track_index: Index of the target track parameter_name: Name of parameter to automate ("volume", "pan", "send", device param name) points: List of [time, value] pairs where time is in beats and value is parameter-specific device_name: Name of device (only for device_param automation, e.g., "EQ Eight") clip_index: Clip index (only for clip-level automation) send_index: Send index (only for send automation, 0-based) Returns: Dict with automation creation status. """ try: idx = int(track_index) if idx < 0 or idx >= len(self._song.tracks): return {"error": "Track index %d out of range" % idx} track = self._song.tracks[idx] param_name = str(parameter_name).lower() points_count = len(points) if isinstance(points, (list, tuple)) else 0 # Track-level automation: volume if param_name == "volume": if hasattr(track, 'mixer_device') and hasattr(track.mixer_device, 'volume'): vol_param = track.mixer_device.volume for point in points[:64]: # Limit to 64 points try: time_val = float(point[0]) if len(point) > 0 else 0.0 value_val = float(point[1]) if len(point) > 1 else 0.85 # Clamp to valid range value_val = max(0.0, min(1.0, value_val)) vol_param.value = value_val except Exception as pe: self.log_message("Volume automation point error: %s" % str(pe)) return { "automation_added": True, "track_index": idx, "parameter": "volume", "points_processed": points_count, "final_value": float(vol_param.value) } return {"error": "Track %d does not have volume control" % idx} # Track-level automation: pan elif param_name == "pan": if hasattr(track, 'mixer_device') and hasattr(track.mixer_device, 'panning'): pan_param = track.mixer_device.panning for point in points[:64]: try: time_val = float(point[0]) if len(point) > 0 else 0.0 value_val = float(point[1]) if len(point) > 1 else 0.0 # Clamp to valid range (-1.0 to 1.0) value_val = max(-1.0, min(1.0, value_val)) pan_param.value = value_val except Exception as pe: self.log_message("Pan automation point error: %s" % str(pe)) return { "automation_added": True, "track_index": idx, "parameter": "pan", "points_processed": points_count, "final_value": float(pan_param.value) } return {"error": "Track %d does not have pan control" % idx} # Send automation elif param_name == "send": send_idx = int(send_index) if send_index is not None else 0 if hasattr(track, 'mixer_device') and hasattr(track.mixer_device, 'sends'): sends = track.mixer_device.sends if send_idx < len(sends): send_param = sends[send_idx] for point in points[:64]: try: time_val = float(point[0]) if len(point) > 0 else 0.0 value_val = float(point[1]) if len(point) > 1 else 0.0 value_val = max(0.0, min(1.0, value_val)) send_param.value = value_val except Exception as pe: self.log_message("Send automation point error: %s" % str(pe)) return { "automation_added": True, "track_index": idx, "parameter": "send", "send_index": send_idx, "points_processed": points_count, "final_value": float(send_param.value) } return {"error": "Send index %d out of range (track has %d sends)" % (send_idx, len(sends))} return {"error": "Track %d does not have sends" % idx} # Device parameter automation elif device_name: # Find device by name target_device = None if hasattr(track, 'devices'): for device in track.devices: if str(device_name).lower() in str(device.name).lower(): target_device = device break if target_device is None: return {"error": "Device '%s' not found on track %d" % (device_name, idx)} # Find parameter by name if hasattr(target_device, 'parameters'): target_param = None for param in target_device.parameters: if param_name in str(param.name).lower(): target_param = param break if target_param is None: return {"error": "Parameter '%s' not found on device '%s'" % (parameter_name, device_name)} # Apply automation points configured = 0 for point in points[:64]: try: time_val = float(point[0]) if len(point) > 0 else 0.0 value_val = float(point[1]) if len(point) > 1 else 0.5 # Get parameter range min_val = getattr(target_param, 'min', 0.0) max_val = getattr(target_param, 'max', 1.0) # Clamp to range value_val = max(min_val, min(max_val, value_val)) target_param.value = value_val configured += 1 except Exception as pe: self.log_message("Device param automation error: %s" % str(pe)) return { "automation_added": True, "track_index": idx, "device_name": device_name, "parameter": parameter_name, "points_processed": configured, "final_value": float(target_param.value) } return {"error": "Device '%s' has no parameters" % device_name} # Try LiveBridge add_automation if available elif self.live_bridge and hasattr(self.live_bridge, 'add_automation'): try: clip_idx = int(clip_index) if clip_index is not None else 0 # Convert points to tuples for LiveBridge tuple_points = [(float(p[0]), float(p[1])) for p in points if len(p) >= 2] result = self.live_bridge.add_automation(idx, clip_idx, parameter_name, tuple_points) return { "automation_added": result.get("success", False), "track_index": idx, "clip_index": clip_idx, "parameter": parameter_name, "live_bridge_result": result } except Exception as lb_err: return {"error": "LiveBridge automation failed: %s" % str(lb_err)} else: return { "error": "Unknown parameter type '%s'. Supported: volume, pan, send, or device_param with device_name" % parameter_name, "track_index": idx } except Exception as e: self.log_message("Agente 5 automation error: %s" % str(e)) return {"automation_added": False, "error": str(e)}