diff --git a/src/VoicevoxCoreSharp.Core/Synthesizer.cs b/src/VoicevoxCoreSharp.Core/Synthesizer.cs index efe41fb..208e7ae 100644 --- a/src/VoicevoxCoreSharp.Core/Synthesizer.cs +++ b/src/VoicevoxCoreSharp.Core/Synthesizer.cs @@ -68,16 +68,22 @@ public ResultCode LoadVoiceModel(VoiceModelFile voiceModel) } } - public ResultCode UnloadVoiceModel(string modelId) + public ResultCode UnloadVoiceModel(VoiceModelId modelId) { unsafe { - fixed (byte* ptr = NativeUuid.ToUUIDv4ByteArray(modelId)) + fixed (byte* ptr = NativeUuid.ToUUIDv4ByteArray(modelId.Id)) { return CoreUnsafe.voicevox_synthesizer_unload_voice_model((VoicevoxSynthesizer*)Handle, ptr).FromNative(); } } } + + // For backward compatibility + public ResultCode UnloadVoiceModel(string modelId) + { + return UnloadVoiceModel(new VoiceModelId(modelId)); + } public bool IsGpuMode { @@ -90,16 +96,22 @@ public bool IsGpuMode } } - public bool IsLoadedVoiceModel(string modelId) + public bool IsLoadedVoiceModel(VoiceModelId modelId) { unsafe { - fixed (byte* ptr = NativeUuid.ToUUIDv4ByteArray(modelId)) + fixed (byte* ptr = NativeUuid.ToUUIDv4ByteArray(modelId.Id)) { return CoreUnsafe.voicevox_synthesizer_is_loaded_voice_model((VoicevoxSynthesizer*)Handle, ptr); } } } + + // For backward compatibility + public bool IsLoadedVoiceModel(string modelId) + { + return IsLoadedVoiceModel(new VoiceModelId(modelId)); + } public string MetasJson { diff --git a/src/VoicevoxCoreSharp.Core/VoiceModel.cs b/src/VoicevoxCoreSharp.Core/VoiceModel.cs index f47b34a..b824a12 100644 --- a/src/VoicevoxCoreSharp.Core/VoiceModel.cs +++ b/src/VoicevoxCoreSharp.Core/VoiceModel.cs @@ -34,21 +34,21 @@ public class VoiceModelFile : IDisposable internal VoiceModelFileHandle Handle { get; private set; } private bool _disposed = false; - public string Id { get; private set; } + public VoiceModelId Id { get; private set; } public string MetasJson { get; private set; } private VoiceModelFile() { Handle = new VoiceModelFileHandle(IntPtr.Zero); - Id = string.Empty; + Id = new VoiceModelId(string.Empty); MetasJson = string.Empty; } private unsafe VoiceModelFile(VoicevoxVoiceModelFile* modelHandle, string id, string metasJson) { Handle = new VoiceModelFileHandle(new IntPtr(modelHandle)); - Id = id; + Id = new VoiceModelId(id); MetasJson = metasJson; } diff --git a/src/VoicevoxCoreSharp.Core/VoiceModelId.cs b/src/VoicevoxCoreSharp.Core/VoiceModelId.cs new file mode 100644 index 0000000..44b5e53 --- /dev/null +++ b/src/VoicevoxCoreSharp.Core/VoiceModelId.cs @@ -0,0 +1,16 @@ +using System; + +namespace VoicevoxCoreSharp.Core +{ + public record VoiceModelId(string Id) + { + // Target framework is netstandard2.0, so init-only properties not available + public string Id { get; } = Id; + + public static implicit operator string(VoiceModelId id) => id.Id; + + public static implicit operator VoiceModelId(string id) => new VoiceModelId(id); + + public override string ToString() => Id; + } +} \ No newline at end of file diff --git a/tests/VoicevoxCoreSharp.Core.Tests/SynthesizerTest.cs b/tests/VoicevoxCoreSharp.Core.Tests/SynthesizerTest.cs index 2aa1938..8c6b803 100644 --- a/tests/VoicevoxCoreSharp.Core.Tests/SynthesizerTest.cs +++ b/tests/VoicevoxCoreSharp.Core.Tests/SynthesizerTest.cs @@ -49,6 +49,7 @@ public void VoiceModelLoaded() VoiceModelFile.Open(Consts.SampleVoiceModel, out var voiceModel); synthesizer.LoadVoiceModel(voiceModel); + // The IsLoadedVoiceModel and UnloadVoiceModel methods should work with the VoiceModelId type Assert.True(synthesizer.IsLoadedVoiceModel(voiceModel.Id)); synthesizer.UnloadVoiceModel(voiceModel.Id); Assert.False(synthesizer.IsLoadedVoiceModel(voiceModel.Id)); diff --git a/tests/VoicevoxCoreSharp.Core.Tests/VoiceModelIdTest.cs b/tests/VoicevoxCoreSharp.Core.Tests/VoiceModelIdTest.cs new file mode 100644 index 0000000..1bfb146 --- /dev/null +++ b/tests/VoicevoxCoreSharp.Core.Tests/VoiceModelIdTest.cs @@ -0,0 +1,38 @@ +using System; +using Xunit; + +namespace VoicevoxCoreSharp.Core.Tests +{ + public class VoiceModelIdTest + { + [Fact] + public void CreateAndConvertToString() + { + var id = new VoiceModelId("test-id"); + Assert.Equal("test-id", id.Id); + Assert.Equal("test-id", id.ToString()); + + // Test implicit conversion to string + string idString = id; + Assert.Equal("test-id", idString); + } + + [Fact] + public void CreateFromString() + { + VoiceModelId id = "test-id"; + Assert.Equal("test-id", id.Id); + } + + [Fact] + public void Equality() + { + var id1 = new VoiceModelId("test-id"); + var id2 = new VoiceModelId("test-id"); + var id3 = new VoiceModelId("different-id"); + + Assert.Equal(id1, id2); + Assert.NotEqual(id1, id3); + } + } +} \ No newline at end of file diff --git a/tests/VoicevoxCoreSharp.Core.Tests/VoiceModelTest.cs b/tests/VoicevoxCoreSharp.Core.Tests/VoiceModelTest.cs index 954743b..101ac81 100644 --- a/tests/VoicevoxCoreSharp.Core.Tests/VoiceModelTest.cs +++ b/tests/VoicevoxCoreSharp.Core.Tests/VoiceModelTest.cs @@ -13,7 +13,7 @@ public void Open() Assert.Equal(ResultCode.RESULT_OK, openResult); Assert.NotNull(voiceModel); - Assert.NotEmpty(voiceModel.Id); + Assert.NotEmpty(voiceModel.Id.Id); Assert.NotEmpty(voiceModel.MetasJson); } @@ -23,10 +23,10 @@ public void AccessMemberAfterDisposed() var _ = VoiceModelFile.Open(Consts.SampleVoiceModel, out var voiceModel); using (voiceModel) { } - Assert.NotEmpty(voiceModel.Id); + Assert.NotEmpty(voiceModel.Id.Id); Assert.NotEmpty(voiceModel.MetasJson); - Assert.True(voiceModel.Id.Length > 0); + Assert.True(voiceModel.Id.Id.Length > 0); Assert.True(voiceModel.MetasJson.Length > 0); } }