The Decent Sampler Preset Tuner is a Python script designed to adjust the tuning for specified musical notes within a Decent Sampler .dspreset file. It allows users to apply individual tuning adjustments to multiple notes, update the background image, and provides flexible file handling through drag-and-drop support or a file selection dialog. The script ensures the original image format is preserved unless a different extension is specified.
To begin, copy the Python code below. Then, open your chosen code editor (e.g., Sublime Text, Visual Studio Code) and paste the code into a new file. Save the file with a .py extension.
import xml.etree.ElementTree as ET
import sys
import os
import re
import tkinter as tk
from tkinter import filedialog
def select_file():
# Check if a file path is provided via command-line arguments (for drag-and-drop)
if len(sys.argv) > 1:
file_path = sys.argv[1]
else:
# Create a file dialog for the user to select the file
root = tk.Tk()
root.withdraw() # Hide the main window
file_path = filedialog.askopenfilename(
title="Select Decent Sampler .dspreset file",
filetypes=[("Decent Sampler Preset", "*.dspreset"), ("XML Files", "*.xml"), ("All Files", "*.*")]
)
return file_path
def update_tuning(input_text, tuning_dict):
for note, tuning_value in tuning_dict.items():
# Escape any special regex characters in the note
note_escaped = re.escape(note)
# Build the note pattern using underscores to delimit the note
pattern = rf'(]+name="[^"]*?_{note_escaped}(\d+)?_.*?"[^>]*?)(\s*/?>)'
# Function to add or update tuning
def add_tuning(match):
tag_content = match.group(1)
closing = match.group(3)
if 'tuning="' not in tag_content:
# Insert tuning attribute before the closing tag
return f'{tag_content} tuning="{tuning_value}"{closing}'
else:
# Update existing tuning value
updated_tag = re.sub(r'tuning="[^"]*"', f'tuning="{tuning_value}"', match.group(0))
return updated_tag
# Update the input text for the current note
input_text = re.sub(pattern, add_tuning, input_text)
return input_text
def update_bgImage(input_text, new_image_name):
# Regular expression to find bgImage="Images/..." attribute
pattern = r'(bgImage="Images/)([^"]*)(")'
match = re.search(pattern, input_text)
if match:
original_image_name = match.group(2)
original_extension = os.path.splitext(original_image_name)[1] # Includes the dot, e.g., '.png'
else:
original_extension = '.png' # Default to .png if not found
if new_image_name != '0':
# If the user did not specify an extension, use the original extension
if not os.path.splitext(new_image_name)[1]:
new_image_name += original_extension
# Function to perform replacement
def replace_bg_image(match):
return f'{match.group(1)}{new_image_name}{match.group(3)}'
# Replace the bgImage attribute value with the new image name
updated_text = re.sub(pattern, replace_bg_image, input_text)
else:
# Do not change the input text
updated_text = input_text
return updated_text
def main():
# Select the file
file_path = select_file()
if not file_path:
print("No file selected. Exiting.")
sys.exit(1)
# Ask for the new image file name
new_image_name = input("Enter the new image file name for bgImage (enter 0 to leave unchanged): ").strip()
# Ask for the music notes and their tuning adjustments
print("Enter the music notes and tuning adjustments in the format 'Note=TuningValue', separated by commas.")
print("For example: G#=-0.51, A#=-0.25, C#=0.1")
notes_input = input("Your input: ")
# Parse the input into a dictionary
tuning_dict = {}
notes_list = [note.strip() for note in notes_input.split(',') if note.strip()]
for note_pair in notes_list:
if '=' in note_pair:
note, tuning = note_pair.split('=')
note = note.strip()
tuning = tuning.strip()
tuning_dict[note] = tuning
else:
print(f"Invalid format for note '{note_pair}'. Expected format is 'Note=TuningValue'.")
sys.exit(1)
try:
# Read the content of the file
with open(file_path, "r", encoding='utf-8') as file:
content = file.read()
# Update the content
content = update_tuning(content, tuning_dict)
content = update_bgImage(content, new_image_name)
# Save the updated content back to a new file
file_dir, file_name = os.path.split(file_path)
file_base, file_ext = os.path.splitext(file_name)
updated_file_name = f"{file_base}_updated{file_ext}"
updated_file_path = os.path.join(file_dir, updated_file_name)
with open(updated_file_path, "w", encoding='utf-8') as file:
file.write(content)
print(f"\nTuning updated for notes: {', '.join(tuning_dict.keys())}")
if new_image_name != '0':
print(f"bgImage updated to: {new_image_name}")
else:
print("bgImage unchanged.")
print(f"Updated file saved as: {updated_file_path}")
except FileNotFoundError:
print("File not found. Please check the file path and try again.")
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == '__main__':
main()