|
| 1 | +import os |
| 2 | + |
| 3 | +import uiautomation as auto |
| 4 | + |
| 5 | +import keybd |
| 6 | +import log |
| 7 | +import verify |
| 8 | +import singers |
| 9 | + |
| 10 | +logger = log.logger |
| 11 | + |
| 12 | + |
| 13 | +def new_project(singer: str = None): |
| 14 | + """ |
| 15 | + 新建工程。X Studio 必须已处于启动状态。 |
| 16 | + :param singer: 可指定新工程的初始歌手 |
| 17 | + """ |
| 18 | + keybd.key_down(17) |
| 19 | + keybd.key_press(78) |
| 20 | + keybd.key_up(17) |
| 21 | + confirm_window = auto.WindowControl(searchDepth=1, Name='X Studio') |
| 22 | + if confirm_window.Exists(maxSearchSeconds=1): |
| 23 | + confirm_window.ButtonControl(searchDepth=1, AutomationId='NoBtn').Click(simulateMove=False) |
| 24 | + if singer: |
| 25 | + track_window = auto.WindowControl(searchDepth=1, RegexName='X Studio .*').CustomControl(searchDepth=1, ClassName='TrackWin') |
| 26 | + track_window.CustomControl(searchDepth=2, ClassName='TrackChannelControlPanel').ButtonControl(searchDepth=2, AutomationId='switchSingerButton').DoubleClick(simulateMove=False) |
| 27 | + singers.choose_singer(singer) |
| 28 | + logger.info('创建新工程,初始歌手:%s。' % singer) |
| 29 | + else: |
| 30 | + logger.info('创建新工程。') |
| 31 | + |
| 32 | + |
| 33 | +def open_project(filename: str, folder: str = None): |
| 34 | + """ |
| 35 | + 打开工程。X Studio 必须已处于启动状态。 |
| 36 | + :param filename: 工程文件名 |
| 37 | + :param folder: 工程所处文件夹路径,默认为 X Studio 上一次打开工程的路径 |
| 38 | + """ |
| 39 | + if folder: |
| 40 | + project = os.path.abspath(os.path.join(folder, filename)) |
| 41 | + if not os.path.exists(project): |
| 42 | + logger.error('工程文件不存在。') |
| 43 | + exit(1) |
| 44 | + else: |
| 45 | + project = filename |
| 46 | + if not filename.endswith('.svip'): |
| 47 | + logger.error('不是一个可打开的 X Studio 工程 (.svip) 文件。') |
| 48 | + exit(1) |
| 49 | + keybd.key_down(17) |
| 50 | + keybd.key_press(79) |
| 51 | + keybd.key_up(17) |
| 52 | + confirm_window = auto.WindowControl(searchDepth=1, Name='X Studio') |
| 53 | + if confirm_window.Exists(maxSearchSeconds=1): |
| 54 | + confirm_window.ButtonControl(searchDepth=1, AutomationId='NoBtn').Click(simulateMove=False) |
| 55 | + main_window = auto.WindowControl(searchDepth=1, RegexName='X Studio .*') |
| 56 | + open_window = main_window.WindowControl(searchDepth=1, Name='打开文件') |
| 57 | + open_window.EditControl(searchDepth=3, Name='文件名(N):').GetValuePattern().SetValue(project) |
| 58 | + open_window.ButtonControl(searchDepth=1, Name='打开(O)').Click(simulateMove=False) |
| 59 | + warning_window = open_window.WindowControl(searchDepth=1, ClassName='#32770') |
| 60 | + if warning_window.Exists(maxSearchSeconds=1): |
| 61 | + warning = warning_window.TextControl(searchDepth=2).Name |
| 62 | + warning_window.ButtonControl(searchDepth=2, Name='确定').Click(simulateMove=False) |
| 63 | + open_window.ButtonControl(searchDepth=1, Name='取消').Click(simulateMove=False) |
| 64 | + logger.error(warning.replace('\r\n', ' ').replace('。 ', '。')) |
| 65 | + exit(1) |
| 66 | + verify.verify_opening(main_window) |
| 67 | + logger.info('打开工程:%s。' % project) |
| 68 | + |
| 69 | + |
| 70 | +def export_project(title: str = None, folder: str = None, format: str = 'mp3', samplerate: int = 48000): |
| 71 | + """ |
| 72 | + 导出当前打开的工程。 |
| 73 | + :param title: 目标文件名,默认与工程同名 |
| 74 | + :param folder: 目标文件夹路径,默认为工程所在文件夹 |
| 75 | + :param format: 导出格式 (mp3/wav/midi),默认为 mp3 |
| 76 | + :param samplerate: 采样率 (48000/44100),默认为 48000 |
| 77 | + """ |
| 78 | + if format not in ['mp3', 'wav', 'midi']: |
| 79 | + logger.error('只能保存为 mp3, wav 或 midi 格式。') |
| 80 | + exit(1) |
| 81 | + if format == 'midi': |
| 82 | + samplerate = None |
| 83 | + elif samplerate != 48000 and samplerate != 44100: |
| 84 | + logger.error('采样率只能为 48000 或 44100。') |
| 85 | + exit(1) |
| 86 | + if folder and not os.path.exists(folder): |
| 87 | + folder = folder.replace('/', '\\') |
| 88 | + os.makedirs(folder) |
| 89 | + auto.ButtonControl(searchDepth=2, Name='导出').Click(simulateMove=False) |
| 90 | + setting_window = auto.WindowControl(searchDepth=2, Name='导出设置') |
| 91 | + if title: |
| 92 | + setting_window.EditControl(searchDepth=1, AutomationId='FileNameTbx').GetValuePattern().SetValue(title) |
| 93 | + else: |
| 94 | + title = setting_window.EditControl(searchDepth=1, AutomationId='FileNameTbx').GetValuePattern().Value |
| 95 | + if folder: |
| 96 | + logger.warning('当前尚不支持指定导出文件夹路径。') |
| 97 | + setting_window.EditControl(searchDepth=1, AutomationId='DestTbx').SendKeys(folder, interval=0.05) |
| 98 | + if format != 'mp3': |
| 99 | + format_box = setting_window.ComboBoxControl(searchDepth=1, AutomationId='FormatComboBox') |
| 100 | + format_box.Click(simulateMove=False) |
| 101 | + if format == 'wav': |
| 102 | + format_box.ListItemControl(searchDepth=1, Name='WAVE文件').Click(simulateMove=False) |
| 103 | + else: |
| 104 | + format_box.ListItemControl(searchDepth=1, Name='Midi文件').Click(simulateMove=False) |
| 105 | + if samplerate == 44100: |
| 106 | + samplerate_box = setting_window.ComboBoxControl(searchDepth=1, AutomationId='SampleRateComboBox') |
| 107 | + samplerate_box.Click(simulateMove=False) |
| 108 | + samplerate_box.ListItemControl(searchDepth=1, Name='44100HZ').Click(simulateMove=False) |
| 109 | + setting_window.ButtonControl(searchDepth=1, Name='导出').Click(simulateMove=False) |
| 110 | + export_window = auto.WindowControl(searchDepth=2, RegexName='导出.*') |
| 111 | + label = export_window.TextControl(searchDepth=1, ClassName='TextBlock', AutomationId='label') |
| 112 | + while True: |
| 113 | + message_window = auto.WindowControl(searchDepth=2, ClassName='#32770') |
| 114 | + if message_window.Exists(maxSearchSeconds=1): |
| 115 | + message = message_window.TextControl(searchDepth=1, ClassName='Static').Name |
| 116 | + message_window.ButtonControl(searchDepth=1, Name='确定').Click(simulateMove=False) |
| 117 | + logger.error(message + '。') |
| 118 | + exit(1) |
| 119 | + if label.Name == '导出成功': |
| 120 | + break |
| 121 | + elif label.Name.startswith('导出失败'): |
| 122 | + logger.error('导出失败,请稍后再试。') |
| 123 | + exit(1) |
| 124 | + export_window.ButtonControl(searchDepth=1, AutomationId='okBtn').Click(simulateMove=False) |
| 125 | + logger.info('导出工程:%s, 格式 %s, 采样率 %d Hz。' % (title, format, samplerate)) |
| 126 | + |
| 127 | + |
| 128 | +def save_project(filename: str = None, folder: str = None): |
| 129 | + """ |
| 130 | + 保存或另存为当前打开的工程。 |
| 131 | + :param filename: 另存为的工程文件名 |
| 132 | + :param folder: 另存为的文件夹路径,默认为工程所在文件夹 |
| 133 | + """ |
| 134 | + if folder: |
| 135 | + if not filename: |
| 136 | + logger.error('另存为工程时必须指定文件名。') |
| 137 | + exit(1) |
| 138 | + if not os.path.exists(folder): |
| 139 | + os.makedirs(folder) |
| 140 | + folder = os.path.abspath(folder.replace('/', '\\')) |
| 141 | + if not filename: |
| 142 | + keybd.key_down(17) |
| 143 | + keybd.key_press(83) |
| 144 | + keybd.key_up(17) |
| 145 | + logger.info('保存工程。') |
| 146 | + else: |
| 147 | + if folder: |
| 148 | + project = os.path.join(folder, filename) |
| 149 | + else: |
| 150 | + project = filename |
| 151 | + keybd.key_down(17) |
| 152 | + keybd.key_down(16) |
| 153 | + keybd.key_press(83) |
| 154 | + keybd.key_up(16) |
| 155 | + keybd.key_up(17) |
| 156 | + save_window = auto.WindowControl(searchDepth=1, RegexName='X Studio .*').WindowControl(searchDepth=1, Name='另存为') |
| 157 | + save_window.EditControl(searchDepth=6, Name='文件名:').GetValuePattern().SetValue(project) |
| 158 | + save_window.ButtonControl(searchDepth=1, Name='保存(S)').Click(simulateMove=False) |
| 159 | + confirm_window = save_window.WindowControl(searchDepth=1, ClassName='#32770') |
| 160 | + if confirm_window.Exists(maxSearchSeconds=1): |
| 161 | + warning = confirm_window.TextControl(searchDepth=2).Name |
| 162 | + if warning.endswith('是否替换它?'): |
| 163 | + confirm_window.ButtonControl(searchDepth=1, Name='是(Y)').Click(simulateMove=False) |
| 164 | + else: |
| 165 | + confirm_window.ButtonControl(searchDepth=2, Name='确定').Click(simulateMove=False) |
| 166 | + save_window.ButtonControl(searchDepth=1, Name='取消').Click(simulateMove=False) |
| 167 | + logger.error(warning.replace('\r\n', ' ').replace('。 ', '。')) |
| 168 | + exit(1) |
| 169 | + logger.info('另存为工程:%s。' % project) |
0 commit comments