22 Oct 2024 by Frank Faruk Ceviz
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.
The Decent Sampler Preset Tuner is a utility script that allows you to:
Open a command prompt or terminal window, navigate to the directory containing the script, and run:
bash
Copy code
python decent_sampler_preset_tuner.py
Note for Windows Users: You can drag and drop the .dspreset file onto the script file to launch it with the file pre-selected.
Prompt:
python
Copy code
Enter the music notes and tuning adjustments in the format 'Note=TuningValue', separated by commas.
For example: G#=-0.51, A#=-0.25, C#=0.1
Your input:
Example:
shell
Copy code
G#=-0.49, A=-0.11, C#=0.05
Confirmation message:
vbnet
Copy code
Tuning updated for notes: G#, A, C#
bgImage updated to: new_background.png
Updated file saved as: /path/to/your/my_instrument_updated.dspreset
Input:
arduino
Copy code
Enter the new image file name for bgImage (enter 0 to leave unchanged): 0
less
Copy code
Your input: G#=-0.49, A=-0.11
Input:
arduino
Copy code
Enter the new image file name for bgImage (enter 0 to leave unchanged): new_bg_image
mathematica
Copy code
Your input: C#=0.1, D#=-0.2
Example:
python
Copy code
Invalid format for note 'G# -0.49'. Expected format is 'Note=TuningValue'.
If you cancel the file selection dialog, the script will exit with a message:
yaml
Copy code
No file selected. Exiting.
This script is provided "as is" without warranty of any kind. Use it at your own risk. Feel free to modify and adapt it to suit your needs.
Contributions are welcome! If you have suggestions for improvements or encounter any issues, please feel free to reach out.
Thank you for using the Decent Sampler Preset Tuner! If you have any questions or need further assistance, feel free to reach out.
Copy and Paste the full code below
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'(<sample[^>]+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()