Created
June 3, 2026 20:52
-
-
Save ology/481c656ee7f8bca1e18a1663fcbd5444 to your computer and use it in GitHub Desktop.
Adding a volume_scale setting. Untested!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import binascii | |
| import random | |
| def make_config(args): | |
| config = { | |
| "glitch_prob": 5, | |
| "hex_min": 0, | |
| "hex_max": 16, | |
| "frame_min": 0, | |
| "frame_max": 1, | |
| "frame_spacing_min": 1, | |
| "frame_spacing_max": 1, | |
| "glitch_width": 8, | |
| "max_glitches_per_frame": 0, | |
| "glitch_volume_scale": 0.5, # Volume multiplier when glitch occurs (0.0 - 1.0) | |
| } | |
| # TODO: | |
| # for key in config: | |
| # if key in <config file heading>: | |
| # argument variables | |
| if args.prob: | |
| config["glitch_prob"] = args.prob | |
| if args.hexmin: | |
| config["hex_min"] = args.hexmin | |
| if args.hexmax: | |
| config["hex_max"] = args.hexmax | |
| if args.framemin: | |
| config["frame_min"] = args.framemin | |
| if args.framemax: | |
| config["frame_max"] = args.framemax | |
| if args.spacingmin: | |
| config["frame_spacing_min"] = args.spacingmin | |
| if args.spacingmax: | |
| config["frame_spacing_max"] = args.spacingmax | |
| if args.width: | |
| config["glitch_width"] = args.width | |
| if args.limit: | |
| config["max_glitches_per_frame"] = args.limit | |
| if hasattr(args, "volume_scale") and args.volume_scale is not None: | |
| config["glitch_volume_scale"] = args.volume_scale | |
| return config | |
| def read_file(input_path): | |
| with open(input_path, "rb") as input_file: | |
| hexdata = input_file.read().hex() | |
| header_start_indices = [] | |
| header_start_index = 0 | |
| while hexdata.find("fff", header_start_index) >= 0: | |
| header_start_index = hexdata.find("fff", header_start_index) | |
| if header_start_index >= 0: | |
| header_start_indices.append(header_start_index) | |
| header_start_index += 8 | |
| frames = [ | |
| hexdata[header_start_indices[i] : header_start_indices[i + 1]] | |
| for i in range(len(header_start_indices) - 1) | |
| ] | |
| return frames | |
| def attenuate_frame(frame_digits, volume_scale): | |
| """ | |
| Lower the volume of a frame by scaling each byte's value. | |
| Skips the first 8 hex digits (4 bytes) to preserve the MP3 frame header. | |
| """ | |
| attenuated = list(frame_digits) | |
| # Process pairs of hex digits (bytes), skipping the 4-byte header (8 hex digits) | |
| for i in range(8, len(attenuated) - 1, 2): | |
| try: | |
| byte_val = int(attenuated[i] + attenuated[i + 1], 16) | |
| scaled = int(byte_val * volume_scale) & 0xFF | |
| hex_scaled = format(scaled, "02x") | |
| attenuated[i] = hex_scaled[0] | |
| attenuated[i + 1] = hex_scaled[1] | |
| except ValueError: | |
| pass # Skip malformed hex pairs | |
| return attenuated | |
| def apply_glitches(frames, config): | |
| hex_digits = "0123456789abcdef" | |
| output_hex = [] | |
| num_glitches_this_frame = 0 | |
| testval = 0 | |
| frame_counter = 0 | |
| frame_spacing = 1 | |
| for idx_frame, frame in enumerate(frames): | |
| num_glitches_this_frame = 0 | |
| frame_digits = list(frame) | |
| frame_was_glitched = False | |
| for idx_digit, digit in enumerate(frame_digits): | |
| if idx_frame > 0: | |
| if idx_digit % config["glitch_width"] == 0: | |
| testval = random.uniform(0, 100) | |
| if testval < config["glitch_prob"]: | |
| num_glitches_this_frame += 1 | |
| if ( | |
| testval < config["glitch_prob"] | |
| and ( | |
| True, | |
| num_glitches_this_frame <= config["max_glitches_per_frame"], | |
| )[config["max_glitches_per_frame"] > 0] | |
| and idx_digit >= (len(frame) * config["frame_min"]) | |
| and idx_digit <= (len(frame) * config["frame_max"]) | |
| and idx_digit >= 8 | |
| and frame_counter == 0 | |
| ): | |
| frame_digits[idx_digit] = random.choice( | |
| hex_digits[config["hex_min"] : config["hex_max"] + 1] | |
| ) | |
| frame_was_glitched = True | |
| # If a glitch occurred in this frame, attenuate the audio data | |
| if frame_was_glitched: | |
| frame_digits = attenuate_frame( | |
| frame_digits, config["glitch_volume_scale"] | |
| ) | |
| output_hex.extend(frame_digits) | |
| if frame_counter == 0: | |
| frame_spacing = random.randrange( | |
| config["frame_spacing_min"], config["frame_spacing_max"] + 1 | |
| ) | |
| frame_counter += 1 | |
| frame_counter %= frame_spacing | |
| return output_hex | |
| def write_file(output_hex, output_path): | |
| rejoined_frames = "".join(output_hex) | |
| if len(rejoined_frames) % 2 != 0: | |
| rejoined_frames = rejoined_frames + "0" | |
| with open(output_path, "wb") as output_file: | |
| output_file.write(binascii.unhexlify(rejoined_frames)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment