s&box Package Code Search
Search C# source code, UI razor templates, shaders, and configs across s&box packages.
link Raw Facepunch API Link: https://public.facepunch.com/sbox/code/search/1/?ident=attackhelicopter.aitools&take=20
Showing code results for query:
*
(4 total matches found)
Editor
library
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.IO;
using Editor;
using Sandbox;
using System.Text;
class SpectogramWidget : Widget
{
private short[] samples;
private int sampleRate;
private List<int> splitPoints = new List<int>();
private int? dragPoint = null;
private Label loadingLabel;
private Label dropLabel;
private bool isLoading = true;
public SoundFile CurrentSound { get; private set; }
public SpectogramWidget(SoundFile soundFile) : base(null)
{
MinimumSize = 100;
MouseTracking = true;
AcceptDrops = true;
loadingLabel = new Label(this);
loadingLabel.Text = "Loading audio data...";
loadingLabel.Visible = false;
dropLabel = new Label(this);
dropLabel.Text = "Drop a sound file here";
dropLabel.SetStyles("font-size: 18px; color: #aaa; text-align: center;");
if (soundFile != null)
{
LoadSound(soundFile);
}
}
public async void LoadSound(SoundFile soundFile)
{
CurrentSound = soundFile;
isLoading = true;
samples = null;
splitPoints.Clear();
loadingLabel.Visible = true;
dropLabel.Visible = false;
await LoadAudioDataAsync(soundFile);
}
private async Task LoadAudioDataAsync(SoundFile soundFile)
{
try
{
await soundFile.LoadAsync();
samples = await soundFile.GetSamplesAsync();
if (samples == null)
{
loadingLabel.Text = "Failed to load audio data";
return;
}
sampleRate = soundFile.Rate;
splitPoints.Add(0);
splitPoints.Add(samples.Length - 1);
loadingLabel.Visible = false;
isLoading = false;
Update();
}
catch (Exception ex)
{
loadingLabel.Text = $"Error loading audio: {ex.Message}";
}
}
protected override void DoLayout()
{
base.DoLayout();
if (loadingLabel != null)
{
loadingLabel.Position = new Vector2(10, Height / 2 - 10);
loadingLabel.Size = new Vector2(Width - 20, 20);
}
if (dropLabel != null)
{
dropLabel.Position = new Vector2(10, Height / 2 - 10);
dropLabel.Size = new Vector2(Width - 20, 20);
}
}
public override void OnDragDrop(DragEvent e)
{
base.OnDragDrop(e);
if (!e.Data.HasFileOrFolder) return;
var asset = AssetSystem.FindByPath(e.Data.FileOrFolder);
if (asset?.AssetType != AssetType.SoundFile) return;
var soundFile = SoundFile.Load(asset.Path);
if (soundFile != null)
{
LoadSound(soundFile);
}
}
public override void OnDragHover(DragEvent e)
{
base.OnDragHover(e);
if (!e.Data.HasFileOrFolder) return;
var asset = AssetSystem.FindByPath(e.Data.FileOrFolder);
if (asset?.AssetType != AssetType.SoundFile) return;
e.Action = DropAction.Link;
}
protected override void OnMouseClick(MouseEvent e)
{
if (isLoading) return;
base.OnMouseClick(e);
if (e.Button == MouseButtons.Left)
{
var samplePos = (int)(e.LocalPosition.x / Width * samples.Length);
var nearPoint = splitPoints.FirstOrDefault(p => Math.Abs(p - samplePos) < (samples.Length / Width * 5));
if (nearPoint != default)
{
dragPoint = splitPoints.IndexOf(nearPoint);
}
else
{
splitPoints.Add(samplePos);
splitPoints.Sort();
Update();
}
}
}
protected override void OnMouseMove(MouseEvent e)
{
if (isLoading) return;
base.OnMouseMove(e);
if (dragPoint.HasValue)
{
var samplePos = (int)(e.LocalPosition.x / Width * samples.Length);
splitPoints[dragPoint.Value] = samplePos;
splitPoints.Sort();
Update();
}
}
protected override void OnMouseReleased(MouseEvent e)
{
if (isLoading) return;
base.OnMouseReleased(e);
dragPoint = null;
}
protected override void OnPaint()
{
base.OnPaint();
if (isLoading || samples == null)
{
return;
}
Paint.ClearPen();
Paint.SetBrush(Theme.Grey.WithAlpha(0.1f));
Paint.DrawRect(LocalRect);
Paint.SetPen(Theme.Blue);
var samplesPerPixel = samples.Length / Width;
for (int x = 0; x < Width; x++)
{
var startSample = (int)(x * samplesPerPixel);
var endSample = Math.Min(startSample + samplesPerPixel, samples.Length);
var max = short.MinValue;
var min = short.MaxValue;
for (int i = startSample; i < endSample; i++)
{
max = Math.Max(max, samples[i]);
min = Math.Min(min, samples[i]);
}
var y1 = Height / 2 + (min / (float)short.MaxValue * Height / 2);
var y2 = Height / 2 + (max / (float)short.MaxValue * Height / 2);
Paint.DrawLine(new Vector2(x, y1), new Vector2(x, y2));
}
Paint.SetPen(Theme.Red);
foreach (var point in splitPoints)
{
var x = point / (float)samples.Length * Width;
Paint.DrawLine(new Vector2(x, 0), new Vector2(x, Height));
}
}
public List<int> GetSplitPoints()
{
return new List<int>(splitPoints);
}
public void SplitCurrentSound(Action<SoundFile> onSoundCreated)
{
if (CurrentSound == null || samples == null) return;
var splitPoints = GetSplitPoints();
if (splitPoints.Count < 2) return;
try
{
var baseFileName = Path.GetFileNameWithoutExtension(CurrentSound.ResourcePath);
var outputDir = Path.Combine(
Project.Current.GetAssetsPath(),
"generated",
$"{baseFileName}_splits"
);
Directory.CreateDirectory(outputDir);
for (int i = 0; i < splitPoints.Count - 1; i++)
{
var start = splitPoints[i];
var end = splitPoints[i + 1];
var length = end - start;
var segmentSamples = new short[length];
Array.Copy(samples, start, segmentSamples, 0, length);
var wavPath = Path.Combine(outputDir, $"{baseFileName}_part_{i + 1}.wav");
using (var writer = new BinaryWriter(File.Create(wavPath)))
{
writer.Write(Encoding.ASCII.GetBytes("RIFF"));
writer.Write(36 + (segmentSamples.Length * 2));
writer.Write(Encoding.ASCII.GetBytes("WAVE"));
writer.Write(Encoding.ASCII.GetBytes("fmt "));
writer.Write(16);
writer.Write((short)1);
writer.Write((short)CurrentSound.Channels);
writer.Write(CurrentSound.Rate);
writer.Write(CurrentSound.Rate * CurrentSound.Channels * 2);
writer.Write((short)(CurrentSound.Channels * 2));
writer.Write((short)16);
writer.Write(Encoding.ASCII.GetBytes("data"));
writer.Write(segmentSamples.Length * 2);
foreach (var sample in segmentSamples)
{
writer.Write(sample);
}
}
var asset = AssetSystem.RegisterFile(wavPath);
if (asset != null)
{
var soundFile = SoundFile.Load(asset.RelativePath);
if (soundFile != null)
{
onSoundCreated?.Invoke(soundFile);
}
}
}
}
catch (Exception ex)
{
Log.Error($"Error splitting sound: {ex.Message}");
}
}
}
Editor
library
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Reflection;
using Sandbox;
using System.Collections.Generic;
using System.Linq;
namespace Editor;
public static class SoundAddons
{
private static string previousSoundGenerationPromp;
private static string previousSoundGenerationDuration;
// [ContextMenuFor( typeof( SoundFile ), "Generate sound", "create" )]
public static void Generate( SoundEvent soundEvent, Action<SoundFile> finished )
{
string defaultInput = !string.IsNullOrEmpty( previousSoundGenerationPromp )
? previousSoundGenerationPromp
: "A dog barking";
Dialog.AskString( ( description ) =>
{
previousSoundGenerationPromp = description;
Dialog.AskString( async ( durationStr ) =>
{
previousSoundGenerationDuration = durationStr;
if ( !float.TryParse( durationStr, out float duration ) || duration < 0.5f || duration > 22f )
{
Log.Error( "Duration must be between 0.5 and 22 seconds" );
return;
}
try
{
string apiKey = SoundSettings.Settings.ElevenLabsApiKey;
var client = new HttpClient();
client.DefaultRequestHeaders.Add( "xi-api-key", apiKey );
var content = new StringContent( JsonSerializer.Serialize( new
{
text = description,
duration_seconds = duration,
prompt_influence = 0.3
} ), Encoding.UTF8, "application/json" );
var response = await client.PostAsync(
"https://api.elevenlabs.io/v1/sound-generation",
content
);
if ( response.IsSuccessStatusCode )
{
var bytes = await response.Content.ReadAsByteArrayAsync();
string safeFileName = description.Replace( " ", "_" ).Replace( "/", "_" ).Replace( "\\", "_" );
var mp3Path = Path.Combine(
SoundSettings.Settings.GenerationPath,
$"{safeFileName}_{DateTime.Now:yyyyMMddHHmmss}.mp3"
);
var fullMp3Path = Path.Combine( Project.Current.GetAssetsPath(), mp3Path );
Directory.CreateDirectory( Path.GetDirectoryName( fullMp3Path ) );
await File.WriteAllBytesAsync( fullMp3Path, bytes );
Log.Info( "File saved to: " + fullMp3Path );
var mp3Asset = AssetSystem.RegisterFile( fullMp3Path );
if ( mp3Asset != null )
{
var soundFile = SoundFile.Load( mp3Asset.RelativePath );
if ( soundFile != null )
{
finished(soundFile);
Log.Info( $"Successfully generated and linked sound: {mp3Asset.RelativePath}" );
}
else
{
Log.Error( "Failed to load generated sound file" );
}
}
else
{
Log.Error( "Failed to register generated mp3 file as asset" );
}
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
Log.Error( $"Failed to generate sound: {response.StatusCode}. Error: {errorContent}" );
}
}
catch ( Exception ex )
{
Log.Error( $"Error generating sound: {ex.Message}" );
}
},
"Enter duration in seconds (0.5 to 22):",
"Generate",
"Cancel",
previousSoundGenerationDuration,
"Set Sound Duration" );
},
"Describe the sound effect to generate:",
"Next",
"Cancel",
defaultInput,
"Generate Sound Effect" );
}
// [ContextMenuFor( typeof( SoundFile ), "Split sound", "content_cut" )]
public static async void SplitSound( Widget parent, SerializedProperty property )
{
var soundResource = property.GetValue<SoundFile>();
if ( soundResource == null || !soundResource.IsValid )
{
Log.Error( "No valid sound file selected" );
return;
}
var dialog = new Dialog();
dialog.Window.Title = "Split Sound";
dialog.Window.Size = new Vector2( 800, 400 );
dialog.Layout = Layout.Column();
var mainLayout = dialog.Layout.AddColumn();
mainLayout.Margin = 16f;
var loadingLabel = new Label( "Loading audio data..." );
mainLayout.Add( loadingLabel );
dialog.Show();
var samples = await soundResource.GetSamplesAsync();
if ( samples == null )
{
loadingLabel.Text = "Failed to load audio samples";
return;
}
loadingLabel.Destroy();
var spectogramWidget = new SpectogramWidget( soundResource );
mainLayout.Add( spectogramWidget, 1 );
var controlsLayout = mainLayout.AddRow();
var splitButton = new Button.Primary( "Split", "content_cut" );
controlsLayout.Add( splitButton );
splitButton.Clicked = () =>
{
var splitPoints = spectogramWidget.GetSplitPoints();
if ( splitPoints.Count < 1 ) return;
var listControlWidget = parent.GetAncestor<ListControlWidget>();
if ( listControlWidget == null )
{
Log.Error( "Could not find ListControlWidget parent" );
return;
}
try
{
var baseFileName = Path.GetFileNameWithoutExtension( soundResource.ResourcePath );
var outputDir = Path.Combine(
Project.Current.GetAssetsPath(),
"generated",
$"{baseFileName}_splits"
);
Directory.CreateDirectory( outputDir );
var newSoundFiles = new List<SoundFile>();
for ( int i = 0; i < splitPoints.Count - 1; i++ )
{
var start = splitPoints[i];
var end = splitPoints[i + 1];
var length = end - start;
var segmentSamples = new short[length];
Array.Copy( samples, start, segmentSamples, 0, length );
var wavPath = Path.Combine( outputDir, $"{baseFileName}_part_{i + 1}.wav" );
using ( var writer = new BinaryWriter( File.Create( wavPath ) ) )
{
writer.Write( Encoding.ASCII.GetBytes( "RIFF" ) );
writer.Write( 36 + (segmentSamples.Length * 2) );
writer.Write( Encoding.ASCII.GetBytes( "WAVE" ) );
writer.Write( Encoding.ASCII.GetBytes( "fmt " ) );
writer.Write( 16 );
writer.Write( (short)1 );
writer.Write( (short)soundResource.Channels );
writer.Write( soundResource.Rate );
writer.Write( soundResource.Rate * soundResource.Channels * 2 );
writer.Write( (short)(soundResource.Channels * 2) );
writer.Write( (short)16 );
writer.Write( Encoding.ASCII.GetBytes( "data" ) );
writer.Write( segmentSamples.Length * 2 );
foreach ( var sample in segmentSamples )
{
writer.Write( sample );
}
}
var asset = AssetSystem.RegisterFile( wavPath );
if ( asset != null )
{
var soundFile = SoundFile.Load( asset.RelativePath );
if ( soundFile != null )
{
newSoundFiles.Add( soundFile );
}
}
}
if ( newSoundFiles.Count > 0 )
{
try
{
var collectionField = listControlWidget.GetType()
.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public )
.FirstOrDefault( f => typeof( SerializedCollection ).IsAssignableFrom( f.FieldType ) );
if ( collectionField == null )
{
return;
}
var collection = collectionField.GetValue( listControlWidget ) as SerializedCollection;
if ( collection == null )
{
return;
}
if ( property.TryGetAsObject( out var original ) )
{
foreach ( var soundFile in newSoundFiles )
{
collection.Add( soundFile );
}
collection.Remove( property );
}
}
catch ( Exception ex )
{
Log.Error( $"Error manipulating collection: {ex.Message}" );
Log.Error( $"Stack trace: {ex.StackTrace}" );
}
}
dialog.Close();
}
catch ( Exception ex )
{
Log.Error( $"Error splitting sound: {ex.Message}" );
}
};
}
}
Editor
library
using System;
using System.IO;
using System.Text.Json;
using Editor;
using Sandbox;
public class SoundSettings : Widget
{
public class Config : ConfigData
{
public string ElevenLabsApiKey { get; set; } = "";
public string GenerationPath { get; set; } = "generated";
}
private LineEdit apiKeyInput;
private LineEdit pathInput;
private static Config _settings;
private Button saveButton;
public static Config Settings
{
get
{
if (_settings == null)
_settings = EditorUtility.LoadProjectSettings<Config>("settings.json");
return _settings;
}
}
public SoundSettings() : base(null)
{
Layout = Layout.Column();
var mainLayout = Layout.Add(Layout.Column());
mainLayout.Margin = 16;
var apiKeyGroup = mainLayout.AddRow();
apiKeyGroup.Add(new Label("ElevenLabs API Key:"));
apiKeyInput = new LineEdit(this);
apiKeyInput.MinimumWidth = 300;
apiKeyInput.PlaceholderText = "Enter your ElevenLabs API key";
apiKeyInput.Text = Settings.ElevenLabsApiKey;
apiKeyGroup.Add(apiKeyInput);
mainLayout.AddSpacingCell(8);
var pathGroup = mainLayout.AddRow();
pathGroup.Add(new Label("Generation Path:"));
pathInput = new LineEdit(this);
pathInput.MinimumWidth = 300;
pathInput.PlaceholderText = "Enter generation path (relative to assets)";
pathInput.Text = Settings.GenerationPath;
pathGroup.Add(pathInput);
mainLayout.AddStretchCell();
var buttonLayout = mainLayout.AddRow();
buttonLayout.AddStretchCell();
saveButton = new Button.Primary("Save", "save");
saveButton.Clicked = SaveSettings;
buttonLayout.Add(saveButton);
}
private void SaveSettings()
{
Settings.ElevenLabsApiKey = apiKeyInput.Text;
Settings.GenerationPath = pathInput.Text;
EditorUtility.SaveProjectSettings(Settings, "settings.json");
Dialog.AskConfirm(() => {}, "Settings saved successfully.", "Success", "Okay");
}
[Menu("Editor", "AI Tools/Settings")]
public static void OpenSettings()
{
var dialog = new Dialog();
dialog.Window.Title = "Sound Generation Settings";
dialog.Window.Size = new Vector2(500, 200);
dialog.Layout = Layout.Column();
dialog.Layout.Add(new SoundSettings());
dialog.Show();
}
public static string GetGenerationPath()
{
return Path.Combine(Project.Current.GetAssetsPath(), Settings.GenerationPath);
}
}
Editor
library
using System.Linq;
using Editor;
using Sandbox;
public static class AIToolsMenu
{
[Menu( "Editor", "AI Tools/Generate sound" )]
public static void Generate()
{
if (SoundSettings.Settings.ElevenLabsApiKey.Length < 1)
{
Dialog.AskConfirm(() => {}, "Set your ElevenLabs API key first in settings.", "Error", "Okay");
return;
}
var inspectorObject = EditorUtility.InspectorObject as Asset;
if (inspectorObject == null)
{
Dialog.AskConfirm(() => {}, "Open SoundEvent in Inspector first.", "Error", "Okay");
return;
}
var resource = inspectorObject.LoadResource();
if (resource == null)
{
Dialog.AskConfirm(() => {}, "Failed to load resource.", "Error", "Okay");
return;
}
if (!(resource is SoundEvent))
{
Dialog.AskConfirm(() => {}, "Selected asset must be a SoundEvent.", "Error", "Okay");
return;
}
var soundEvent = resource as SoundEvent;
SoundAddons.Generate(soundEvent, (soundFile) => {
soundEvent.Sounds.Add(soundFile);
EditorUtility.InspectorObject = null;
EditorUtility.InspectorObject = inspectorObject;
});
}
[Menu("Editor", "AI Tools/Split sound")]
public static void Split()
{
var asset = EditorUtility.InspectorObject as Asset;
var soundEvent = asset.LoadResource() as SoundEvent;
var dialog = new Dialog();
dialog.Window.Title = "Split Sound";
dialog.Window.Size = new Vector2(800, 400);
dialog.Layout = Layout.Column();
var mainLayout = dialog.Layout.AddColumn();
mainLayout.Margin = 16f;
var spectogramWidget = new SpectogramWidget(null);
mainLayout.Add(spectogramWidget, 1);
var controlsLayout = mainLayout.AddRow();
var splitButton = new Button.Primary("Split", "content_cut");
controlsLayout.Add(splitButton);
splitButton.Clicked = () =>
{
if (spectogramWidget.CurrentSound == null)
{
Log.Error("No sound loaded to split");
return;
}
spectogramWidget.SplitCurrentSound((soundFile) => {
soundEvent.Sounds.Add(soundFile);
EditorUtility.InspectorObject = null;
EditorUtility.InspectorObject = asset;
});
};
dialog.Show();
}
}
Debug: View Raw JSON Response
{
"TotalCount": 4,
"Files": [
{
"Ident": "attackhelicopter.aitools",
"Path": "Editor/SpectogramWidget.cs",
"FileName": "SpectogramWidget.cs",
"PackageType": "library",
"CodeKind": "Editor",
"AssetVersionId": 76432,
"IsPrivate": false,
"Code": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing Editor;\r\nusing Sandbox;\r\nusing System.Text;\r\n\r\nclass SpectogramWidget : Widget \r\n{\r\n private short[] samples;\r\n private int sampleRate;\r\n private List<int> splitPoints = new List<int>();\r\n private int? dragPoint = null;\r\n private Label loadingLabel;\r\n private Label dropLabel;\r\n private bool isLoading = true;\r\n public SoundFile CurrentSound { get; private set; }\r\n\r\n public SpectogramWidget(SoundFile soundFile) : base(null)\r\n {\r\n MinimumSize = 100;\r\n MouseTracking = true;\r\n AcceptDrops = true;\r\n\r\n loadingLabel = new Label(this);\r\n loadingLabel.Text = \"Loading audio data...\";\r\n loadingLabel.Visible = false;\r\n \r\n dropLabel = new Label(this);\r\n dropLabel.Text = \"Drop a sound file here\";\r\n dropLabel.SetStyles(\"font-size: 18px; color: #aaa; text-align: center;\");\r\n \r\n if (soundFile != null)\r\n {\r\n LoadSound(soundFile);\r\n }\r\n }\r\n\r\n public async void LoadSound(SoundFile soundFile)\r\n {\r\n CurrentSound = soundFile;\r\n isLoading = true;\r\n samples = null;\r\n splitPoints.Clear();\r\n \r\n loadingLabel.Visible = true;\r\n dropLabel.Visible = false;\r\n\r\n await LoadAudioDataAsync(soundFile);\r\n }\r\n\r\n private async Task LoadAudioDataAsync(SoundFile soundFile)\r\n {\r\n try \r\n {\r\n await soundFile.LoadAsync();\r\n samples = await soundFile.GetSamplesAsync();\r\n \r\n if (samples == null)\r\n {\r\n loadingLabel.Text = \"Failed to load audio data\";\r\n return;\r\n }\r\n\r\n sampleRate = soundFile.Rate;\r\n splitPoints.Add(0);\r\n splitPoints.Add(samples.Length - 1);\r\n\r\n loadingLabel.Visible = false;\r\n isLoading = false;\r\n\r\n Update();\r\n }\r\n catch (Exception ex)\r\n {\r\n loadingLabel.Text = $\"Error loading audio: {ex.Message}\";\r\n }\r\n }\r\n\r\n protected override void DoLayout()\r\n {\r\n base.DoLayout();\r\n\r\n if (loadingLabel != null)\r\n {\r\n loadingLabel.Position = new Vector2(10, Height / 2 - 10);\r\n loadingLabel.Size = new Vector2(Width - 20, 20);\r\n }\r\n\r\n if (dropLabel != null)\r\n {\r\n dropLabel.Position = new Vector2(10, Height / 2 - 10);\r\n dropLabel.Size = new Vector2(Width - 20, 20);\r\n }\r\n }\r\n\r\n public override void OnDragDrop(DragEvent e)\r\n {\r\n base.OnDragDrop(e);\r\n\r\n if (!e.Data.HasFileOrFolder) return;\r\n\r\n var asset = AssetSystem.FindByPath(e.Data.FileOrFolder);\r\n if (asset?.AssetType != AssetType.SoundFile) return;\r\n\r\n var soundFile = SoundFile.Load(asset.Path);\r\n if (soundFile != null)\r\n {\r\n LoadSound(soundFile);\r\n }\r\n }\r\n\r\n public override void OnDragHover(DragEvent e)\r\n {\r\n base.OnDragHover(e);\r\n\r\n if (!e.Data.HasFileOrFolder) return;\r\n\r\n var asset = AssetSystem.FindByPath(e.Data.FileOrFolder);\r\n if (asset?.AssetType != AssetType.SoundFile) return;\r\n\r\n e.Action = DropAction.Link;\r\n }\r\n\r\n protected override void OnMouseClick(MouseEvent e)\r\n {\r\n if (isLoading) return;\r\n \r\n base.OnMouseClick(e);\r\n\r\n if (e.Button == MouseButtons.Left)\r\n {\r\n var samplePos = (int)(e.LocalPosition.x / Width * samples.Length);\r\n var nearPoint = splitPoints.FirstOrDefault(p => Math.Abs(p - samplePos) < (samples.Length / Width * 5));\r\n \r\n if (nearPoint != default)\r\n {\r\n dragPoint = splitPoints.IndexOf(nearPoint);\r\n }\r\n else\r\n {\r\n splitPoints.Add(samplePos);\r\n splitPoints.Sort();\r\n Update();\r\n }\r\n }\r\n }\r\n\r\n protected override void OnMouseMove(MouseEvent e)\r\n {\r\n if (isLoading) return;\r\n \r\n base.OnMouseMove(e);\r\n\r\n if (dragPoint.HasValue)\r\n {\r\n var samplePos = (int)(e.LocalPosition.x / Width * samples.Length);\r\n splitPoints[dragPoint.Value] = samplePos;\r\n splitPoints.Sort();\r\n Update();\r\n }\r\n }\r\n\r\n protected override void OnMouseReleased(MouseEvent e)\r\n {\r\n if (isLoading) return;\r\n \r\n base.OnMouseReleased(e);\r\n dragPoint = null;\r\n }\r\n\r\n protected override void OnPaint()\r\n {\r\n base.OnPaint();\r\n\r\n if (isLoading || samples == null)\r\n {\r\n return;\r\n }\r\n\r\n Paint.ClearPen();\r\n Paint.SetBrush(Theme.Grey.WithAlpha(0.1f));\r\n Paint.DrawRect(LocalRect);\r\n\r\n Paint.SetPen(Theme.Blue);\r\n var samplesPerPixel = samples.Length / Width;\r\n for (int x = 0; x < Width; x++)\r\n {\r\n var startSample = (int)(x * samplesPerPixel);\r\n var endSample = Math.Min(startSample + samplesPerPixel, samples.Length);\r\n \r\n var max = short.MinValue;\r\n var min = short.MaxValue;\r\n \r\n for (int i = startSample; i < endSample; i++)\r\n {\r\n max = Math.Max(max, samples[i]);\r\n min = Math.Min(min, samples[i]);\r\n }\r\n\r\n var y1 = Height / 2 + (min / (float)short.MaxValue * Height / 2);\r\n var y2 = Height / 2 + (max / (float)short.MaxValue * Height / 2);\r\n \r\n Paint.DrawLine(new Vector2(x, y1), new Vector2(x, y2));\r\n }\r\n\r\n Paint.SetPen(Theme.Red);\r\n foreach (var point in splitPoints)\r\n {\r\n var x = point / (float)samples.Length * Width;\r\n Paint.DrawLine(new Vector2(x, 0), new Vector2(x, Height));\r\n }\r\n }\r\n\r\n public List<int> GetSplitPoints()\r\n {\r\n return new List<int>(splitPoints);\r\n }\r\n\r\n public void SplitCurrentSound(Action<SoundFile> onSoundCreated)\r\n {\r\n if (CurrentSound == null || samples == null) return;\r\n\r\n var splitPoints = GetSplitPoints();\r\n if (splitPoints.Count < 2) return;\r\n\r\n try\r\n {\r\n var baseFileName = Path.GetFileNameWithoutExtension(CurrentSound.ResourcePath);\r\n var outputDir = Path.Combine(\r\n Project.Current.GetAssetsPath(),\r\n \"generated\",\r\n $\"{baseFileName}_splits\"\r\n );\r\n Directory.CreateDirectory(outputDir);\r\n\r\n for (int i = 0; i < splitPoints.Count - 1; i++)\r\n {\r\n var start = splitPoints[i];\r\n var end = splitPoints[i + 1];\r\n var length = end - start;\r\n\r\n var segmentSamples = new short[length];\r\n Array.Copy(samples, start, segmentSamples, 0, length);\r\n\r\n var wavPath = Path.Combine(outputDir, $\"{baseFileName}_part_{i + 1}.wav\");\r\n\r\n using (var writer = new BinaryWriter(File.Create(wavPath)))\r\n {\r\n writer.Write(Encoding.ASCII.GetBytes(\"RIFF\"));\r\n writer.Write(36 + (segmentSamples.Length * 2));\r\n writer.Write(Encoding.ASCII.GetBytes(\"WAVE\"));\r\n\r\n writer.Write(Encoding.ASCII.GetBytes(\"fmt \"));\r\n writer.Write(16);\r\n writer.Write((short)1);\r\n writer.Write((short)CurrentSound.Channels);\r\n writer.Write(CurrentSound.Rate);\r\n writer.Write(CurrentSound.Rate * CurrentSound.Channels * 2);\r\n writer.Write((short)(CurrentSound.Channels * 2));\r\n writer.Write((short)16);\r\n\r\n writer.Write(Encoding.ASCII.GetBytes(\"data\"));\r\n writer.Write(segmentSamples.Length * 2);\r\n\r\n foreach (var sample in segmentSamples)\r\n {\r\n writer.Write(sample);\r\n }\r\n }\r\n\r\n var asset = AssetSystem.RegisterFile(wavPath);\r\n if (asset != null)\r\n {\r\n var soundFile = SoundFile.Load(asset.RelativePath);\r\n if (soundFile != null)\r\n {\r\n onSoundCreated?.Invoke(soundFile);\r\n }\r\n }\r\n }\r\n }\r\n catch (Exception ex)\r\n {\r\n Log.Error($\"Error splitting sound: {ex.Message}\");\r\n }\r\n }\r\n}"
},
{
"Ident": "attackhelicopter.aitools",
"Path": "Editor/SoundAddons.cs",
"FileName": "SoundAddons.cs",
"PackageType": "library",
"CodeKind": "Editor",
"AssetVersionId": 76432,
"IsPrivate": false,
"Code": "using System;\r\nusing System.IO;\r\nusing System.Net.Http;\r\nusing System.Text;\r\nusing System.Text.Json;\r\nusing System.Reflection;\r\nusing Sandbox;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\n\r\nnamespace Editor;\r\n\r\npublic static class SoundAddons\r\n{\r\n\tprivate static string previousSoundGenerationPromp;\r\n\tprivate static string previousSoundGenerationDuration;\r\n\r\n\t// [ContextMenuFor( typeof( SoundFile ), \"Generate sound\", \"create\" )]\r\n\tpublic static void Generate( SoundEvent soundEvent, Action<SoundFile> finished )\r\n\t{\r\n\t\tstring defaultInput = !string.IsNullOrEmpty( previousSoundGenerationPromp )\r\n\t\t\t? previousSoundGenerationPromp\r\n\t\t\t: \"A dog barking\";\r\n\r\n\t\tDialog.AskString( ( description ) =>\r\n\t\t{\r\n\t\t\tpreviousSoundGenerationPromp = description;\r\n\r\n\t\t\tDialog.AskString( async ( durationStr ) =>\r\n\t\t\t{\r\n\t\t\t\tpreviousSoundGenerationDuration = durationStr;\r\n\t\t\t\tif ( !float.TryParse( durationStr, out float duration ) || duration < 0.5f || duration > 22f )\r\n\t\t\t\t{\r\n\t\t\t\t\tLog.Error( \"Duration must be between 0.5 and 22 seconds\" );\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttry\r\n\t\t\t\t{\r\n\t\t\t\t\tstring apiKey = SoundSettings.Settings.ElevenLabsApiKey;\r\n\t\t\t\t\tvar client = new HttpClient();\r\n\t\t\t\t\tclient.DefaultRequestHeaders.Add( \"xi-api-key\", apiKey );\r\n\r\n\t\t\t\t\tvar content = new StringContent( JsonSerializer.Serialize( new\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ttext = description,\r\n\t\t\t\t\t\tduration_seconds = duration,\r\n\t\t\t\t\t\tprompt_influence = 0.3\r\n\t\t\t\t\t} ), Encoding.UTF8, \"application/json\" );\r\n\r\n\t\t\t\t\tvar response = await client.PostAsync(\r\n\t\t\t\t\t\t\"https://api.elevenlabs.io/v1/sound-generation\",\r\n\t\t\t\t\t\tcontent\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\tif ( response.IsSuccessStatusCode )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvar bytes = await response.Content.ReadAsByteArrayAsync();\r\n\r\n\t\t\t\t\t\tstring safeFileName = description.Replace( \" \", \"_\" ).Replace( \"/\", \"_\" ).Replace( \"\\\\\", \"_\" );\r\n\t\t\t\t\t\tvar mp3Path = Path.Combine(\r\n\t\t\t\t\t\t\tSoundSettings.Settings.GenerationPath,\r\n\t\t\t\t\t\t\t$\"{safeFileName}_{DateTime.Now:yyyyMMddHHmmss}.mp3\"\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tvar fullMp3Path = Path.Combine( Project.Current.GetAssetsPath(), mp3Path );\r\n\t\t\t\t\t\tDirectory.CreateDirectory( Path.GetDirectoryName( fullMp3Path ) );\r\n\r\n\t\t\t\t\t\tawait File.WriteAllBytesAsync( fullMp3Path, bytes );\r\n\t\t\t\t\t\tLog.Info( \"File saved to: \" + fullMp3Path );\r\n\r\n\t\t\t\t\t\tvar mp3Asset = AssetSystem.RegisterFile( fullMp3Path );\r\n\t\t\t\t\t\tif ( mp3Asset != null )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tvar soundFile = SoundFile.Load( mp3Asset.RelativePath );\r\n\t\t\t\t\t\t\tif ( soundFile != null )\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tfinished(soundFile);\r\n\t\t\t\t\t\t\t\tLog.Info( $\"Successfully generated and linked sound: {mp3Asset.RelativePath}\" );\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tLog.Error( \"Failed to load generated sound file\" );\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tLog.Error( \"Failed to register generated mp3 file as asset\" );\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvar errorContent = await response.Content.ReadAsStringAsync();\r\n\t\t\t\t\t\tLog.Error( $\"Failed to generate sound: {response.StatusCode}. Error: {errorContent}\" );\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tcatch ( Exception ex )\r\n\t\t\t\t{\r\n\t\t\t\t\tLog.Error( $\"Error generating sound: {ex.Message}\" );\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\t\"Enter duration in seconds (0.5 to 22):\",\r\n\t\t\t\"Generate\",\r\n\t\t\t\"Cancel\",\r\n\t\t\tpreviousSoundGenerationDuration,\r\n\t\t\t\"Set Sound Duration\" );\r\n\t\t},\r\n\t\t\"Describe the sound effect to generate:\",\r\n\t\t\"Next\",\r\n\t\t\"Cancel\",\r\n\t\tdefaultInput,\r\n\t\t\"Generate Sound Effect\" );\r\n\t}\r\n\r\n\t// [ContextMenuFor( typeof( SoundFile ), \"Split sound\", \"content_cut\" )]\r\n\tpublic static async void SplitSound( Widget parent, SerializedProperty property )\r\n\t{\r\n\t\tvar soundResource = property.GetValue<SoundFile>();\r\n\t\tif ( soundResource == null || !soundResource.IsValid )\r\n\t\t{\r\n\t\t\tLog.Error( \"No valid sound file selected\" );\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar dialog = new Dialog();\r\n\t\tdialog.Window.Title = \"Split Sound\";\r\n\t\tdialog.Window.Size = new Vector2( 800, 400 );\r\n\r\n\t\tdialog.Layout = Layout.Column();\r\n\t\tvar mainLayout = dialog.Layout.AddColumn();\r\n\t\tmainLayout.Margin = 16f;\r\n\r\n\t\tvar loadingLabel = new Label( \"Loading audio data...\" );\r\n\t\tmainLayout.Add( loadingLabel );\r\n\r\n\t\tdialog.Show();\r\n\r\n\t\tvar samples = await soundResource.GetSamplesAsync();\r\n\t\tif ( samples == null )\r\n\t\t{\r\n\t\t\tloadingLabel.Text = \"Failed to load audio samples\";\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tloadingLabel.Destroy();\r\n\r\n\t\tvar spectogramWidget = new SpectogramWidget( soundResource );\r\n\t\tmainLayout.Add( spectogramWidget, 1 );\r\n\r\n\t\tvar controlsLayout = mainLayout.AddRow();\r\n\r\n\t\tvar splitButton = new Button.Primary( \"Split\", \"content_cut\" );\r\n\t\tcontrolsLayout.Add( splitButton );\r\n\r\n\t\tsplitButton.Clicked = () =>\r\n\t\t{\r\n\t\t\tvar splitPoints = spectogramWidget.GetSplitPoints();\r\n\t\t\tif ( splitPoints.Count < 1 ) return;\r\n\r\n\t\t\tvar listControlWidget = parent.GetAncestor<ListControlWidget>();\r\n\t\t\tif ( listControlWidget == null )\r\n\t\t\t{\r\n\t\t\t\tLog.Error( \"Could not find ListControlWidget parent\" );\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\tvar baseFileName = Path.GetFileNameWithoutExtension( soundResource.ResourcePath );\r\n\t\t\t\tvar outputDir = Path.Combine(\r\n\t\t\t\t\tProject.Current.GetAssetsPath(),\r\n\t\t\t\t\t\"generated\",\r\n\t\t\t\t\t$\"{baseFileName}_splits\"\r\n\t\t\t\t);\r\n\t\t\t\tDirectory.CreateDirectory( outputDir );\r\n\r\n\t\t\t\tvar newSoundFiles = new List<SoundFile>();\r\n\r\n\t\t\t\tfor ( int i = 0; i < splitPoints.Count - 1; i++ )\r\n\t\t\t\t{\r\n\t\t\t\t\tvar start = splitPoints[i];\r\n\t\t\t\t\tvar end = splitPoints[i + 1];\r\n\t\t\t\t\tvar length = end - start;\r\n\r\n\t\t\t\t\tvar segmentSamples = new short[length];\r\n\t\t\t\t\tArray.Copy( samples, start, segmentSamples, 0, length );\r\n\r\n\t\t\t\t\tvar wavPath = Path.Combine( outputDir, $\"{baseFileName}_part_{i + 1}.wav\" );\r\n\r\n\t\t\t\t\tusing ( var writer = new BinaryWriter( File.Create( wavPath ) ) )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\twriter.Write( Encoding.ASCII.GetBytes( \"RIFF\" ) );\r\n\t\t\t\t\t\twriter.Write( 36 + (segmentSamples.Length * 2) );\r\n\t\t\t\t\t\twriter.Write( Encoding.ASCII.GetBytes( \"WAVE\" ) );\r\n\r\n\t\t\t\t\t\twriter.Write( Encoding.ASCII.GetBytes( \"fmt \" ) );\r\n\t\t\t\t\t\twriter.Write( 16 );\r\n\t\t\t\t\t\twriter.Write( (short)1 );\r\n\t\t\t\t\t\twriter.Write( (short)soundResource.Channels );\r\n\t\t\t\t\t\twriter.Write( soundResource.Rate );\r\n\t\t\t\t\t\twriter.Write( soundResource.Rate * soundResource.Channels * 2 );\r\n\t\t\t\t\t\twriter.Write( (short)(soundResource.Channels * 2) );\r\n\t\t\t\t\t\twriter.Write( (short)16 );\r\n\r\n\t\t\t\t\t\twriter.Write( Encoding.ASCII.GetBytes( \"data\" ) );\r\n\t\t\t\t\t\twriter.Write( segmentSamples.Length * 2 );\r\n\r\n\t\t\t\t\t\tforeach ( var sample in segmentSamples )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\twriter.Write( sample );\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tvar asset = AssetSystem.RegisterFile( wavPath );\r\n\t\t\t\t\tif ( asset != null )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvar soundFile = SoundFile.Load( asset.RelativePath );\r\n\t\t\t\t\t\tif ( soundFile != null )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tnewSoundFiles.Add( soundFile );\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( newSoundFiles.Count > 0 )\r\n\t\t\t\t{\r\n\t\t\t\t\ttry\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvar collectionField = listControlWidget.GetType()\r\n\t\t\t\t\t\t\t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public )\r\n\t\t\t\t\t\t\t.FirstOrDefault( f => typeof( SerializedCollection ).IsAssignableFrom( f.FieldType ) );\r\n\r\n\t\t\t\t\t\tif ( collectionField == null )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tvar collection = collectionField.GetValue( listControlWidget ) as SerializedCollection;\r\n\t\t\t\t\t\tif ( collection == null )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif ( property.TryGetAsObject( out var original ) )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tforeach ( var soundFile in newSoundFiles )\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tcollection.Add( soundFile );\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tcollection.Remove( property );\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcatch ( Exception ex )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tLog.Error( $\"Error manipulating collection: {ex.Message}\" );\r\n\t\t\t\t\t\tLog.Error( $\"Stack trace: {ex.StackTrace}\" );\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tdialog.Close();\r\n\t\t\t}\r\n\t\t\tcatch ( Exception ex )\r\n\t\t\t{\r\n\t\t\t\tLog.Error( $\"Error splitting sound: {ex.Message}\" );\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n}"
},
{
"Ident": "attackhelicopter.aitools",
"Path": "Editor/SoundSettings.cs",
"FileName": "SoundSettings.cs",
"PackageType": "library",
"CodeKind": "Editor",
"AssetVersionId": 76432,
"IsPrivate": false,
"Code": "using System;\r\nusing System.IO;\r\nusing System.Text.Json;\r\nusing Editor;\r\nusing Sandbox;\r\n\r\npublic class SoundSettings : Widget\r\n{\r\n public class Config : ConfigData\r\n {\r\n public string ElevenLabsApiKey { get; set; } = \"\";\r\n public string GenerationPath { get; set; } = \"generated\";\r\n }\r\n\r\n private LineEdit apiKeyInput;\r\n private LineEdit pathInput;\r\n private static Config _settings;\r\n private Button saveButton;\r\n\r\n public static Config Settings \r\n {\r\n get\r\n {\r\n if (_settings == null)\r\n _settings = EditorUtility.LoadProjectSettings<Config>(\"settings.json\");\r\n return _settings;\r\n }\r\n }\r\n\r\n public SoundSettings() : base(null)\r\n {\r\n Layout = Layout.Column();\r\n var mainLayout = Layout.Add(Layout.Column());\r\n mainLayout.Margin = 16;\r\n\r\n var apiKeyGroup = mainLayout.AddRow();\r\n apiKeyGroup.Add(new Label(\"ElevenLabs API Key:\"));\r\n \r\n apiKeyInput = new LineEdit(this);\r\n apiKeyInput.MinimumWidth = 300;\r\n apiKeyInput.PlaceholderText = \"Enter your ElevenLabs API key\";\r\n apiKeyInput.Text = Settings.ElevenLabsApiKey;\r\n apiKeyGroup.Add(apiKeyInput);\r\n\r\n mainLayout.AddSpacingCell(8);\r\n\r\n var pathGroup = mainLayout.AddRow();\r\n pathGroup.Add(new Label(\"Generation Path:\"));\r\n \r\n pathInput = new LineEdit(this);\r\n pathInput.MinimumWidth = 300;\r\n pathInput.PlaceholderText = \"Enter generation path (relative to assets)\";\r\n pathInput.Text = Settings.GenerationPath;\r\n pathGroup.Add(pathInput);\r\n\r\n mainLayout.AddStretchCell();\r\n\r\n var buttonLayout = mainLayout.AddRow();\r\n buttonLayout.AddStretchCell();\r\n\r\n saveButton = new Button.Primary(\"Save\", \"save\");\r\n saveButton.Clicked = SaveSettings;\r\n buttonLayout.Add(saveButton);\r\n }\r\n\r\n private void SaveSettings()\r\n {\r\n Settings.ElevenLabsApiKey = apiKeyInput.Text;\r\n Settings.GenerationPath = pathInput.Text;\r\n EditorUtility.SaveProjectSettings(Settings, \"settings.json\");\r\n Dialog.AskConfirm(() => {}, \"Settings saved successfully.\", \"Success\", \"Okay\");\r\n }\r\n\r\n [Menu(\"Editor\", \"AI Tools/Settings\")]\r\n public static void OpenSettings()\r\n {\r\n var dialog = new Dialog();\r\n dialog.Window.Title = \"Sound Generation Settings\";\r\n dialog.Window.Size = new Vector2(500, 200);\r\n dialog.Layout = Layout.Column();\r\n dialog.Layout.Add(new SoundSettings());\r\n dialog.Show();\r\n }\r\n\r\n public static string GetGenerationPath()\r\n {\r\n return Path.Combine(Project.Current.GetAssetsPath(), Settings.GenerationPath);\r\n }\r\n}"
},
{
"Ident": "attackhelicopter.aitools",
"Path": "Editor/AIToolsMenu.cs",
"FileName": "AIToolsMenu.cs",
"PackageType": "library",
"CodeKind": "Editor",
"AssetVersionId": 76432,
"IsPrivate": false,
"Code": "using System.Linq;\r\nusing Editor;\r\nusing Sandbox;\r\n\r\npublic static class AIToolsMenu\r\n{\r\n\t[Menu( \"Editor\", \"AI Tools/Generate sound\" )]\r\n public static void Generate()\r\n {\r\n\t\tif (SoundSettings.Settings.ElevenLabsApiKey.Length < 1)\r\n {\r\n Dialog.AskConfirm(() => {}, \"Set your ElevenLabs API key first in settings.\", \"Error\", \"Okay\");\r\n return;\r\n }\r\n\r\n var inspectorObject = EditorUtility.InspectorObject as Asset;\r\n if (inspectorObject == null)\r\n {\r\n Dialog.AskConfirm(() => {}, \"Open SoundEvent in Inspector first.\", \"Error\", \"Okay\");\r\n return;\r\n }\r\n\r\n var resource = inspectorObject.LoadResource();\r\n if (resource == null)\r\n {\r\n Dialog.AskConfirm(() => {}, \"Failed to load resource.\", \"Error\", \"Okay\");\r\n return;\r\n }\r\n\r\n if (!(resource is SoundEvent))\r\n {\r\n Dialog.AskConfirm(() => {}, \"Selected asset must be a SoundEvent.\", \"Error\", \"Okay\");\r\n return;\r\n }\r\n\r\n var soundEvent = resource as SoundEvent;\r\n SoundAddons.Generate(soundEvent, (soundFile) => {\r\n soundEvent.Sounds.Add(soundFile);\r\n\t\t\tEditorUtility.InspectorObject = null;\r\n EditorUtility.InspectorObject = inspectorObject;\r\n });\r\n }\r\n\r\n[Menu(\"Editor\", \"AI Tools/Split sound\")]\r\n public static void Split()\r\n {\r\n var asset = EditorUtility.InspectorObject as Asset;\r\n var soundEvent = asset.LoadResource() as SoundEvent;\r\n\r\n var dialog = new Dialog();\r\n dialog.Window.Title = \"Split Sound\";\r\n dialog.Window.Size = new Vector2(800, 400);\r\n\r\n dialog.Layout = Layout.Column();\r\n var mainLayout = dialog.Layout.AddColumn();\r\n mainLayout.Margin = 16f;\r\n\r\n var spectogramWidget = new SpectogramWidget(null);\r\n mainLayout.Add(spectogramWidget, 1);\r\n\r\n var controlsLayout = mainLayout.AddRow();\r\n var splitButton = new Button.Primary(\"Split\", \"content_cut\");\r\n controlsLayout.Add(splitButton);\r\n\r\n splitButton.Clicked = () =>\r\n {\r\n if (spectogramWidget.CurrentSound == null)\r\n {\r\n Log.Error(\"No sound loaded to split\");\r\n return;\r\n }\r\n\r\n spectogramWidget.SplitCurrentSound((soundFile) => {\r\n soundEvent.Sounds.Add(soundFile);\r\n\t\t\t\tEditorUtility.InspectorObject = null;\r\n\t\t\t\tEditorUtility.InspectorObject = asset;\r\n });\r\n };\r\n\r\n dialog.Show();\r\n }\r\n}\r\n"
}
]
}