allow playing mid with external player

This commit is contained in:
josc146 2023-12-12 22:13:09 +08:00
parent b14fbc29b7
commit 0c796c8cfc
11 changed files with 113 additions and 25 deletions

View File

@ -68,6 +68,7 @@ jobs:
del ./backend-python/rwkv_pip/cpp/librwkv.dylib del ./backend-python/rwkv_pip/cpp/librwkv.dylib
del ./backend-python/rwkv_pip/cpp/librwkv.so del ./backend-python/rwkv_pip/cpp/librwkv.so
(Get-Content -Path ./backend-golang/app.go) -replace "//go:custom_build windows ", "" | Set-Content -Path ./backend-golang/app.go (Get-Content -Path ./backend-golang/app.go) -replace "//go:custom_build windows ", "" | Set-Content -Path ./backend-golang/app.go
(Get-Content -Path ./backend-golang/utils.go) -replace "//go:custom_build windows ", "" | Set-Content -Path ./backend-golang/utils.go
make make
Rename-Item -Path "build/bin/RWKV-Runner.exe" -NewName "RWKV-Runner_windows_x64.exe" Rename-Item -Path "build/bin/RWKV-Runner.exe" -NewName "RWKV-Runner_windows_x64.exe"

1
.gitignore vendored
View File

@ -8,6 +8,7 @@ __pycache__
*.st *.st
*.safetensors *.safetensors
*.bin *.bin
*.mid
/config.json /config.json
/cache.json /cache.json
/presets.json /presets.json

View File

@ -14,6 +14,13 @@ import (
wruntime "github.com/wailsapp/wails/v2/pkg/runtime" wruntime "github.com/wailsapp/wails/v2/pkg/runtime"
) )
func (a *App) SaveFile(path string, savedContent []byte) error {
if err := os.WriteFile(a.exDir+path, savedContent, 0644); err != nil {
return err
}
return nil
}
func (a *App) SaveJson(fileName string, jsonData any) error { func (a *App) SaveJson(fileName string, jsonData any) error {
text, err := json.MarshalIndent(jsonData, "", " ") text, err := json.MarshalIndent(jsonData, "", " ")
if err != nil { if err != nil {
@ -195,3 +202,8 @@ func (a *App) OpenFileFolder(path string, relative bool) error {
} }
return errors.New("unsupported OS") return errors.New("unsupported OS")
} }
func (a *App) StartFile(path string) error {
_, err := CmdHelper(path)
return err
}

View File

@ -15,33 +15,51 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"syscall"
) )
func Cmd(args ...string) (string, error) { func CmdHelper(args ...string) (*exec.Cmd, error) {
switch platform := runtime.GOOS; platform { if runtime.GOOS != "windows" {
case "windows": return nil, errors.New("unsupported OS")
if err := os.WriteFile("./cmd-helper.bat", []byte("start %*"), 0644); err != nil {
return "", err
} }
cmdHelper, err := filepath.Abs("./cmd-helper") filename := "./cmd-helper.bat"
_, err := os.Stat(filename)
if err != nil { if err != nil {
return "", err if err := os.WriteFile(filename, []byte("start %*"), 0644); err != nil {
return nil, err
}
}
cmdHelper, err := filepath.Abs(filename)
if err != nil {
return nil, err
} }
if strings.Contains(cmdHelper, " ") { if strings.Contains(cmdHelper, " ") {
for _, arg := range args { for _, arg := range args {
if strings.Contains(arg, " ") { if strings.Contains(arg, " ") {
return "", errors.New("path contains space") // golang bug https://github.com/golang/go/issues/17149#issuecomment-473976818 return nil, errors.New("path contains space") // golang bug https://github.com/golang/go/issues/17149#issuecomment-473976818
} }
} }
} }
cmd := exec.Command(cmdHelper, args...) cmd := exec.Command(cmdHelper, args...)
out, err := cmd.CombinedOutput() cmd.SysProcAttr = &syscall.SysProcAttr{}
//go:custom_build windows cmd.SysProcAttr.HideWindow = true
err = cmd.Start()
if err != nil {
return nil, err
}
return cmd, nil
}
func Cmd(args ...string) (string, error) {
switch platform := runtime.GOOS; platform {
case "windows":
cmd, err := CmdHelper(args...)
if err != nil { if err != nil {
return "", err return "", err
} }
return string(out), nil cmd.Wait()
return "", nil
case "darwin": case "darwin":
ex, err := os.Executable() ex, err := os.Executable()
if err != nil { if err != nil {

View File

@ -316,5 +316,6 @@
"Current Instrument": "現在の楽器", "Current Instrument": "現在の楽器",
"Please convert model to GGML format first": "モデルをGGML形式に変換してください", "Please convert model to GGML format first": "モデルをGGML形式に変換してください",
"Convert To GGML Format": "GGML形式に変換", "Convert To GGML Format": "GGML形式に変換",
"CPU (rwkv.cpp, Faster)": "CPU (rwkv.cpp, 高速)" "CPU (rwkv.cpp, Faster)": "CPU (rwkv.cpp, 高速)",
"Play With External Player": "外部プレーヤーで再生"
} }

View File

@ -316,5 +316,6 @@
"Current Instrument": "当前乐器", "Current Instrument": "当前乐器",
"Please convert model to GGML format first": "请先将模型转换为GGML格式", "Please convert model to GGML format first": "请先将模型转换为GGML格式",
"Convert To GGML Format": "转换为GGML格式", "Convert To GGML Format": "转换为GGML格式",
"CPU (rwkv.cpp, Faster)": "CPU (rwkv.cpp, 更快)" "CPU (rwkv.cpp, Faster)": "CPU (rwkv.cpp, 更快)",
"Play With External Player": "使用外部播放器播放"
} }

View File

@ -21,7 +21,9 @@ import {
FileExists, FileExists,
OpenFileFolder, OpenFileFolder,
OpenMidiPort, OpenMidiPort,
OpenSaveFileDialogBytes OpenSaveFileDialogBytes,
SaveFile,
StartFile
} from '../../wailsjs/go/backend_golang/App'; } from '../../wailsjs/go/backend_golang/App';
import { getServerRoot, getSoundFont, toastWithButton } from '../utils'; import { getServerRoot, getSoundFont, toastWithButton } from '../utils';
import { CompositionParams } from '../types/composition'; import { CompositionParams } from '../types/composition';
@ -98,6 +100,31 @@ const CompositionPanel: FC = observer(() => {
} }
}, []); }, []);
const externalPlayListener = () => {
const params = commonStore.compositionParams;
const saveAndPlay = async (midi: ArrayBuffer, path: string) => {
await SaveFile(path, Array.from(new Uint8Array(midi)));
StartFile(path);
};
if (params.externalPlay) {
if (params.midi) {
setTimeout(() => {
playerRef.current?.stop();
});
saveAndPlay(params.midi, './midi/last.mid').catch((e: string) => {
if (e.includes('being used'))
saveAndPlay(params.midi!, './midi/last-2.mid');
});
}
}
};
useEffect(() => {
playerRef.current?.addEventListener('start', externalPlayListener);
return () => {
playerRef.current?.removeEventListener('start', externalPlayListener);
};
}, [params.externalPlay]);
useEffect(() => { useEffect(() => {
if (!(commonStore.activeMidiDeviceIndex in commonStore.midiPorts)) { if (!(commonStore.activeMidiDeviceIndex in commonStore.midiPorts)) {
commonStore.setActiveMidiDeviceIndex(-1); commonStore.setActiveMidiDeviceIndex(-1);
@ -123,6 +150,9 @@ const CompositionPanel: FC = observer(() => {
}); });
updateNs(ns); updateNs(ns);
if (autoPlay) { if (autoPlay) {
if (commonStore.compositionParams.externalPlay)
externalPlayListener();
else
setTimeout(() => { setTimeout(() => {
playerRef.current?.start(); playerRef.current?.start();
}); });
@ -268,6 +298,16 @@ const CompositionPanel: FC = observer(() => {
setSoundFont(); setSoundFont();
}} /> }} />
} }
{
commonStore.platform === 'windows' &&
<Checkbox className="select-none"
size="large" label={t('Play With External Player')} checked={params.externalPlay}
onChange={async (_, data) => {
setParams({
externalPlay: data.checked as boolean
});
}} />
}
<Checkbox className="select-none" <Checkbox className="select-none"
size="large" label={t('Auto Play At The End')} checked={params.autoPlay} onChange={(_, data) => { size="large" label={t('Auto Play At The End')} checked={params.autoPlay} onChange={(_, data) => {
setParams({ setParams({

View File

@ -94,6 +94,7 @@ class CommonStore {
topP: 0.8, topP: 0.8,
autoPlay: true, autoPlay: true,
useLocalSoundFont: false, useLocalSoundFont: false,
externalPlay: false,
midi: null, midi: null,
ns: null ns: null
}; };

View File

@ -9,6 +9,7 @@ export type CompositionParams = {
topP: number, topP: number,
autoPlay: boolean, autoPlay: boolean,
useLocalSoundFont: boolean, useLocalSoundFont: boolean,
externalPlay: boolean,
midi: ArrayBuffer | null, midi: ArrayBuffer | null,
ns: NoteSequence | null ns: NoteSequence | null
} }

View File

@ -58,8 +58,12 @@ export function ReadJson(arg1:string):Promise<any>;
export function RestartApp():Promise<void>; export function RestartApp():Promise<void>;
export function SaveFile(arg1:string,arg2:Array<number>):Promise<void>;
export function SaveJson(arg1:string,arg2:any):Promise<void>; export function SaveJson(arg1:string,arg2:any):Promise<void>;
export function StartFile(arg1:string):Promise<void>;
export function StartServer(arg1:string,arg2:number,arg3:string,arg4:boolean,arg5:boolean,arg6:boolean):Promise<string>; export function StartServer(arg1:string,arg2:number,arg3:string,arg4:boolean,arg5:boolean,arg6:boolean):Promise<string>;
export function StartWebGPUServer(arg1:number,arg2:string):Promise<string>; export function StartWebGPUServer(arg1:number,arg2:string):Promise<string>;

View File

@ -114,10 +114,18 @@ export function RestartApp() {
return window['go']['backend_golang']['App']['RestartApp'](); return window['go']['backend_golang']['App']['RestartApp']();
} }
export function SaveFile(arg1, arg2) {
return window['go']['backend_golang']['App']['SaveFile'](arg1, arg2);
}
export function SaveJson(arg1, arg2) { export function SaveJson(arg1, arg2) {
return window['go']['backend_golang']['App']['SaveJson'](arg1, arg2); return window['go']['backend_golang']['App']['SaveJson'](arg1, arg2);
} }
export function StartFile(arg1) {
return window['go']['backend_golang']['App']['StartFile'](arg1);
}
export function StartServer(arg1, arg2, arg3, arg4, arg5, arg6) { export function StartServer(arg1, arg2, arg3, arg4, arg5, arg6) {
return window['go']['backend_golang']['App']['StartServer'](arg1, arg2, arg3, arg4, arg5, arg6); return window['go']['backend_golang']['App']['StartServer'](arg1, arg2, arg3, arg4, arg5, arg6);
} }