Compare commits
2 Commits
ad07bf7fe6
...
69c9d80a82
| Author | SHA1 | Date | |
|---|---|---|---|
| 69c9d80a82 | |||
| 8c83819a17 |
@ -2,12 +2,94 @@
|
|||||||
{
|
{
|
||||||
"name": "Uncategorized",
|
"name": "Uncategorized",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"clips": []
|
"clips": [
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_195932.wav",
|
||||||
|
"name": "Clip 20260226_195932",
|
||||||
|
"playbackType": "playOverlap",
|
||||||
|
"volume": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Test",
|
"name": "Test",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"clips": []
|
"clips": [
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_183607.wav",
|
||||||
|
"name": "Clip 20260226_183607",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"volume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_183812.wav",
|
||||||
|
"name": "Clip 20260226_183812",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"volume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_183822.wav",
|
||||||
|
"name": "Clip 20260226_183822",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"volume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_184028.wav",
|
||||||
|
"name": "Clip 20260226_184028",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"volume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_184030.wav",
|
||||||
|
"name": "Clip 20260226_184030",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"volume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_184032.wav",
|
||||||
|
"name": "Clip 20260226_184032",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"volume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_184037.wav",
|
||||||
|
"name": "Clip 20260226_184037",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"volume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_184040.wav",
|
||||||
|
"name": "Clip 20260226_184040",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"volume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_184041.wav",
|
||||||
|
"name": "Clip 20260226_184041",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"volume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_184042.wav",
|
||||||
|
"name": "Clip 20260226_184042",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"volume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_184043.wav",
|
||||||
|
"name": "Clip 20260226_184043",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"volume": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endTime": 14.772566995768694,
|
||||||
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260226_194441.wav",
|
||||||
|
"name": "Test",
|
||||||
|
"playbackType": "playStop",
|
||||||
|
"startTime": 9.8548571932299,
|
||||||
|
"volume": 0.6
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "New",
|
"name": "New",
|
||||||
@ -18,15 +100,15 @@
|
|||||||
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260220_193822.wav",
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260220_193822.wav",
|
||||||
"name": "Pee pee\npoo poo",
|
"name": "Pee pee\npoo poo",
|
||||||
"playbackType": "playOverlap",
|
"playbackType": "playOverlap",
|
||||||
"startTime": 27.76674010920584,
|
"startTime": 27.64044943820222,
|
||||||
"volume": 0.25
|
"volume": 0.31
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"endTime": 27.516843118383072,
|
"endTime": 30,
|
||||||
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260220_200442.wav",
|
"filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260220_200442.wav",
|
||||||
"name": "Clip 20260220_200442",
|
"name": "Test",
|
||||||
"playbackType": "playOverlap",
|
"playbackType": "playOverlap",
|
||||||
"startTime": 25.120307988450435,
|
"startTime": 26.14685314685314,
|
||||||
"volume": 0.64
|
"volume": 0.64
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
sounddevice==0.5.1
|
Flask==3.1.3
|
||||||
numpy==1.22.3
|
flask_cors==6.0.2
|
||||||
python-osc==1.9.3
|
flask_socketio==5.6.1
|
||||||
scipy==1.10.1
|
numpy==2.4.2
|
||||||
comtypes==1.4.8
|
scipy==1.17.1
|
||||||
pycaw==20240210
|
sounddevice==0.5.5
|
||||||
Flask==3.1.2
|
|
||||||
|
|||||||
@ -10,8 +10,8 @@
|
|||||||
"output_device": {
|
"output_device": {
|
||||||
"channels": 2,
|
"channels": 2,
|
||||||
"default_samplerate": 48000,
|
"default_samplerate": 48000,
|
||||||
"index": 44,
|
"index": 45,
|
||||||
"name": "VM to Headset (VB-Audio Voicemeeter VAIO)"
|
"name": "VM to Discord (VB-Audio Voicemeeter VAIO)"
|
||||||
},
|
},
|
||||||
"http_port": 5010
|
"http_port": 5010
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@ -19,7 +19,7 @@ import threading
|
|||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
CORS(app)
|
CORS(app)
|
||||||
socketio = SocketIO(app, cors_allowed_origins="*")
|
socketio = SocketIO(app, cors_allowed_origins="*", logger=True, engineio_logger=True, async_mode='eventlet')
|
||||||
|
|
||||||
@socketio.on('connect')
|
@socketio.on('connect')
|
||||||
def handle_connect():
|
def handle_connect():
|
||||||
@ -27,10 +27,18 @@ def handle_connect():
|
|||||||
emit('full_data', MetaDataManager().collections)
|
emit('full_data', MetaDataManager().collections)
|
||||||
|
|
||||||
@socketio.on('record_clip')
|
@socketio.on('record_clip')
|
||||||
def record_clip(data):
|
def record_clip():
|
||||||
io = AudioIO()
|
io = AudioIO()
|
||||||
io.save_last_n_seconds();
|
io.save_last_n_seconds();
|
||||||
|
|
||||||
|
@socketio.on('play_clip')
|
||||||
|
def play_clip(data):
|
||||||
|
io = AudioIO()
|
||||||
|
print(f"Received play_clip event with data: {data}")
|
||||||
|
if data:
|
||||||
|
io.play_clip(data)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Create argument parser
|
# Create argument parser
|
||||||
parser = argparse.ArgumentParser(description='Audio Recording Service')
|
parser = argparse.ArgumentParser(description='Audio Recording Service')
|
||||||
@ -65,8 +73,9 @@ def main():
|
|||||||
app.register_blueprint(device_bp)
|
app.register_blueprint(device_bp)
|
||||||
app.register_blueprint(metadata_bp)
|
app.register_blueprint(metadata_bp)
|
||||||
app.register_blueprint(settings_bp)
|
app.register_blueprint(settings_bp)
|
||||||
|
print(f"Starting Flask server on port {settings.get_settings('http_port')}")
|
||||||
# app.run(host='127.0.0.1', port=settings.get_settings('http_port'), debug=False, use_reloader=True)
|
# app.run(host='127.0.0.1', port=settings.get_settings('http_port'), debug=False, use_reloader=True)
|
||||||
socketio.run(app, host='127.0.0.1', port=settings.get_settings('http_port'), debug=False, use_reloader=True)
|
socketio.run(app, host='127.0.0.1', port=settings.get_settings('http_port'), debug=False, use_reloader=True, allow_unsafe_werkzeug=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -41,6 +41,8 @@ class MetaDataManager:
|
|||||||
if collection is None:
|
if collection is None:
|
||||||
raise ValueError(f"Collection '{collection_name}' does not exist.")
|
raise ValueError(f"Collection '{collection_name}' does not exist.")
|
||||||
collection["clips"].append(clip_metadata)
|
collection["clips"].append(clip_metadata)
|
||||||
|
if not self.socket is None:
|
||||||
|
self.socket.emit('collection_updated', collection)
|
||||||
self.save_metadata()
|
self.save_metadata()
|
||||||
|
|
||||||
def remove_clip_from_collection(self, collection_name, clip_metadata):
|
def remove_clip_from_collection(self, collection_name, clip_metadata):
|
||||||
@ -56,11 +58,18 @@ class MetaDataManager:
|
|||||||
clip for clip in collection["clips"]
|
clip for clip in collection["clips"]
|
||||||
if clip.get("filename") != clip_metadata.get("filename")
|
if clip.get("filename") != clip_metadata.get("filename")
|
||||||
]
|
]
|
||||||
|
if not self.socket is None:
|
||||||
|
self.socket.emit('collection_updated', collection)
|
||||||
self.save_metadata()
|
self.save_metadata()
|
||||||
|
|
||||||
|
|
||||||
def move_clip_to_collection(self, source_collection, target_collection, clip_metadata):
|
def move_clip_to_collection(self, source_collection, target_collection, clip_metadata):
|
||||||
self.remove_clip_from_collection(source_collection, clip_metadata)
|
self.remove_clip_from_collection(source_collection, clip_metadata)
|
||||||
self.add_clip_to_collection(target_collection, clip_metadata)
|
self.add_clip_to_collection(target_collection, clip_metadata)
|
||||||
|
if not self.socket is None:
|
||||||
|
self.socket.emit('collection_updated', source_collection)
|
||||||
|
self.socket.emit('collection_updated', target_collection)
|
||||||
|
|
||||||
|
|
||||||
def edit_clip_in_collection(self, collection_name, new_clip_metadata):
|
def edit_clip_in_collection(self, collection_name, new_clip_metadata):
|
||||||
collection = next((c for c in self.collections if c.get("name") == collection_name), None)
|
collection = next((c for c in self.collections if c.get("name") == collection_name), None)
|
||||||
@ -72,6 +81,8 @@ class MetaDataManager:
|
|||||||
raise ValueError(f"Clip with filename '{new_clip_metadata.get('filename')}' not found in collection '{collection_name}'.")
|
raise ValueError(f"Clip with filename '{new_clip_metadata.get('filename')}' not found in collection '{collection_name}'.")
|
||||||
|
|
||||||
collection["clips"][index] = new_clip_metadata
|
collection["clips"][index] = new_clip_metadata
|
||||||
|
if not self.socket is None:
|
||||||
|
self.socket.emit('collection_updated', collection)
|
||||||
self.save_metadata()
|
self.save_metadata()
|
||||||
|
|
||||||
def get_collections(self):
|
def get_collections(self):
|
||||||
|
|||||||
Binary file not shown.
@ -1,9 +1,5 @@
|
|||||||
import sounddevice as sd
|
import sounddevice as sd
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import comtypes
|
|
||||||
import comtypes.client
|
|
||||||
from comtypes import CLSCTX_ALL
|
|
||||||
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
class WindowsAudioManager:
|
class WindowsAudioManager:
|
||||||
|
|||||||
@ -112,9 +112,6 @@ const createWindow = async () => {
|
|||||||
|
|
||||||
registerFileIpcHandlers();
|
registerFileIpcHandlers();
|
||||||
|
|
||||||
const pythonManager = new PythonSubprocessManager('src/main.py');
|
|
||||||
|
|
||||||
pythonManager.start();
|
|
||||||
// Remove this if your app does not use auto updates
|
// Remove this if your app does not use auto updates
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
new AppUpdater();
|
new AppUpdater();
|
||||||
@ -135,6 +132,8 @@ app.on('window-all-closed', () => {
|
|||||||
app
|
app
|
||||||
.whenReady()
|
.whenReady()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
const pythonManager = new PythonSubprocessManager('src/main.py');
|
||||||
|
pythonManager.start();
|
||||||
createWindow();
|
createWindow();
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
// On macOS it's common to re-create a window in the app when the
|
// On macOS it's common to re-create a window in the app when the
|
||||||
|
|||||||
@ -40,7 +40,7 @@ export default class PythonSubprocessManager {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.process.stdout.on('data', (data: Buffer) => {
|
this.process.stdout.on('data', (data: Buffer) => {
|
||||||
console.log(`Python stdout: ${data.toString()}`);
|
// console.log(`Python stdout: ${data.toString()}`);
|
||||||
});
|
});
|
||||||
this.process.stderr.on('data', (data: Buffer) => {
|
this.process.stderr.on('data', (data: Buffer) => {
|
||||||
// console.error(`Python stderr: ${data.toString()}`);
|
// console.error(`Python stderr: ${data.toString()}`);
|
||||||
|
|||||||
@ -1,13 +1,16 @@
|
|||||||
using System;
|
using BarRaider.SdTools;
|
||||||
|
using ClipTrimDotNet.Keys;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SocketIOClient;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||||
using SocketIOClient;
|
|
||||||
using BarRaider.SdTools;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace ClipTrimDotNet.Client
|
namespace ClipTrimDotNet.Client
|
||||||
{
|
{
|
||||||
@ -78,62 +81,124 @@ namespace ClipTrimDotNet.Client
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
|
||||||
Task.Run(async () => await socket.ConnectAsync());
|
socket.OnDisconnected += (sender, e) =>
|
||||||
//Task.Run(ShortPoll);
|
{
|
||||||
|
Logger.Instance.LogMessage(TracingLevel.INFO, $"Socket disconnected: {e}");
|
||||||
|
Task.Run(async () => await Connect());
|
||||||
|
};
|
||||||
|
Task.Run(async () => await Connect());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task Connect()
|
||||||
|
{
|
||||||
|
while (!socket.Connected)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await socket.ConnectAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
//public async Task ShortPoll()
|
}
|
||||||
//{
|
}
|
||||||
// while (true)
|
}
|
||||||
// {
|
|
||||||
// await GetMetadata();
|
|
||||||
// await Task.Delay(TimeSpan.FromSeconds(5)); await Task.Delay(TimeSpan.FromSeconds(5));
|
|
||||||
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
public List<CollectionMetaData> Collections { get; private set; } = new List<CollectionMetaData>();
|
public List<CollectionMetaData> Collections { get; private set; } = new List<CollectionMetaData>();
|
||||||
public int SelectedCollection { get; private set; } = -1;
|
public int SelectedCollection { get; private set; } = -1;
|
||||||
public int PageIndex { get; private set; } = 0;
|
|
||||||
//private async Task GetMetadata()
|
|
||||||
//{
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// var response = await httpClient.GetAsync("meta");
|
|
||||||
// if (response.IsSuccessStatusCode)
|
|
||||||
// {
|
|
||||||
// var json = await response.Content.ReadAsStringAsync();
|
|
||||||
// dynamic collections = JsonConvert.DeserializeObject(json);
|
|
||||||
// collections = collections.collections;
|
|
||||||
// Collections = JsonConvert.DeserializeObject<List<CollectionMetaData>>(collections.ToString());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, $"Error pinging ClipTrim API: {ex.Message}");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
//}
|
public Dictionary<int, int> CollectionIndexes { get; private set; } = new();
|
||||||
|
public int PageIndex
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (SelectedCollection == -1) return 0;
|
||||||
|
if (!CollectionIndexes.ContainsKey(SelectedCollection))
|
||||||
|
{
|
||||||
|
CollectionIndexes[SelectedCollection] = 0;
|
||||||
|
}
|
||||||
|
return CollectionIndexes[SelectedCollection];
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SelectedCollection == -1) return;
|
||||||
|
CollectionIndexes[SelectedCollection] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool PageMode { get; set; } = false;
|
||||||
|
|
||||||
|
public int PageCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (SelectedCollection == -1) return 0;
|
||||||
|
var collection = Collections[SelectedCollection];
|
||||||
|
return (collection.Clips.Count - 1) / 10 + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool CanPageUp
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(PageMode) return false;
|
||||||
|
if (SelectedCollection == -1) return false;
|
||||||
|
return PageCount - PageIndex > 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanPageDown
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (PageMode) return false;
|
||||||
|
return PageIndex > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PageDown()
|
||||||
|
{
|
||||||
|
if (CanPageDown)
|
||||||
|
{
|
||||||
|
PageIndex--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PageUp()
|
||||||
|
{
|
||||||
|
if (CanPageUp)
|
||||||
|
{
|
||||||
|
PageIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
public List<string> GetCollectionNames()
|
public List<string> GetCollectionNames()
|
||||||
{
|
{
|
||||||
//await GetMetadata();
|
//await GetMetadata();
|
||||||
return Collections.Select(x => x.Name).ToList();
|
return Collections.Where(x => x.Name != "Uncategorized").Select(x => x.Name).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSelectedCollectionByName(string name)
|
public string GetPlayerStringByCoordinateIndex(int index)
|
||||||
{
|
{
|
||||||
SelectedCollection = Collections.FindIndex(x => x.Name == name);
|
if (PageMode)
|
||||||
if (SelectedCollection != -1)
|
|
||||||
{
|
{
|
||||||
PageIndex = 0;
|
int pageNumber = index + 1;
|
||||||
|
if(pageNumber <= PageCount)
|
||||||
|
{
|
||||||
|
return pageNumber.ToString();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var collection = GetClipByPagedIndex(index);
|
||||||
|
return collection?.Name ?? "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public ClipMetadata? GetClipByPagedIndex(int index)
|
public ClipMetadata? GetClipByPagedIndex(int index)
|
||||||
{
|
{
|
||||||
|
SelectedCollection = Collections.FindIndex(x => x.Name == GlobalSettings.Instance.ProfileName);
|
||||||
if (SelectedCollection == -1) return null;
|
if (SelectedCollection == -1) return null;
|
||||||
int clipIndex = PageIndex * 10 + index;
|
int clipIndex = PageIndex * 10 + index;
|
||||||
var collection = Collections[SelectedCollection];
|
var collection = Collections[SelectedCollection];
|
||||||
@ -144,15 +209,29 @@ namespace ClipTrimDotNet.Client
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void PlayClip(ClipMetadata? metadata)
|
public async void PlayClip(int index)
|
||||||
{
|
{
|
||||||
|
if (PageMode)
|
||||||
|
{
|
||||||
|
if(index < 0 || index >= PageCount) return;
|
||||||
|
PageIndex = index;
|
||||||
|
PageMode = false;
|
||||||
|
Player.TickAll();
|
||||||
|
PageNavigator.TickAll();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var metadata = GetClipByPagedIndex(index);
|
||||||
if (metadata == null) return;
|
if (metadata == null) return;
|
||||||
|
Logger.Instance.LogMessage(TracingLevel.INFO, $"playing clip:");
|
||||||
|
await socket.EmitAsync("play_clip", new List<object>() { metadata });
|
||||||
|
}
|
||||||
|
|
||||||
//var response = await httpClient.PostAsync("playback/start", new StringContent(JsonConvert.SerializeObject(metadata), Encoding.UTF8, "application/json"));
|
}
|
||||||
//if (!response.IsSuccessStatusCode)
|
|
||||||
//{
|
public async void SaveClip()
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, $"Error playing clip: {response.ReasonPhrase}");
|
{
|
||||||
//}
|
await socket.EmitAsync("record_clip", new List<object>() { });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,28 +10,6 @@ using Newtonsoft.Json.Linq;
|
|||||||
|
|
||||||
namespace ClipTrimDotNet
|
namespace ClipTrimDotNet
|
||||||
{
|
{
|
||||||
public class FileEntry
|
|
||||||
{
|
|
||||||
public FileEntry()
|
|
||||||
{
|
|
||||||
Volume = 1.0;
|
|
||||||
Playtype = "Play/Overlap";
|
|
||||||
}
|
|
||||||
[JsonProperty(PropertyName = "Volume")]
|
|
||||||
public double Volume { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "Playtype")]
|
|
||||||
public string Playtype { get; set; }
|
|
||||||
}
|
|
||||||
public class CollectionEntry
|
|
||||||
{
|
|
||||||
public CollectionEntry()
|
|
||||||
{
|
|
||||||
Files = new Dictionary<string, FileEntry>();
|
|
||||||
}
|
|
||||||
[JsonProperty(PropertyName = "Files")]
|
|
||||||
public Dictionary<string, FileEntry> Files { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GlobalSettings
|
public class GlobalSettings
|
||||||
{
|
{
|
||||||
public static GlobalSettings? _inst;
|
public static GlobalSettings? _inst;
|
||||||
@ -50,59 +28,18 @@ namespace ClipTrimDotNet
|
|||||||
public static GlobalSettings CreateDefaultSettings()
|
public static GlobalSettings CreateDefaultSettings()
|
||||||
{
|
{
|
||||||
GlobalSettings instance = new GlobalSettings();
|
GlobalSettings instance = new GlobalSettings();
|
||||||
instance.BasePath = null;
|
|
||||||
instance.ProfileName = null;
|
instance.ProfileName = null;
|
||||||
instance.Collections = new Dictionary<string, CollectionEntry>();
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[FilenameProperty]
|
|
||||||
[JsonProperty(PropertyName = "basePath")]
|
|
||||||
public string? BasePath { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "profileName")]
|
[JsonProperty(PropertyName = "profileName")]
|
||||||
public string? ProfileName { get; set; }
|
public string? ProfileName { get; set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "outputDevice")]
|
|
||||||
public string? OutputDevice { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "collections")]
|
|
||||||
public Dictionary<string, CollectionEntry> Collections { get; set; }
|
|
||||||
|
|
||||||
public void SetCurrentProfile(string profile)
|
public void SetCurrentProfile(string profile)
|
||||||
{
|
{
|
||||||
ProfileName = profile;
|
ProfileName = profile;
|
||||||
if(!Collections.ContainsKey(profile))
|
|
||||||
{
|
|
||||||
Collections.Add(profile, new CollectionEntry());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileEntry GetFileOptionsInCurrentProfile(string filename)
|
|
||||||
{
|
|
||||||
if(!Collections.TryGetValue(ProfileName, out CollectionEntry collection))
|
|
||||||
{
|
|
||||||
return new FileEntry();
|
|
||||||
}
|
|
||||||
if(!collection.Files.TryGetValue(filename, out FileEntry file))
|
|
||||||
{
|
|
||||||
return new FileEntry();
|
|
||||||
}
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, "fetched file settings " + filename + JsonConvert.SerializeObject(file));
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetFileOptionsCurrentProfile(string filename, FileEntry file)
|
|
||||||
{
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, "SetFileOptionsCurrentProfile ");
|
|
||||||
if (!Collections.TryGetValue(ProfileName, out CollectionEntry collection))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, "SetFileOptionsCurrentProfile 2");
|
|
||||||
//collection.Files[filename] = file;
|
|
||||||
Collections[ProfileName].Files[filename] = file;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
49
stream_deck_plugin/ClipTrimDotNet/Keys/ClipSave.cs
Normal file
49
stream_deck_plugin/ClipTrimDotNet/Keys/ClipSave.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using BarRaider.SdTools;
|
||||||
|
using ClipTrimDotNet.Client;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ClipTrimDotNet.Keys
|
||||||
|
{
|
||||||
|
[PluginActionId("com.michal-courson.cliptrim.clip-save")]
|
||||||
|
public class ClipSave : KeypadBase
|
||||||
|
{
|
||||||
|
public ClipSave(SDConnection connection, InitialPayload payload) : base(connection, payload)
|
||||||
|
{
|
||||||
|
GlobalSettingsManager.Instance.RequestGlobalSettings();
|
||||||
|
}
|
||||||
|
public void Instance_OnReceivedGlobalSettings(object sender, ReceivedGlobalSettingsPayload e)
|
||||||
|
{
|
||||||
|
Tools.AutoPopulateSettings(GlobalSettings.Instance, e.Settings);
|
||||||
|
}
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public override void KeyPressed(KeyPayload payload)
|
||||||
|
{
|
||||||
|
ClipTrimClient.Instance.SaveClip();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void OnTick()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void KeyReleased(KeyPayload payload)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReceivedSettings(ReceivedSettingsPayload payload)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload)
|
||||||
|
{
|
||||||
|
Tools.AutoPopulateSettings(GlobalSettings.Instance, payload.Settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
stream_deck_plugin/ClipTrimDotNet/Keys/PageNavigator.cs
Normal file
107
stream_deck_plugin/ClipTrimDotNet/Keys/PageNavigator.cs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
using BarRaider.SdTools;
|
||||||
|
using ClipTrimDotNet.Client;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ClipTrimDotNet.Keys
|
||||||
|
{
|
||||||
|
[PluginActionId("com.michal-courson.cliptrim.page-navigator")]
|
||||||
|
public class PageNavigator : KeypadBase
|
||||||
|
{
|
||||||
|
static List<PageNavigator> instances = new();
|
||||||
|
private KeyCoordinates coordinates;
|
||||||
|
public PageNavigator(SDConnection connection, InitialPayload payload) : base(connection, payload)
|
||||||
|
{
|
||||||
|
coordinates = payload.Coordinates;
|
||||||
|
GlobalSettingsManager.Instance.RequestGlobalSettings();
|
||||||
|
instances.Add(this);
|
||||||
|
OnTick();
|
||||||
|
}
|
||||||
|
public void Instance_OnReceivedGlobalSettings(object sender, ReceivedGlobalSettingsPayload e)
|
||||||
|
{
|
||||||
|
Tools.AutoPopulateSettings(GlobalSettings.Instance, e.Settings);
|
||||||
|
}
|
||||||
|
public int GetIndex()
|
||||||
|
{
|
||||||
|
int index = Math.Min(Math.Max(coordinates.Column - 1, 0), 2);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public override void KeyPressed(KeyPayload payload)
|
||||||
|
{
|
||||||
|
switch (GetIndex())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
ClipTrimClient.Instance.PageDown();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ClipTrimClient.Instance.PageMode = !ClipTrimClient.Instance.PageMode;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ClipTrimClient.Instance.PageUp();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Player.TickAll();
|
||||||
|
TickAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TickAll()
|
||||||
|
{
|
||||||
|
foreach (var instance in instances)
|
||||||
|
{
|
||||||
|
instance.OnTick();
|
||||||
|
}
|
||||||
|
instances.RemoveAll(i => i == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void SetTitle()
|
||||||
|
{
|
||||||
|
switch (GetIndex())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
await Connection.SetTitleAsync(ClipTrimClient.Instance.CanPageDown ? "<" : "");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
await Connection.SetTitleAsync((ClipTrimClient.Instance.PageIndex + 1).ToString());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
await Connection.SetTitleAsync(ClipTrimClient.Instance.CanPageUp ? ">" : "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnTick()
|
||||||
|
{
|
||||||
|
SetTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void KeyReleased(KeyPayload payload)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReceivedSettings(ReceivedSettingsPayload payload)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload)
|
||||||
|
{
|
||||||
|
Tools.AutoPopulateSettings(GlobalSettings.Instance, payload.Settings);
|
||||||
|
//if (payload.Settings == null || payload.Settings.Count == 0)
|
||||||
|
//{
|
||||||
|
// var inst = GlobalSettings.Instance;
|
||||||
|
// //GlobalSettingsManager.Instance.SetGlobalSettings(JObject.FromObject(inst));
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// GlobalSettings.Instance = payload.Settings.ToObject<GlobalSettings>();
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
stream_deck_plugin/ClipTrimDotNet/Keys/Player.cs
Normal file
87
stream_deck_plugin/ClipTrimDotNet/Keys/Player.cs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
using BarRaider.SdTools;
|
||||||
|
using BarRaider.SdTools.Wrappers;
|
||||||
|
using ClipTrimDotNet.Client;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ClipTrimDotNet.Keys
|
||||||
|
{
|
||||||
|
[PluginActionId("com.michal-courson.cliptrim.player")]
|
||||||
|
public class Player : KeypadBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private int coordIndex;
|
||||||
|
private string? current_text = null;
|
||||||
|
private KeyCoordinates coordinates;
|
||||||
|
|
||||||
|
static List<Player> instances = new();
|
||||||
|
|
||||||
|
public Player(SDConnection connection, InitialPayload payload) : base(connection, payload)
|
||||||
|
{
|
||||||
|
coordinates = payload.Coordinates;
|
||||||
|
GlobalSettingsManager.Instance.RequestGlobalSettings();
|
||||||
|
instances.Add(this);
|
||||||
|
coordIndex = Math.Max((coordinates.Row - 1) * 5 + coordinates.Column, 0);
|
||||||
|
OnTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TickAll()
|
||||||
|
{
|
||||||
|
Logger.Instance.LogMessage(TracingLevel.INFO, "Ticking all Player instances" + instances.Count);
|
||||||
|
foreach (var instance in instances)
|
||||||
|
{
|
||||||
|
instance.OnTick();
|
||||||
|
}
|
||||||
|
instances.RemoveAll(i => i == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void CheckFile()
|
||||||
|
{
|
||||||
|
var next_text = ClipTrimClient.Instance.GetPlayerStringByCoordinateIndex(coordIndex);
|
||||||
|
if(next_text != current_text)
|
||||||
|
{
|
||||||
|
current_text = next_text;
|
||||||
|
await Connection.SetTitleAsync($"{current_text ?? ""}");
|
||||||
|
}
|
||||||
|
current_text = next_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void KeyPressed(KeyPayload payload)
|
||||||
|
{
|
||||||
|
ClipTrimClient.Instance.PlayClip(coordIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void OnTick() {
|
||||||
|
CheckFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload) {
|
||||||
|
Tools.AutoPopulateSettings(GlobalSettings.Instance, payload.Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void KeyReleased(KeyPayload payload)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReceivedSettings(ReceivedSettingsPayload payload)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
136
stream_deck_plugin/ClipTrimDotNet/Keys/ProfileSwitcher.cs
Normal file
136
stream_deck_plugin/ClipTrimDotNet/Keys/ProfileSwitcher.cs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
using BarRaider.SdTools;
|
||||||
|
using BarRaider.SdTools.Wrappers;
|
||||||
|
using ClipTrimDotNet.Client;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ClipTrimDotNet.Keys
|
||||||
|
{
|
||||||
|
public class DataSourceItem
|
||||||
|
{
|
||||||
|
public string label { get; set; } = "";
|
||||||
|
public string value { get; set; } = "";
|
||||||
|
}
|
||||||
|
[PluginActionId("com.michal-courson.cliptrim.profile-switcher")]
|
||||||
|
public class ProfileSwitcher : KeypadBase
|
||||||
|
{
|
||||||
|
private class PluginSettings
|
||||||
|
{
|
||||||
|
public static PluginSettings CreateDefaultSettings()
|
||||||
|
{
|
||||||
|
PluginSettings instance = new PluginSettings();
|
||||||
|
instance.ProfileName = null;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "profileName")]
|
||||||
|
public string? ProfileName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Private Members
|
||||||
|
|
||||||
|
private PluginSettings settings;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
public ProfileSwitcher(SDConnection connection, InitialPayload payload) : base(connection, payload)
|
||||||
|
{
|
||||||
|
if (payload.Settings == null || payload.Settings.Count == 0)
|
||||||
|
{
|
||||||
|
settings = PluginSettings.CreateDefaultSettings();
|
||||||
|
SaveSettings();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
settings = payload.Settings.ToObject<PluginSettings>()!;
|
||||||
|
}
|
||||||
|
Logger.Instance.LogMessage(TracingLevel.INFO, $"ProfileSwitcher initialized with payload {JsonConvert.SerializeObject(payload)}");
|
||||||
|
GlobalSettingsManager.Instance.RequestGlobalSettings();
|
||||||
|
Connection.OnSendToPlugin += Connection_OnSendToPlugin;
|
||||||
|
SetTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void SetTitle()
|
||||||
|
{
|
||||||
|
|
||||||
|
await Connection.SetTitleAsync(settings.ProfileName + " B");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Connection_OnSendToPlugin(object? sender, SDEventReceivedEventArgs<BarRaider.SdTools.Events.SendToPlugin> e)
|
||||||
|
{
|
||||||
|
//Logger.Instance.LogMessage(TracingLevel.INFO, "get profiles");
|
||||||
|
if (e.Event.Payload["event"] is null) return;
|
||||||
|
|
||||||
|
if (e.Event.Payload["event"]!.ToString() == "getProfiles")
|
||||||
|
{
|
||||||
|
var files = ClipTrimClient.Instance.GetCollectionNames();
|
||||||
|
var items = files.Select(x => new DataSourceItem { label = x, value = x});
|
||||||
|
var obj = new JObject
|
||||||
|
{
|
||||||
|
["event"] = "getProfiles",
|
||||||
|
["items"] = JArray.FromObject(items)
|
||||||
|
};
|
||||||
|
await Connection.SendToPropertyInspectorAsync(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async void KeyPressed(KeyPayload payload)
|
||||||
|
{
|
||||||
|
GlobalSettings.Instance.SetCurrentProfile(settings.ProfileName??"");
|
||||||
|
|
||||||
|
await Connection.SetGlobalSettingsAsync(JObject.FromObject(GlobalSettings.Instance));
|
||||||
|
await Connection.SwitchProfileAsync("ClipTrim");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void KeyReleased(KeyPayload payload)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnTick()
|
||||||
|
{
|
||||||
|
SetTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReceivedSettings(ReceivedSettingsPayload payload)
|
||||||
|
{
|
||||||
|
Tools.AutoPopulateSettings(settings, payload.Settings);
|
||||||
|
SaveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload)
|
||||||
|
{
|
||||||
|
Tools.AutoPopulateSettings(GlobalSettings.Instance, payload.Settings);
|
||||||
|
//if (payload.Settings == null || payload.Settings.Count == 0)
|
||||||
|
//{
|
||||||
|
// var inst = GlobalSettings.Instance;
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// GlobalSettings.Instance = payload.Settings.ToObject<GlobalSettings>();
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
|
||||||
|
private Task SaveSettings()
|
||||||
|
{
|
||||||
|
return Connection.SetSettingsAsync(JObject.FromObject(settings));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,194 +0,0 @@
|
|||||||
using BarRaider.SdTools;
|
|
||||||
using BarRaider.SdTools.Wrappers;
|
|
||||||
using ClipTrimDotNet.Client;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Dynamic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ClipTrimDotNet
|
|
||||||
{
|
|
||||||
[PluginActionId("com.michal-courson.cliptrim.player")]
|
|
||||||
public class Player : KeypadBase
|
|
||||||
{
|
|
||||||
|
|
||||||
private ClipMetadata? metadata;
|
|
||||||
private KeyCoordinates coordinates;
|
|
||||||
private class PluginSettings
|
|
||||||
{
|
|
||||||
public static PluginSettings CreateDefaultSettings()
|
|
||||||
{
|
|
||||||
PluginSettings instance = new PluginSettings();
|
|
||||||
instance.Path = null;
|
|
||||||
instance.PlayType = "Play/Overlap";
|
|
||||||
instance.Index = 0;
|
|
||||||
instance.Volume = 1;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
[FilenameProperty]
|
|
||||||
[JsonPropertyName("path")]
|
|
||||||
public string? Path { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("index")]
|
|
||||||
public int? Index { get; set; }
|
|
||||||
[JsonPropertyName("playtype")]
|
|
||||||
public string PlayType { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("volume")]
|
|
||||||
public double Volume { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Private Members
|
|
||||||
|
|
||||||
private PluginSettings settings;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
public Player(SDConnection connection, InitialPayload payload) : base(connection, payload)
|
|
||||||
{
|
|
||||||
if (payload.Settings == null || payload.Settings.Count == 0)
|
|
||||||
{
|
|
||||||
this.settings = PluginSettings.CreateDefaultSettings();
|
|
||||||
SaveSettings();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.settings = payload.Settings.ToObject<PluginSettings>();
|
|
||||||
}
|
|
||||||
this.coordinates = payload.Coordinates;
|
|
||||||
GlobalSettingsManager.Instance.RequestGlobalSettings();
|
|
||||||
CheckFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Instance_OnReceivedGlobalSettings(object sender, ReceivedGlobalSettingsPayload e)
|
|
||||||
{
|
|
||||||
Tools.AutoPopulateSettings(GlobalSettings.Instance, e.Settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetIndex()
|
|
||||||
{
|
|
||||||
return Math.Max((coordinates.Row - 1) * 5 + coordinates.Column, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void CheckFile()
|
|
||||||
{
|
|
||||||
|
|
||||||
//if (settings == null || GlobalSettings.Instance.ProfileName ==null) return;
|
|
||||||
metadata = ClipTrimClient.Instance.GetClipByPagedIndex(GetIndex());
|
|
||||||
await Connection.SetTitleAsync($"{metadata?.Name ?? ""}");
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, $"Set title to {metadata?.Name ?? ""}");
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
//var files = Directory.GetFiles(Path.Combine(Path.GetDirectoryName(GlobalSettings.Instance.BasePath), GlobalSettings.Instance.ProfileName), "*.wav", SearchOption.TopDirectoryOnly)
|
|
||||||
// .OrderBy(file => File.GetCreationTime(file))
|
|
||||||
// .ToArray();
|
|
||||||
//int? i = this.settings.Index;
|
|
||||||
//string new_path = "";
|
|
||||||
//if (i != null && i >= 0 && i < files.Length)
|
|
||||||
//{
|
|
||||||
// new_path = files[i ?? 0];
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
//await Connection.SetTitleAsync(Path.GetFileNameWithoutExtension(new_path));
|
|
||||||
//if (new_path != settings.Path)
|
|
||||||
//{
|
|
||||||
// settings.Path = new_path;
|
|
||||||
// if(new_path != "")
|
|
||||||
// {
|
|
||||||
// FileEntry opts = GlobalSettings.Instance.GetFileOptionsInCurrentProfile(new_path);
|
|
||||||
// settings.Volume = opts.Volume;
|
|
||||||
// settings.PlayType = opts.Playtype;
|
|
||||||
// }
|
|
||||||
// await SaveSettings();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private async void Connection_OnApplicationDidLaunch(object sender, BarRaider.SdTools.Wrappers.SDEventReceivedEventArgs<BarRaider.SdTools.Events.ApplicationDidLaunch> e)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Connection_OnTitleParametersDidChange(object sender, SDEventReceivedEventArgs<BarRaider.SdTools.Events.TitleParametersDidChange> e)
|
|
||||||
{
|
|
||||||
//titleParameters = e.Event?.Payload?.TitleParameters;
|
|
||||||
//userTitle = e.Event?.Payload?.Title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Dispose()
|
|
||||||
{
|
|
||||||
Connection.OnTitleParametersDidChange -= Connection_OnTitleParametersDidChange;
|
|
||||||
Connection.OnApplicationDidLaunch -= Connection_OnApplicationDidLaunch;
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, $"Destructor called");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void KeyPressed(KeyPayload payload)
|
|
||||||
{
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, "Key Pressedd");
|
|
||||||
Tools.AutoPopulateSettings(settings, payload.Settings);
|
|
||||||
// Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(settings));
|
|
||||||
ClipTrimClient.Instance.PlayClip(metadata);
|
|
||||||
//try
|
|
||||||
//{
|
|
||||||
// WavPlayer.Instance.Play(settings.Path, GlobalSettings.Instance.OutputDevice, settings.Volume, settings.PlayType == "Play/Overlap" ? WavPlayer.PlayMode.PlayOverlap : WavPlayer.PlayMode.PlayStop);
|
|
||||||
//}
|
|
||||||
//catch
|
|
||||||
//{
|
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void KeyReleased(KeyPayload payload) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void OnTick() {
|
|
||||||
CheckFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async void ReceivedSettings(ReceivedSettingsPayload payload)
|
|
||||||
{
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, "Player rec settings");
|
|
||||||
Tools.AutoPopulateSettings(settings, payload.Settings);
|
|
||||||
GlobalSettings.Instance.SetFileOptionsCurrentProfile(settings.Path, new FileEntry() { Playtype = settings.PlayType, Volume = settings.Volume });
|
|
||||||
await Connection.SetGlobalSettingsAsync(JObject.FromObject(GlobalSettings.Instance));
|
|
||||||
//SaveSettings();
|
|
||||||
//CheckFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload) {
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, "ReceivedGlobalSettings");
|
|
||||||
|
|
||||||
if (payload.Settings == null || payload.Settings.Count == 0)
|
|
||||||
{
|
|
||||||
var inst = GlobalSettings.Instance;
|
|
||||||
//GlobalSettingsManager.Instance.SetGlobalSettings(JObject.FromObject(inst));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GlobalSettings.Instance = payload.Settings.ToObject<GlobalSettings>();
|
|
||||||
}
|
|
||||||
|
|
||||||
//CheckFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Private Methods
|
|
||||||
|
|
||||||
private Task SaveSettings()
|
|
||||||
{
|
|
||||||
return Connection.SetSettingsAsync(JObject.FromObject(settings));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,165 +0,0 @@
|
|||||||
using BarRaider.SdTools;
|
|
||||||
using BarRaider.SdTools.Wrappers;
|
|
||||||
using ClipTrimDotNet.Client;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Dynamic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ClipTrimDotNet
|
|
||||||
{
|
|
||||||
public class DataSourceItem
|
|
||||||
{
|
|
||||||
public string label { get; set; }
|
|
||||||
public string value { get; set; }
|
|
||||||
}
|
|
||||||
[PluginActionId("com.michal-courson.cliptrim.profile-switcher")]
|
|
||||||
public class ProfileSwitcher : KeypadBase
|
|
||||||
{
|
|
||||||
private class PluginSettings
|
|
||||||
{
|
|
||||||
public static PluginSettings CreateDefaultSettings()
|
|
||||||
{
|
|
||||||
PluginSettings instance = new PluginSettings();
|
|
||||||
instance.ProfileName = null;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "profileName")]
|
|
||||||
public string? ProfileName { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Private Members
|
|
||||||
|
|
||||||
private PluginSettings settings;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
public ProfileSwitcher(SDConnection connection, InitialPayload payload) : base(connection, payload)
|
|
||||||
{
|
|
||||||
if (payload.Settings == null || payload.Settings.Count == 0)
|
|
||||||
{
|
|
||||||
this.settings = PluginSettings.CreateDefaultSettings();
|
|
||||||
SaveSettings();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.settings = payload.Settings.ToObject<PluginSettings>();
|
|
||||||
}
|
|
||||||
GlobalSettingsManager.Instance.RequestGlobalSettings();
|
|
||||||
Connection.OnSendToPlugin += Connection_OnSendToPlugin;
|
|
||||||
SetTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void SetTitle()
|
|
||||||
{
|
|
||||||
|
|
||||||
await Connection.SetTitleAsync(settings.ProfileName + " B");
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Connection_OnSendToPlugin(object sender, SDEventReceivedEventArgs<BarRaider.SdTools.Events.SendToPlugin> e)
|
|
||||||
{
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, "get profiles");
|
|
||||||
if (e.Event.Payload["event"].ToString() == "getProfiles")
|
|
||||||
{
|
|
||||||
//string basePath = "C:\\Users\\mickl\\Music\\clips";
|
|
||||||
//var files = Directory.GetDirectories(basePath, "*", SearchOption.TopDirectoryOnly).Select(x => Path.GetFileNameWithoutExtension(x)).Where(x => x != "original");
|
|
||||||
var files = ClipTrimClient.Instance.GetCollectionNames();
|
|
||||||
var items = files.Select(x => new DataSourceItem { label = x, value = x});
|
|
||||||
var obj = new JObject();
|
|
||||||
obj["event"] = "getProfiles";
|
|
||||||
obj["items"] = JArray.FromObject(items);
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, "get profiles return " + JsonConvert.SerializeObject(obj));
|
|
||||||
await Connection.SendToPropertyInspectorAsync(obj);
|
|
||||||
}
|
|
||||||
//if (e.Event.Payload["event"].ToString() == "getOutputDevices")
|
|
||||||
//{
|
|
||||||
// List<WaveOutCapabilities> devices = new List<WaveOutCapabilities>();
|
|
||||||
// for (int n = -1; n < WaveOut.DeviceCount; n++)
|
|
||||||
// {
|
|
||||||
// var caps = WaveOut.GetCapabilities(n);
|
|
||||||
// devices.Add(caps);
|
|
||||||
// }
|
|
||||||
// var items = devices.Select(x => new DataSourceItem { label = x.ProductName, value = x.ProductName });
|
|
||||||
// var obj = new JObject();
|
|
||||||
// obj["event"] = "getOutputDevices";
|
|
||||||
// obj["items"] = JArray.FromObject(items);
|
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, "get devices return " + JsonConvert.SerializeObject(obj));
|
|
||||||
// await Connection.SendToPropertyInspectorAsync(obj);
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Connection_OnTitleParametersDidChange(object sender, SDEventReceivedEventArgs<BarRaider.SdTools.Events.TitleParametersDidChange> e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Dispose()
|
|
||||||
{
|
|
||||||
Connection.OnTitleParametersDidChange -= Connection_OnTitleParametersDidChange;
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, $"Destructor called");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async void KeyPressed(KeyPayload payload)
|
|
||||||
{
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, "KeyPressed");
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(settings));
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(GlobalSettings.Instance));
|
|
||||||
ClipTrimClient.Instance.SetSelectedCollectionByName(settings.ProfileName);
|
|
||||||
GlobalSettings.Instance.SetCurrentProfile(settings.ProfileName);
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(GlobalSettings.Instance));
|
|
||||||
|
|
||||||
await Connection.SetGlobalSettingsAsync(JObject.FromObject(GlobalSettings.Instance));
|
|
||||||
await Connection.SwitchProfileAsync("ClipTrim");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void KeyReleased(KeyPayload payload)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnTick()
|
|
||||||
{
|
|
||||||
SetTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ReceivedSettings(ReceivedSettingsPayload payload)
|
|
||||||
{
|
|
||||||
Tools.AutoPopulateSettings(settings, payload.Settings);
|
|
||||||
SaveSettings();
|
|
||||||
//tTitle();
|
|
||||||
//CheckFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload)
|
|
||||||
{
|
|
||||||
//Logger.Instance.LogMessage(TracingLevel.INFO, "ReceivedGlobalSettings");
|
|
||||||
|
|
||||||
if (payload.Settings == null || payload.Settings.Count == 0)
|
|
||||||
{
|
|
||||||
var inst = GlobalSettings.Instance;
|
|
||||||
//GlobalSettingsManager.Instance.SetGlobalSettings(JObject.FromObject(inst));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GlobalSettings.Instance = payload.Settings.ToObject<GlobalSettings>();
|
|
||||||
}
|
|
||||||
|
|
||||||
//CheckFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Private Methods
|
|
||||||
|
|
||||||
private Task SaveSettings()
|
|
||||||
{
|
|
||||||
return Connection.SetSettingsAsync(JObject.FromObject(settings));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -11,7 +11,7 @@
|
|||||||
<!--
|
<!--
|
||||||
Learn more about property inspector components at https://sdpi-components.dev/docs/components
|
Learn more about property inspector components at https://sdpi-components.dev/docs/components
|
||||||
-->
|
-->
|
||||||
<sdpi-item label="Index">
|
<!--<sdpi-item label="Index">
|
||||||
<sdpi-select setting="index" placeholder="file index">
|
<sdpi-select setting="index" placeholder="file index">
|
||||||
<option value="0">0</option>
|
<option value="0">0</option>
|
||||||
<option value="1">1</option>
|
<option value="1">1</option>
|
||||||
@ -39,7 +39,7 @@
|
|||||||
</sdpi-item>
|
</sdpi-item>
|
||||||
<sdpi-item label="Volume">
|
<sdpi-item label="Volume">
|
||||||
<sdpi-range setting="volume" min=".1" max="1" , step="0.05"></sdpi-range>
|
<sdpi-range setting="volume" min=".1" max="1" , step="0.05"></sdpi-range>
|
||||||
</sdpi-item>
|
</sdpi-item>-->
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
show-refresh="true"
|
show-refresh="true"
|
||||||
placeholder="Select a ClipTrim page"></sdpi-select>
|
placeholder="Select a ClipTrim page"></sdpi-select>
|
||||||
</sdpi-item>
|
</sdpi-item>
|
||||||
<sdpi-item label="Base Path">
|
<!--<sdpi-item label="Base Path">
|
||||||
<sdpi-file setting="basePath"
|
<sdpi-file setting="basePath"
|
||||||
global="true"
|
global="true"
|
||||||
webkitdirectory
|
webkitdirectory
|
||||||
@ -29,6 +29,6 @@
|
|||||||
datasource="getOutputDevices"
|
datasource="getOutputDevices"
|
||||||
show-refresh="true"
|
show-refresh="true"
|
||||||
placeholder="Select an Ouput Device"></sdpi-select>
|
placeholder="Select an Ouput Device"></sdpi-select>
|
||||||
</sdpi-item>
|
</sdpi-item>-->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -1,225 +0,0 @@
|
|||||||
//using System;
|
|
||||||
//using System.Collections.Concurrent;
|
|
||||||
//using System.Collections.Generic;
|
|
||||||
//using System.Linq;
|
|
||||||
//using System.ServiceModel.Security;
|
|
||||||
//using System.Threading.Tasks;
|
|
||||||
//using BarRaider.SdTools;
|
|
||||||
//using NAudio.Wave;
|
|
||||||
//using NAudio.Wave.SampleProviders;
|
|
||||||
//using Newtonsoft.Json;
|
|
||||||
|
|
||||||
//class CachedSound
|
|
||||||
//{
|
|
||||||
// public byte[] AudioData { get; private set; }
|
|
||||||
// public WaveFormat WaveFormat { get; private set; }
|
|
||||||
// public CachedSound(string audioFileName)
|
|
||||||
// {
|
|
||||||
// using (var audioFileReader = new AudioFileReader(audioFileName))
|
|
||||||
// {
|
|
||||||
// // TODO: could add resampling in here if required
|
|
||||||
// WaveFormat = audioFileReader.WaveFormat;
|
|
||||||
// var wholeFile = new List<byte>((int)(audioFileReader.Length));
|
|
||||||
// var readBuffer = new byte[audioFileReader.WaveFormat.SampleRate * audioFileReader.WaveFormat.Channels*4];
|
|
||||||
// int samplesRead;
|
|
||||||
// while ((samplesRead = audioFileReader.Read(readBuffer, 0, readBuffer.Length)) > 0)
|
|
||||||
// {
|
|
||||||
// wholeFile.AddRange(readBuffer.Take(samplesRead));
|
|
||||||
// }
|
|
||||||
// AudioData = wholeFile.ToArray();
|
|
||||||
// }
|
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, $"AudioData Length {AudioData.Length}");
|
|
||||||
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//class CachedSoundSampleProvider : IWaveProvider
|
|
||||||
//{
|
|
||||||
// private readonly CachedSound cachedSound;
|
|
||||||
// private long position;
|
|
||||||
|
|
||||||
// ~CachedSoundSampleProvider() {
|
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, $"Cache destructor");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public CachedSoundSampleProvider(CachedSound cachedSound)
|
|
||||||
// {
|
|
||||||
// this.cachedSound = cachedSound;
|
|
||||||
// position = 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public int Read(byte[] buffer, int offset, int count)
|
|
||||||
// {
|
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, $"Read1 byte");
|
|
||||||
// var availableSamples = cachedSound.AudioData.Length - position;
|
|
||||||
// var samplesToCopy = Math.Min(availableSamples, count);
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, $"{cachedSound.AudioData.GetType()} {buffer.GetType()}");
|
|
||||||
// Array.Copy(cachedSound.AudioData, position, buffer, offset, samplesToCopy);
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, $"{ex.ToString()}");
|
|
||||||
// }
|
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, $"Read3");
|
|
||||||
// position += samplesToCopy;
|
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, $"Sending {samplesToCopy} samples");
|
|
||||||
// return (int)samplesToCopy;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public WaveFormat WaveFormat => cachedSound.WaveFormat;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public class WavPlayer
|
|
||||||
//{
|
|
||||||
// private static WavPlayer? instance;
|
|
||||||
// public static WavPlayer Instance
|
|
||||||
// {
|
|
||||||
// get
|
|
||||||
// {
|
|
||||||
// instance ??= new WavPlayer();
|
|
||||||
// return instance;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
// public enum PlayMode
|
|
||||||
// {
|
|
||||||
// PlayOverlap,
|
|
||||||
// PlayStop
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private readonly ConcurrentDictionary<string, List<Tuple<WaveOutEvent, IWaveProvider>>> _activePlayers;
|
|
||||||
|
|
||||||
// public WavPlayer()
|
|
||||||
// {
|
|
||||||
// _activePlayers = new ConcurrentDictionary<string, List<Tuple<WaveOutEvent, IWaveProvider>>>();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public void Play(string filePath, string id, double volume, PlayMode mode)
|
|
||||||
// {
|
|
||||||
// if (string.IsNullOrWhiteSpace(filePath))
|
|
||||||
// throw new ArgumentException("File path cannot be null or empty.", nameof(filePath));
|
|
||||||
|
|
||||||
// if (mode == PlayMode.PlayOverlap)
|
|
||||||
// {
|
|
||||||
// PlayWithOverlap(filePath, id, volume);
|
|
||||||
// }
|
|
||||||
// else if (mode == PlayMode.PlayStop)
|
|
||||||
// {
|
|
||||||
// PlayWithStop(filePath, id, volume);
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// throw new ArgumentOutOfRangeException(nameof(mode), "Invalid play mode specified.");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private void PlayWithOverlap(string filePath, string id, double volume)
|
|
||||||
// {
|
|
||||||
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, "Play overlap");
|
|
||||||
// var player = CreatePlayer(filePath, id);
|
|
||||||
|
|
||||||
// if (!_activePlayers.ContainsKey(filePath))
|
|
||||||
// {
|
|
||||||
// _activePlayers[filePath] = new List<Tuple<WaveOutEvent, IWaveProvider>>();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// _activePlayers[filePath].Add(player);
|
|
||||||
// player.Item1.Volume = (float)volume;
|
|
||||||
// player.Item1.Play();
|
|
||||||
// }
|
|
||||||
// catch(Exception ex)
|
|
||||||
// {
|
|
||||||
// //Logger.Instance.LogMessage(TracingLevel.INFO, ex.ToString());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// //var playersToDispose = _activePlayers[filePath].Where(x => x.Item1.PlaybackState == PlaybackState.Stopped).ToList();
|
|
||||||
// //foreach (var p in playersToDispose)
|
|
||||||
// //{
|
|
||||||
// // p.Item1.Stop();
|
|
||||||
// // p.Item1.Dispose();
|
|
||||||
// //}
|
|
||||||
// //_activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private void PlayWithStop(string filePath, string id, double volume)
|
|
||||||
// {
|
|
||||||
// if (_activePlayers.TryGetValue(filePath, out var players))
|
|
||||||
// {
|
|
||||||
|
|
||||||
// // Stop and dispose all current players for this file
|
|
||||||
// if (players.Any(x => x.Item1.PlaybackState == PlaybackState.Playing))
|
|
||||||
// {
|
|
||||||
// var playersToDispose = players.ToList();
|
|
||||||
// foreach (var player in playersToDispose)
|
|
||||||
// {
|
|
||||||
// player.Item1.Stop();
|
|
||||||
// player.Item1.Dispose();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// PlayWithOverlap(filePath, id, volume);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// // Start a new player
|
|
||||||
// PlayWithOverlap(filePath, id, volume);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// _activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private Tuple<WaveOutEvent, IWaveProvider> CreatePlayer(string filePath, string name)
|
|
||||||
// {
|
|
||||||
// var reader = new CachedSoundSampleProvider(new CachedSound(filePath));
|
|
||||||
// //var reader = new AudioFileReader(filePath);
|
|
||||||
// int number = -1;
|
|
||||||
// for (int i = 0; i < WaveOut.DeviceCount; ++i)
|
|
||||||
// {
|
|
||||||
// if (WaveOut.GetCapabilities(i).ProductName == name)
|
|
||||||
// {
|
|
||||||
// number = i;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// var player = new WaveOutEvent() { DeviceNumber = number };
|
|
||||||
// player.Init(reader);
|
|
||||||
// return new Tuple<WaveOutEvent, IWaveProvider>(player, reader);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private void CleanupPlayer(string filePath)
|
|
||||||
// {
|
|
||||||
// if (_activePlayers.TryGetValue(filePath, out var players))
|
|
||||||
// {
|
|
||||||
// var playersToDispose = players.ToList();
|
|
||||||
// foreach (var p in playersToDispose)
|
|
||||||
// {
|
|
||||||
// p.Item1.Stop();
|
|
||||||
// p.Item1.Dispose();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// _activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped);
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public void StopAll()
|
|
||||||
// {
|
|
||||||
// foreach (var players in _activePlayers.Values)
|
|
||||||
// {
|
|
||||||
// var playersToDispose = players.ToList();
|
|
||||||
// foreach (var player in playersToDispose)
|
|
||||||
// {
|
|
||||||
// player.Item1.Stop();
|
|
||||||
// player.Item1.Dispose();
|
|
||||||
// }
|
|
||||||
// players.Clear();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// _activePlayers.Clear();
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@ -30,6 +30,36 @@
|
|||||||
"Tooltip": "Selects which sub folder to use and opens effect profile",
|
"Tooltip": "Selects which sub folder to use and opens effect profile",
|
||||||
"UUID": "com.michal-courson.cliptrim.profile-switcher",
|
"UUID": "com.michal-courson.cliptrim.profile-switcher",
|
||||||
"PropertyInspectorPath": "PropertyInspector/profile_swticher.html"
|
"PropertyInspectorPath": "PropertyInspector/profile_swticher.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Icon": "Images/icon",
|
||||||
|
"Name": "Page Navigator",
|
||||||
|
"States": [
|
||||||
|
{
|
||||||
|
"Image": "Images/pluginAction",
|
||||||
|
"TitleAlignment": "middle",
|
||||||
|
"FontSize": 16
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SupportedInMultiActions": false,
|
||||||
|
"Tooltip": "Navigates pages",
|
||||||
|
"UUID": "com.michal-courson.cliptrim.page-navigator",
|
||||||
|
"PropertyInspectorPath": "PropertyInspector/file_player.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Icon": "Images/icon",
|
||||||
|
"Name": "Save Clip",
|
||||||
|
"States": [
|
||||||
|
{
|
||||||
|
"Image": "Images/pluginAction",
|
||||||
|
"TitleAlignment": "middle",
|
||||||
|
"FontSize": 16
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SupportedInMultiActions": false,
|
||||||
|
"Tooltip": "Saves the current clip",
|
||||||
|
"UUID": "com.michal-courson.cliptrim.clip-save",
|
||||||
|
"PropertyInspectorPath": "PropertyInspector/file_player.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Author": "Michal Courson",
|
"Author": "Michal Courson",
|
||||||
|
|||||||
Reference in New Issue
Block a user