waveform_preview.gd 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. extends Control
  2. var left_channel: PackedFloat32Array = PackedFloat32Array()
  3. var right_channel: PackedFloat32Array = PackedFloat32Array()
  4. var samples_per_pixel: int = 10 # Number of samples to average per pixel for a more detailed waveform
  5. # Function to set the audio stream
  6. func set_audio_stream(stream: AudioStream) -> void:
  7. if stream is AudioStreamWAV:
  8. var byte_data: PackedByteArray = stream.data
  9. var is_stereo: bool = stream.stereo
  10. var bit_depth: int = stream.format # 0 = 8-bit, 1 = 16-bit
  11. # Assuming the plugin outputs 16-bit audio (for this case)
  12. if bit_depth == 1:
  13. var total_samples: int = byte_data.size() / 2 # 2 bytes per 16-bit sample
  14. var raw_samples: PackedFloat32Array = PackedFloat32Array()
  15. raw_samples.resize(total_samples)
  16. # Manually process 16-bit PCM data (little endian assumption)
  17. for i in range(total_samples):
  18. var low = byte_data[i * 2]
  19. var high = byte_data[i * 2 + 1]
  20. var sample: int = (high << 8) | low # Combine bytes to form a 16-bit sample
  21. raw_samples[i] = float(sample) / 32768.0 # Normalize to -1.0..1.0
  22. if is_stereo:
  23. left_channel.resize(total_samples / 2)
  24. right_channel.resize(total_samples / 2)
  25. for i in range(0, total_samples, 2):
  26. left_channel[i / 2] = raw_samples[i]
  27. right_channel[i / 2] = raw_samples[i + 1]
  28. else:
  29. left_channel = raw_samples
  30. right_channel = raw_samples
  31. queue_redraw() # Trigger the redrawing of the waveform
  32. else:
  33. push_error("Unsupported bit depth. Only 16-bit PCM WAV files are supported.")
  34. else:
  35. push_error("Only AudioStreamWAV is supported for waveform preview.")
  36. # Function to draw the waveform
  37. func _draw() -> void:
  38. if left_channel.is_empty():
  39. return
  40. var width: int = int(size.x)
  41. var height: float = size.y
  42. var center_y: float = height / 2.0
  43. var half_height: float = height / 2.0
  44. var total_samples: int = left_channel.size()
  45. # Calculate samples per pixel
  46. samples_per_pixel = max(1, total_samples / width) # Ensure at least 1 sample per pixel
  47. var left_points: PackedVector2Array = PackedVector2Array()
  48. var right_points: PackedVector2Array = PackedVector2Array()
  49. # Loop through each pixel (width)
  50. for x in range(width):
  51. var i: int = x * samples_per_pixel
  52. if i >= total_samples:
  53. break
  54. # Average the samples within the window defined by samples_per_pixel for each pixel
  55. var left_sample_avg: float = 0.0
  56. var right_sample_avg: float = 0.0
  57. var num_samples: int = samples_per_pixel
  58. # Sum samples over the window and calculate average
  59. for j in range(i, min(i + samples_per_pixel, total_samples)):
  60. left_sample_avg += left_channel[j]
  61. right_sample_avg += right_channel[j]
  62. left_sample_avg /= num_samples
  63. right_sample_avg /= num_samples
  64. # Clamp values to -1.0..1.0
  65. left_sample_avg = clamp(left_sample_avg, -1.0, 1.0)
  66. right_sample_avg = clamp(right_sample_avg, -1.0, 1.0)
  67. # Create points for drawing
  68. left_points.append(Vector2(x, center_y - left_sample_avg * half_height))
  69. right_points.append(Vector2(x, center_y - right_sample_avg * half_height))
  70. # Draw the waveform for the left channel
  71. draw_polyline(left_points, Color.CYAN, 1.5)
  72. # Draw the waveform for the right channel (stereo support)
  73. if right_channel.size() > 0:
  74. draw_polyline(right_points, Color.MAGENTA, 1.5)