-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathDjzDatabendingV1.py
189 lines (164 loc) · 7.62 KB
/
DjzDatabendingV1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import numpy as np
import torch
import cv2
from PIL import Image
import io
import scipy.signal as signal
import tempfile
import os
class DjzDatabendingV1:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"images": ("IMAGE",), # Batch of images input
"effect_type": (["echo", "reverb", "distortion", "bitcrush", "tremolo", "phaser", "chorus"],),
"echo_delay": ("FLOAT", {
"default": 0.3,
"min": 0.1,
"max": 1.0,
"step": 0.1,
}),
"echo_decay": ("FLOAT", {
"default": 0.1,
"min": 0.0,
"max": 0.9,
"step": 0.1,
}),
"distortion_intensity": ("FLOAT", {
"default": 0.5,
"min": 0.1,
"max": 1.0,
"step": 0.1,
}),
"modulation_rate": ("FLOAT", {
"default": 1.0,
"min": 0.1,
"max": 10.0,
"step": 0.1,
}),
"modulation_depth": ("FLOAT", {
"default": 0.5,
"min": 0.1,
"max": 2.0,
"step": 0.1,
}),
},
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "apply_databending"
CATEGORY = "image/effects"
def apply_echo(self, audio_data, delay, decay, sample_rate=44100):
"""Apply echo effect to audio data"""
print(f"Applying echo effect (delay: {delay}, decay: {decay})")
delay_samples = int(delay * sample_rate)
echo_filter = np.zeros(delay_samples + 1)
echo_filter[0] = 1
echo_filter[-1] = decay
return signal.convolve(audio_data, echo_filter, mode='same')
def apply_reverb(self, audio_data, depth, decay, sample_rate=44100):
"""Apply reverb effect to audio data"""
print(f"Applying reverb effect (depth: {depth}, decay: {decay})")
num_reflections = int(depth * sample_rate)
decay_curve = np.exp(-decay * np.arange(num_reflections))
impulse = np.random.rand(num_reflections) * decay_curve
return signal.convolve(audio_data, impulse, mode='same')
def apply_distortion(self, audio_data, intensity):
"""Apply distortion effect to audio data"""
print(f"Applying distortion effect (intensity: {intensity})")
return np.clip(audio_data * (1 + intensity), -1, 1)
def apply_bitcrush(self, audio_data, depth):
"""Apply bit crushing effect to audio data"""
print(f"Applying bitcrush effect (depth: {depth})")
bits = int(16 * (1 - depth)) # Convert depth to bits (1-16)
steps = 2**bits
return np.round(audio_data * steps) / steps
def apply_tremolo(self, audio_data, rate, depth, sample_rate=44100):
"""Apply tremolo effect to audio data"""
print(f"Applying tremolo effect (rate: {rate}, depth: {depth})")
t = np.arange(len(audio_data)) / sample_rate
mod = depth * np.sin(2 * np.pi * rate * t) + (1 - depth)
return audio_data * mod
def apply_phaser(self, audio_data, rate, depth, sample_rate=44100):
"""Apply phaser effect to audio data"""
print(f"Applying phaser effect (rate: {rate}, depth: {depth})")
t = np.arange(len(audio_data)) / sample_rate
lfo = (np.sin(2 * np.pi * rate * t) + 1) * depth
allpass = np.exp(-2j * np.pi * lfo / sample_rate)
return np.real(audio_data * allpass)
def apply_chorus(self, audio_data, rate, depth, sample_rate=44100):
"""Apply chorus effect to audio data"""
print(f"Applying chorus effect (rate: {rate}, depth: {depth})")
t = np.arange(len(audio_data)) / sample_rate
mod = depth * np.sin(2 * np.pi * rate * t)
indices = np.arange(len(audio_data)) + (mod * sample_rate).astype(int)
indices = np.clip(indices, 0, len(audio_data) - 1)
return 0.5 * (audio_data + audio_data[indices])
def process_single_image(self, image, effect_type, params):
"""Process a single image with databending effects"""
print(f"Processing image with {effect_type} effect...")
# Create temporary BMP file
with tempfile.NamedTemporaryFile(suffix='.bmp', delete=False) as tmp_bmp:
bmp_path = tmp_bmp.name
Image.fromarray((image * 255).astype(np.uint8)).save(bmp_path, 'BMP')
print("Converting to raw audio data...")
# Read BMP header
with open(bmp_path, 'rb') as f:
header = f.read(54) # BMP header size
audio_data = np.frombuffer(f.read(), dtype=np.uint8).astype(np.float32) / 255.0
print("Applying audio effect...")
# Apply selected effect
if effect_type == "echo":
processed_audio = self.apply_echo(audio_data, params['delay'], params['decay'])
elif effect_type == "reverb":
processed_audio = self.apply_reverb(audio_data, params['depth'], params['decay'])
elif effect_type == "distortion":
processed_audio = self.apply_distortion(audio_data, params['intensity'])
elif effect_type == "bitcrush":
processed_audio = self.apply_bitcrush(audio_data, params['depth'])
elif effect_type == "tremolo":
processed_audio = self.apply_tremolo(audio_data, params['rate'], params['depth'])
elif effect_type == "phaser":
processed_audio = self.apply_phaser(audio_data, params['rate'], params['depth'])
elif effect_type == "chorus":
processed_audio = self.apply_chorus(audio_data, params['rate'], params['depth'])
print("Converting back to image...")
# Convert back to image data
processed_data = (processed_audio * 255).astype(np.uint8)
# Create new image with original header
with tempfile.NamedTemporaryFile(suffix='.bmp', delete=False) as tmp_out:
tmp_out.write(header)
tmp_out.write(processed_data.tobytes())
# Read processed image
processed_image = np.array(Image.open(tmp_out.name)).astype(np.float32) / 255.0
# Cleanup temporary files
os.unlink(bmp_path)
os.unlink(tmp_out.name)
return processed_image
def apply_databending(self, images, effect_type, echo_delay, echo_decay, distortion_intensity, modulation_rate, modulation_depth):
"""Process batch of images with databending effects"""
print(f"\nStarting databending process with {effect_type} effect...")
# Convert from torch tensor to numpy array
batch_numpy = images.cpu().numpy()
batch_size = batch_numpy.shape[0]
# Prepare parameters
params = {
'delay': echo_delay,
'decay': echo_decay,
'intensity': distortion_intensity,
'rate': modulation_rate,
'depth': modulation_depth
}
# Process each image in the batch
processed_batch = np.zeros_like(batch_numpy)
for i in range(batch_size):
print(f"\nProcessing image {i+1}/{batch_size}")
processed_batch[i] = self.process_single_image(batch_numpy[i], effect_type, params)
print("\nDatabending process complete!")
return (torch.from_numpy(processed_batch).to(images.device),)
NODE_CLASS_MAPPINGS = {
"DjzDatabendingV1": DjzDatabendingV1
}
NODE_DISPLAY_NAME_MAPPINGS = {
"DjzDatabendingV1": "Databending Effect v1"
}