Page MenuHomePhabricator

No OneTemporary

diff --git a/AutoCoverTool/online/inference_one.py b/AutoCoverTool/online/inference_one.py
index a59619e..d1cde10 100644
--- a/AutoCoverTool/online/inference_one.py
+++ b/AutoCoverTool/online/inference_one.py
@@ -1,712 +1,713 @@
"""
单个处理的逻辑
song_id:
---src.mp3 // 源数据,需要提前放进去
---cache
---vocal.wav // 分离之后产生
---acc.wav // 分离之后产生
---vocal_32.wav // 分离之后产生
---song_id_sp1.wav // 合成之后产生
---song_id_sp2.wav // 合成之后产生
---song_id_sp2_d.wav // 降噪之后生成
---song_id_sp2_dv.wav // 降噪+拉伸之后产生 [占比太高的不产生]
---song_id_sp2_dve442.wav // 手动调整之后产生
---song_id_sp2_dve442_replace.wav // 替换之后产生
---song_id_sp2_dve442_replace_mix.wav // 人声+伴奏混合之后产生
---song_id
--acc.mp3 // 44k双声道320k
--vocal.mp3 // 44k双声道320k
--src.mp3 // 44k双声道320k
--song_id_sp2_dv.mp3 // 44k单声道320k
---song_id_out // 对外输出
--src.mp3 // 原始音频
--song_id_sp2_dv_replace_mix.mp3 // 制作完成的音频
环境安装:
conda create -n auto_song_cover python=3.9
# 安装demucs环境[进入到ref.music_remover 执行pip install -r requirements.txt]
# 安装so_vits_svc环境[进入到ref.so_vits_svc 执行pip install -r requirements.txt]
pip install librosa
pip install scikit-maad
pip install praat-parselmouth
pip install matplotlib
pip install torchvision
pip install madmom
pip install torchstat
环境设置:
export PATH=$PATH:/data/gpu_env_common/env/bin/ffmpeg/bin
export PYTHONPATH=$PWD:$PWD/ref/music_remover/demucs:$PWD/ref/so_vits_svc:$PWD/ref/split_dirty_frame
"""
import os
import time
import shutil
import random
import logging
import librosa
logging.basicConfig(filename='/tmp/inference.log', level=logging.INFO)
gs_err_code_success = 0
gs_err_code_no_src_mp3 = 1
gs_err_code_separate = 2
gs_err_code_trans_32 = 3
gs_err_code_encode_err = 4
gs_err_code_replace_err = 5
gs_err_code_replace_trans_err = 6
gs_err_code_mix_err = 7
gs_err_code_mix_transcode_err = 8
gs_err_code_no_src_dir = 9
gs_err_code_volume_err = 10
gs_err_code_trans2_442 = 11
gs_err_code_reverb = 12
gs_err_code_no_good_choice = 13
gs_err_code_preprocess_vocal = 14
gs_err_code_replace_except_err = 15
gs_denoise_exe = "/opt/soft/bin/denoise_exe"
gs_draw_volume_exe = "/opt/soft/bin/draw_volume"
gs_simple_mixer_path = "/opt/soft/bin/simple_mixer"
gs_rever_path = "/opt/soft/bin/dereverbrate"
from ref.music_remover.separate_interface import SeparateInterface
from ref.so_vits_svc.inference_main import *
from ref.split_dirty_frame.script.process_one import ReplaceVocalFrame, construct_power_fragment
class SongCoverInference:
def __init__(self):
self.work_dir = None
self.cache_dir = None
self.cid = None
self.src_mp3 = None
self.vocal_path = None
self.vocal_32_path = None
self.acc_path = None
self.speakers = [
10414574138721494,
10414574140317353,
1688849864840588,
3634463651,
5629499489839033,
5910973794723621,
6755399374234747,
8162774327817435,
8162774329368194,
1125899914308640, # 以下为男声,包括这个
12384898975368914,
12947848931397021,
3096224748076687,
3096224751151928,
5066549357604730,
5348024335101054,
6755399442719465,
7036874421386111
]
self.speakers2gender = {
10414574138721494: 2,
10414574140317353: 2,
1688849864840588: 2,
3634463651: 2,
5629499489839033: 2,
5910973794723621: 2,
6755399374234747: 2,
8162774327817435: 2,
8162774329368194: 2,
1125899914308640: 1, # 1是男
12384898975368914: 1,
12947848931397021: 1,
3096224748076687: 1,
3096224751151928: 1,
5066549357604730: 1,
5348024335101054: 1,
6755399442719465: 1,
7036874421386111: 1
}
self.speakers_model_path = "data/train_users/{}/logs/32k/G_2000.pth"
self.speakers_model_config = "data/train_users/{}/config/config.json"
st = time.time()
self.separate_inst = None
logging.info("post process ... ReplaceVocalFrame init sp={}".format(time.time() - st))
self.replace_vocal_frame_inst = None
logging.info("SongCoverInference init sp={}".format(time.time() - st))
def separate(self, cid, src_mp3, vocal_path, acc_path):
"""
人声伴奏分离
:param cid:
:param src_mp3:
:param vocal_path:
:param acc_path:
:return:
"""
st = time.time()
if self.separate_inst is None:
self.separate_inst = SeparateInterface()
if not self.separate_inst.process(cid, src_mp3, vocal_path, acc_path):
return gs_err_code_separate
if not os.path.exists(vocal_path) or not os.path.exists(acc_path):
return gs_err_code_separate
# 转码出一个32k单声道的数据
cmd = "ffmpeg -i {} -ar 32000 -ac 1 -y {} -loglevel fatal".format(vocal_path, self.vocal_32_path)
os.system(cmd)
if not os.path.exists(self.vocal_32_path):
return gs_err_code_trans_32
print("separate:cid={}|sp={}".format(cid, time.time() - st))
return gs_err_code_success
def get_start_ms(self, vocal_path):
"""
给定原始音频,找一段连续10s的音频
:param vocal_path:
:return:
"""
audio, sr = librosa.load(vocal_path, sr=16000)
audio = librosa.util.normalize(audio)
# 帧长100ms,帧移10ms,计算能量
power_arr = []
for i in range(0, len(audio) - 1600, 160):
power_arr.append(np.sum(np.abs(audio[i:i + 160])) / 160)
# 将能量小于等于10的部分做成段
power_arr = construct_power_fragment(power_arr)
fragments = []
last_pos = 0
for idx, line in enumerate(power_arr):
start = round(float(line[0]) * 0.01, 3)
duration = round(float(line[1]) * 0.01, 3)
fragments.append([last_pos, start - last_pos])
last_pos = start + duration
if last_pos < len(audio) / sr:
fragments.append([last_pos, len(audio) / sr - last_pos])
# 合并数据,两者间隔在50ms以内的合并起来
idx = 0
while idx < len(fragments) - 1:
if fragments[idx + 1][0] - (fragments[idx][0] + fragments[idx][1]) < 0.05:
fragments[idx][1] = fragments[idx + 1][0] + fragments[idx + 1][1] - fragments[idx][0]
del fragments[idx + 1]
idx -= 1
idx += 1
# out_file = vocal_path + "_power.csv"
# with open(out_file, "w") as f:
# f.write("Name\tStart\tDuration\tTime Format\tType\n")
# for fragment in fragments:
# start = round(float(fragment[0]), 3)
# duration = round(float(fragment[1]), 3)
# strr = "{}\t{}\t{}\t{}\n".format("11", start, duration, "decimal\tCue\t")
# f.write(strr)
# 筛选出开始的位置
# 1. 连续时长大于10s,当前段长度大于3s
# 2. 不可用
# 从0到fragments[idx], 包含idx其中人声段的总和
tot_vocal_duration = [fragments[0][1]]
for i in range(1, len(fragments)):
tot_vocal_duration.append(tot_vocal_duration[i - 1] + fragments[i][1])
# 计算出任意两段之间非人声占比
for i in range(0, len(fragments)):
if fragments[i][1] >= 3:
now_tot = 0
if i > 0:
now_tot = tot_vocal_duration[i - 1]
for j in range(i + 1, len(fragments)):
cur_rate = tot_vocal_duration[j] - now_tot
cur_rate = cur_rate / (fragments[j][1] + fragments[j][0] - fragments[i][0])
if cur_rate > 0.1:
return fragments[i][0]
return -1
def inference_speaker(self):
"""
推理生成合成后的音频
随机取5个干声,选择占比最小的,并且要求占比小于0.3
:return:
"""
st = time.time()
out_speakers = random.sample(self.speakers, 15)
out_songs_dict = {}
for speaker in out_speakers:
model_path = self.speakers_model_path.format(speaker)
config_path = self.speakers_model_config.format(speaker)
song_path = os.path.join(self.cache_dir, "{}_{}.wav".format(self.cid, speaker))
try:
inf(model_path, config_path, self.vocal_32_path, song_path, "prod")
except Exception as ex:
logging.info("cid={}, inference_speaker err={}".format(self.cid, ex))
continue
if os.path.exists(song_path):
if self.replace_vocal_frame_inst is None:
self.replace_vocal_frame_inst = ReplaceVocalFrame(
"data/models/split_dirty_frame_v5_3_epoch3_852.pth")
rate = self.replace_vocal_frame_inst.get_rate(song_path)
if rate < 0.3:
out_songs_dict[song_path] = rate
# 从内部选择占比最低的
out_songs = []
if len(out_songs_dict.keys()) > 0:
st_sec = self.get_start_ms(self.vocal_path)
song_msg = sorted(out_songs_dict.items(), key=lambda kv: kv[1])[0]
out_songs = [song_msg[0]]
logging.info("GetRate:cid={},song={},rate={},st_tm={}".format(self.cid, song_msg[0], round(song_msg[1], 2),
round(st_sec, 3)))
print("GetRate:cid={},song={},rate={},st_tm={}".format(self.cid, song_msg[0], round(song_msg[1], 2),
round(st_sec, 3)))
# logging.info("inference_speaker len = {} finish sp = {}".format(len(out_songs), time.time() - st))
print("inference_speaker len = {} finish sp = {}".format(len(out_songs), time.time() - st))
return out_songs
def get_new_vocal_rate(self, songs):
"""
获取人声的比率
:param songs:
:return:
"""
st = time.time()
need_to_process_song = []
for song in songs:
if self.replace_vocal_frame_inst is None:
self.replace_vocal_frame_inst = ReplaceVocalFrame("data/models/split_dirty_frame_v5_3_epoch3_852.pth")
rate = self.replace_vocal_frame_inst.get_rate(song)
logging.info("{} {} replace_rate={}".format(self.cid, song, rate))
if rate < 1.0:
need_to_process_song.append(song)
logging.info(
"get_new_vocal_rate belen = {} len = {} finish sp = {}".format(len(songs), len(need_to_process_song),
time.time() - st))
return need_to_process_song
def preprocess_vocal(self, songs, vocal_path):
"""
1. 降噪
2. 拉伸
:param songs:
:param vocal_path: 参考的音频信号
:return:
"""
st = time.time()
dv_out_list = []
for song in songs:
denoise_path = str(song).replace(".wav", "_d.wav")
cmd = "{} {} {}".format(gs_denoise_exe, song, denoise_path)
os.system(cmd)
if not os.path.exists(denoise_path):
print("{} {} ERROR denoise".format(self.cid, song))
continue
# 拉伸
volume_path = str(song).replace(".wav", "_dv.wav")
cmd = "{} {} {} {}".format(gs_draw_volume_exe, denoise_path, vocal_path, volume_path)
os.system(cmd)
if not os.path.exists(volume_path):
print("{} {} ERROR denoise".format(self.cid, volume_path))
continue
dv_out_list.append(volume_path)
print(
"preprocess_vocal belen = {} len = {} finish sp = {}".format(len(songs), len(dv_out_list),
time.time() - st))
return dv_out_list
def output(self, dv_out_list):
"""
对外输出数据
:param dv_out_list:
:return:
"""
st = time.time()
out_dir = os.path.join(self.work_dir, self.cid)
if os.path.exists(out_dir):
shutil.rmtree(out_dir)
os.makedirs(out_dir)
# 拷贝数据
dst_mp3_path = os.path.join(out_dir, "src_mp3")
dst_acc_path = os.path.join(out_dir, "acc.mp3")
dst_vocal_path = os.path.join(out_dir, "vocal.mp3")
shutil.copyfile(self.src_mp3, dst_mp3_path)
cmd = "ffmpeg -i {} -ab 320k -y {} -loglevel fatal".format(self.acc_path, dst_acc_path)
os.system(cmd)
if not os.path.exists(dst_acc_path):
return gs_err_code_encode_err
cmd = "ffmpeg -i {} -ab 320k -y {} -loglevel fatal".format(self.vocal_path, dst_vocal_path)
os.system(cmd)
if not os.path.exists(dst_vocal_path):
return gs_err_code_encode_err
# 将所有数据放到out_dir中,用于给人工标注
for dv_wav in dv_out_list:
dv_wav_name = str(dv_wav).split("/")[-1].replace(".wav", "_441.mp3")
dst_dv_path = os.path.join(out_dir, dv_wav_name)
cmd = "ffmpeg -i {} -ar 44100 -ac 1 -ab 320k -y {} -loglevel fatal".format(dv_wav, dst_dv_path)
os.system(cmd)
if not os.path.exists(dst_dv_path):
print("{} encode err!".format(cmd))
continue
logging.info(
"preprocess_vocal output sp = {}".format(time.time() - st))
def process_one(self, cid, work_dir, enable_output=False):
logging.info("\nstart:cid={},work_dir={}----------------------->>>>>>>>".format(cid, work_dir))
self.cid = cid
self.work_dir = work_dir
# 所有不对外交付的,全部放到这里
self.cache_dir = os.path.join(work_dir, "cache")
if os.path.exists(self.cache_dir):
shutil.rmtree(self.cache_dir)
os.makedirs(self.cache_dir)
self.src_mp3 = os.path.join(self.work_dir, "src.mp3")
if not os.path.exists(self.src_mp3):
return gs_err_code_no_src_mp3
self.vocal_path = os.path.join(self.cache_dir, "vocal.wav")
self.vocal_32_path = os.path.join(self.cache_dir, "vocal_32.wav")
self.acc_path = os.path.join(self.cache_dir, "acc.wav")
if not os.path.exists(self.vocal_32_path):
logging.info("start separate ... {} {} {}".format(self.src_mp3, self.vocal_path, self.acc_path))
err = self.separate(cid, self.src_mp3, self.vocal_path, self.acc_path)
if err != gs_err_code_success:
return err, None, None
logging.info("start inference_speaker ...")
out_songs = self.inference_speaker()
dv_out_list = self.preprocess_vocal(out_songs, self.vocal_path)
if len(dv_out_list) == 0:
return gs_err_code_no_good_choice, None, None
mix_mp3_path = None
gender = -1
if enable_output:
self.output(dv_out_list)
else:
# 默认全部处理一遍
for dv_out_path in dv_out_list:
src_path = dv_out_path.replace("_dv.wav", ".wav")
err, mix_mp3_path = self.after_process(self.cid, self.work_dir, src_path, dv_out_path, self.vocal_path,
self.acc_path,
True, False)
if err != gs_err_code_success:
logging.info("after_process err {}".format(err))
# 取出性别属性
if err == gs_err_code_success and mix_mp3_path is not None:
gender = self.speakers2gender[int(str(os.path.basename(mix_mp3_path)).split("_")[1])]
logging.info("finish:cid={},work_dir={}----------------------->>>>>>>>".format(cid, work_dir))
return gs_err_code_success, mix_mp3_path, gender
def reverb_by_vocal(self, file):
st = time.time()
file_442 = file.replace(".wav", "_442.wav")
if not os.path.exists(file_442):
cmd = "ffmpeg -i {} -ar 44100 -ac 2 -y {}".format(file, file_442)
os.system(cmd)
if not os.path.exists(file_442):
return gs_err_code_trans2_442, None
file_dst = file.replace(".wav", "_442_dr.wav")
cmd = "{} {} {} {}".format(gs_rever_path, self.vocal_path, file_442, file_dst)
os.system(cmd)
if not os.path.exists(file_dst):
return gs_err_code_reverb, None
print("cid = {}, reverb_by_vocal sp={}".format(self.cid, time.time() - st))
return gs_err_code_success, file_dst
def after_process(self, cid, work_dir, in_file, effect_file, vocal_file, acc_file, need_draw=True,
need_reverb=True):
"""
后处理逻辑
将处理好的音频进行替换,然后和伴奏进行混合,最后进行编码
:return:
"""
if need_reverb:
# 抓取混响
err, effect_file = self.reverb_by_vocal(in_file)
if err != gs_err_code_success:
return err, None
if need_draw:
# 增加一个拉伸的步骤
volume_path = str(effect_file).replace(".wav", "_dv.wav")
cmd = "{} {} {} {}".format(gs_draw_volume_exe, effect_file, vocal_file, volume_path)
print(cmd)
os.system(cmd)
if not os.path.exists(volume_path):
print("{} {} ERROR draw volume".format(self.cid, volume_path))
return gs_err_code_volume_err, None
effect_file = volume_path
st = time.time()
self.cid = cid
self.work_dir = work_dir
self.src_mp3 = os.path.join(self.work_dir, "src.mp3")
if not os.path.exists(self.work_dir):
return gs_err_code_no_src_dir
self.replace_vocal_frame_inst.process(in_file, effect_file, vocal_file)
dst_path = effect_file + "_replace.wav"
if not os.path.exists(dst_path):
return gs_err_code_replace_err, None
print("replace_vocal_frame_inst sp = {}".format(time.time() - st))
# 转码
dst_path_442 = dst_path.replace("_replace.wav", "_replace442.wav")
cmd = "ffmpeg -i {} -ar 44100 -ac 2 -y {} -loglevel fatal".format(dst_path, dst_path_442)
os.system(cmd)
if not os.path.exists(dst_path_442):
return gs_err_code_replace_trans_err, None
# 合并转码后再做一次拉伸,保证响度
volume_path = str(dst_path_442).replace(".wav", "_dv.wav")
cmd = "{} {} {} {}".format(gs_draw_volume_exe, dst_path_442, vocal_file, volume_path)
print(cmd)
os.system(cmd)
if not os.path.exists(volume_path):
print("{} {} ERROR draw volume".format(self.cid, volume_path))
return gs_err_code_volume_err, None
dst_path_442 = volume_path
# 混合
mix_path = dst_path_442.replace("_replace442.wav", "_replace442_mix.wav")
cmd = "{} {} {} {}".format(gs_simple_mixer_path, dst_path_442, acc_file, mix_path)
print("{}".format(cmd))
os.system(cmd)
if not os.path.exists(mix_path):
return gs_err_code_mix_err, None
# 编码为mp3
output_dir = os.path.join(self.work_dir, self.cid + "_out")
if not os.path.exists(output_dir):
os.makedirs(output_dir)
name = str(mix_path).replace("_replace442_mix.wav", "_replace442_mix.mp3").split("/")[-1]
mix_path_mp3 = os.path.join(output_dir, name)
cmd = "ffmpeg -i {} -ab 320k -y {} -loglevel fatal".format(mix_path, mix_path_mp3)
os.system(cmd)
if not os.path.exists(mix_path_mp3):
return gs_err_code_mix_transcode_err, None
# 拷贝src到output_dir
# shutil.copyfile(self.src_mp3, os.path.join(output_dir, "src.mp3"))
# logging.info("after_process sp = {}".format(time.time() - st))
return gs_err_code_success, mix_path_mp3
####################################新对外接口############################################################
def prepare_env(self, cid, work_dir, create_dir=False):
self.cid = cid
self.work_dir = work_dir
# 所有不对外交付的,全部放到这里
self.cache_dir = os.path.join(work_dir, "cache")
if create_dir:
if os.path.exists(self.cache_dir):
shutil.rmtree(self.cache_dir)
os.makedirs(self.cache_dir)
self.src_mp3 = os.path.join(self.work_dir, "src.mp3")
if not os.path.exists(self.src_mp3):
return gs_err_code_no_src_mp3
self.vocal_path = os.path.join(self.cache_dir, "vocal.wav")
self.vocal_32_path = os.path.join(self.cache_dir, "vocal_32.wav")
self.acc_path = os.path.join(self.cache_dir, "acc.wav")
return gs_err_code_success
def generate_svc_file(self, cid, work_dir):
"""
:param cid:
:param work_dir:
:return:err_code, 生成出的svc的文件名称
"""
err = self.prepare_env(cid, work_dir, create_dir=True)
if err != gs_err_code_success:
return err, None
# 音源分离
if not os.path.exists(self.vocal_32_path):
st = time.time()
err = self.separate(cid, self.src_mp3, self.vocal_path, self.acc_path)
logging.info("cid={},separate,sp={}".format(self.cid, time.time() - st))
if err != gs_err_code_success:
return err, None
# 生成svc,只保留一个最佳的
st = time.time()
out_songs = self.inference_speaker()
if len(out_songs) == 0:
return gs_err_code_no_good_choice, None
logging.info("cid={},inference_speaker,{},sp={}".format(self.cid, out_songs[0], time.time() - st))
return gs_err_code_success, out_songs[0]
def effect(self, cid, work_dir, svc_file):
st = time.time()
err = self.prepare_env(cid, work_dir)
if err != gs_err_code_success:
return err, None
logging.info("cid={},effect_and_mix,{},sp={}".format(self.cid, svc_file, time.time() - st))
# 预处理人声
dv_out_list = self.preprocess_vocal([svc_file], self.vocal_path)
if len(dv_out_list) == 0:
return gs_err_code_preprocess_vocal, None
svc_file = dv_out_list[0]
# 做音效
st = time.time()
err, effect_file = self.reverb_by_vocal(svc_file)
if err != gs_err_code_success:
return err, None
logging.info("cid={},reverb_by_vocal,{},sp={}".format(self.cid, svc_file, time.time() - st))
return err, effect_file
def mix(self, cid, work_dir, svc_file, effect_file):
"""
做音效以及合并
:param cid:
:param work_dir:
:param svc_file:
:param effect_file:
:return: err_code, 完成的mp3文件
"""
st = time.time()
err = self.prepare_env(cid, work_dir)
if err != gs_err_code_success:
return err, None
logging.info("cid={},effect_and_mix,{},sp={}".format(self.cid, svc_file, time.time() - st))
# 拉伸
st = time.time()
volume_path = str(effect_file).replace(".wav", "_dv.wav")
cmd = "{} {} {} {}".format(gs_draw_volume_exe, effect_file, self.vocal_path, volume_path)
os.system(cmd)
if not os.path.exists(volume_path):
print("{} {} ERROR draw volume".format(self.cid, volume_path))
return gs_err_code_volume_err, None
effect_file = volume_path
logging.info("cid={},draw_volume,{},sp={}".format(self.cid, svc_file, time.time() - st))
# 替换
st = time.time()
try:
if self.replace_vocal_frame_inst is None:
self.replace_vocal_frame_inst = ReplaceVocalFrame("data/models/split_dirty_frame_v5_3_epoch3_852.pth")
self.replace_vocal_frame_inst.process(svc_file, effect_file, self.vocal_path)
except Exception as ex:
logging.info("{},replace_vocal_frame_inst, {}", self.cid, ex)
return gs_err_code_replace_except_err, None
dst_path = effect_file + "_replace.wav"
if not os.path.exists(dst_path):
return gs_err_code_replace_err, None
logging.info("cid={},replace_vocal_frame_inst,{},sp={}".format(self.cid, svc_file, time.time() - st))
# 转码
st = time.time()
dst_path_442 = dst_path.replace("_replace.wav", "_replace442.wav")
cmd = "ffmpeg -i {} -ar 44100 -ac 2 -y {} -loglevel fatal".format(dst_path, dst_path_442)
os.system(cmd)
if not os.path.exists(dst_path_442):
return gs_err_code_replace_trans_err, None
logging.info("cid={},transcode,{},sp={}".format(self.cid, svc_file, time.time() - st))
# 合并转码后再做一次拉伸,保证响度
st = time.time()
volume_path = str(dst_path_442).replace("_replace442.wav", "_replace442_dv.wav")
cmd = "{} {} {} {}".format(gs_draw_volume_exe, dst_path_442, self.vocal_path, volume_path)
os.system(cmd)
if not os.path.exists(volume_path):
print("{} {} ERROR draw volume".format(self.cid, volume_path))
return gs_err_code_volume_err, None
dst_path_442 = volume_path
logging.info("cid={},draw_volume2,{},sp={}".format(self.cid, svc_file, time.time() - st))
# 混合
st = time.time()
mix_path = dst_path_442.replace("_replace442_dv.wav", "_replace442_dv_mix.wav")
cmd = "{} {} {} {}".format(gs_simple_mixer_path, dst_path_442, self.acc_path, mix_path)
os.system(cmd)
if not os.path.exists(mix_path):
return gs_err_code_mix_err, None
logging.info("cid={},mixer,{},sp={}".format(self.cid, svc_file, time.time() - st))
# 编码为mp3
st = time.time()
output_dir = os.path.join(self.work_dir, self.cid + "_out")
if not os.path.exists(output_dir):
os.makedirs(output_dir)
name = str(mix_path).replace("_replace442_dv_mix.wav", "_replace442_dv_mix.mp3").split("/")[-1]
mix_path_mp3 = os.path.join(output_dir, name)
cmd = "ffmpeg -i {} -ab 320k -y {} -loglevel fatal".format(mix_path, mix_path_mp3)
print(cmd)
os.system(cmd)
if not os.path.exists(mix_path_mp3):
return gs_err_code_mix_transcode_err, None
logging.info("cid={},encode,{},sp={}".format(self.cid, svc_file, time.time() - st))
return gs_err_code_success, mix_path_mp3
def get_gender(self, svc_file):
return self.speakers2gender[int(os.path.basename(svc_file.replace(".wav", "")).split("_")[1])]
def process_one_logic(self, cid, work_dir):
"""
搞成两部分:
1. 分离数据+5次推理,获取最佳结果,并保存
2. 利用最佳结果做音效以及合并
:return:
"""
err, svc_file = self.generate_svc_file(cid, work_dir)
gender = -1
if err != gs_err_code_success:
return err, svc_file, gender,
gender = self.get_gender(svc_file)
err, effect_file = self.effect(cid, work_dir, svc_file)
if err != gs_err_code_success:
return err, svc_file, gender
err, mix_mp3_path = self.mix(cid, work_dir, svc_file, effect_file)
return err, mix_mp3_path, gender
def test():
arr = [
# "611752105020343687",
# "611752105023532439",
# "611752105030419688",
# "611752105030485748",
# "611752105030485685",
"dzq",
]
base_dir = "/data/rsync/jianli.yang/AutoCoverTool/data/test"
s_inst = SongCoverInference()
for cid in arr:
st = time.time()
# err, mix_mp3, gender = s_inst.process_one(cid, os.path.join(base_dir, cid), False)
err, mix_mp3, gender = s_inst.process_one_logic(cid, os.path.join(base_dir, cid))
print(mix_mp3, gender)
print("cid={} RealFinish err={} sp={}".format(cid, err, time.time() - st))
def test_gene_svc():
base_dir = "/data/rsync/jianli.yang/AutoCoverTool/data/test"
# cid = "clean_yibo"
cid = "dzq"
work_dir = os.path.join(base_dir, cid)
st = time.time()
- speaker = "1125899914308640_v1"
+ speaker = "jianli"
speakers_model_path = "data/train_users/{}/logs/32k/G_2000.pth"
speakers_model_config = "data/train_users/{}/config/config.json"
model_path = speakers_model_path.format(speaker)
config_path = speakers_model_config.format(speaker)
# 缓存目录:
cache_dir = os.path.join(work_dir, "cache")
if os.path.exists(cache_dir):
shutil.rmtree(cache_dir)
os.makedirs(cache_dir)
song_path = os.path.join(cache_dir, "{}_{}.wav".format(cid, speaker))
- vocal_path = os.path.join(work_dir, "vocal_32.wav")
+ # vocal_path = os.path.join(work_dir, "vocal_32.wav")
+ vocal_path = os.path.join(work_dir, "test_silce.wav")
inf(model_path, config_path, vocal_path, song_path, "prod")
print("finish....")
if __name__ == '__main__':
test_gene_svc()
diff --git a/AutoCoverTool/online/tone_shift_one.py b/AutoCoverTool/online/tone_shift_one.py
index 585ed35..d734c21 100644
--- a/AutoCoverTool/online/tone_shift_one.py
+++ b/AutoCoverTool/online/tone_shift_one.py
@@ -1,232 +1,267 @@
"""
变调的方式做处理
1. 下载
2. 分离
3. 针对于人声变调+2,伴奏+1
4. 合成
"""
import os
import json
import shutil
import librosa
import logging
import numpy as np
from ref.music_remover.separate_interface import SeparateInterface
from online.inference_worker import upload_file2cos, gs_state_use, gs_state_finish, gs_state_default
from online.common import *
logging.basicConfig(filename='/tmp/tone_shift_one.log', level=logging.INFO)
gs_tone_shift_exe = "/opt/soft/bin/tone_shift_exe"
gs_simple_mixer_path = "/opt/soft/bin/simple_mixer"
gs_err_code_success = 0
gs_err_code_tone_shift = 1
gs_err_code_mix = 2
gs_err_code_transcode = 3
gs_err_code_upload = 4
gs_err_code_download = 5
gs_err_code_trans_to_mp3 = 6
gs_err_code_separate = 7
gs_err_code_duration_too_long = 8
gs_err_code_duration_no_vocal = 9
gs_err_code_duration_err = 10
+gs_err_code_transcode_acc = 11
+gs_err_code_upload_acc = 12
def exec_cmd(cmd):
r = os.popen(cmd)
text = r.read()
r.close()
return text
def get_d(audio_path):
cmd = "ffprobe -v quiet -print_format json -show_format -show_streams {}".format(audio_path)
data = exec_cmd(cmd)
data = json.loads(data)
# 返回秒
if 'format' in data.keys() and 'duration' in data['format']:
return float(data["format"]["duration"])
return -1
def get_mean_power(audio_path):
sr = 44100
audio, sr = librosa.load(audio_path, sr=sr, mono=True)
mm = np.mean(np.abs(audio))
return mm
class ToneShift:
def __init__(self):
self.separate_inst = SeparateInterface()
def update_state(self, song_id, state):
sql = "update svc_queue_table set state={},update_time={} where song_id = {}". \
format(state, int(time.time()), song_id)
banned_user_map['db'] = "av_db"
update_db(sql, banned_user_map)
def get_url_by_id(self, song_id):
sql = "select song_id, url from svc_queue_table where song_id={}".format(song_id)
banned_user_map["db"] = "av_db"
data = get_data_by_mysql(sql)
if len(data) == 0:
return None, None
return str(data[0][0]), data[0][1]
- def get_one_data(self):
- sql = "select song_id, url from svc_queue_table where state = 0 and song_src=3 order by create_time desc limit 1"
+ def get_one_data_logic(self):
+ """
+ 按照5,4,3的优先级进行获取
+ :return:
+ """
+ song_src_arr = [5, 4, 3]
+ for song_src in song_src_arr:
+ song_id, song_url = self.get_one_data(song_src=song_src)
+ if song_id is not None:
+ return song_id, song_url
+ return None, None
+
+ def get_one_data(self, song_src=3):
+ sql = "select song_id, url from svc_queue_table where state = 0 and song_src={} order by create_time desc limit 1".format(
+ song_src)
banned_user_map["db"] = "av_db"
data = get_data_by_mysql(sql, banned_user_map)
if len(data) == 0:
return None, None
song_id, song_url = data[0]
if song_id != "":
self.update_state(song_id, gs_state_use)
return str(song_id), song_url
def pre_process(self, work_dir, song_url):
"""
创建文件夹,下载数据
:return:
"""
if "?sign=" in song_url:
return gs_err_code_download
ext = str(song_url).split(".")[-1]
dst_file = "{}/src_origin.{}".format(work_dir, ext)
cmd = "wget {} -O {}".format(song_url, dst_file)
os.system(cmd)
if not os.path.exists(dst_file):
return gs_err_code_download
duration = get_d(dst_file)
if duration < 0:
return gs_err_code_duration_err
print("Duration:", dst_file, duration)
if duration > 20 * 60:
return gs_err_code_duration_too_long
- dst_mp3_file = "{}/src.mp3".format(work_dir)
+ dst_mp3_file = "{}/src.wav".format(work_dir)
cmd = "ffmpeg -i {} -ar 44100 -ac 2 -y {} ".format(dst_file, dst_mp3_file)
os.system(cmd)
if not os.path.exists(dst_mp3_file):
return gs_err_code_trans_to_mp3
return gs_err_code_success
def tone_shift_one(self, in_file, dst_file, pitch):
cmd = "{} {} {} {}".format(gs_tone_shift_exe, in_file, dst_file, pitch)
os.system(cmd)
return os.path.exists(dst_file)
def mix(self, cid, vocal_path, acc_path, tp):
if tp == 1:
vocal_pitch = 2
acc_pitch = 0
else:
vocal_pitch = -2
acc_pitch = 0
vocal_path_2 = vocal_path.replace(".wav", "_{}.wav".format(vocal_pitch))
acc_path_2 = acc_path.replace(".wav", "_{}.wav".format(acc_pitch))
err = self.tone_shift_one(vocal_path, vocal_path_2, vocal_pitch)
if not err:
return gs_err_code_tone_shift, None
err = self.tone_shift_one(acc_path, acc_path_2, acc_pitch)
if not err:
return gs_err_code_tone_shift, None
base_dir = os.path.dirname(vocal_path)
mix_path = "{}/mix_{}_{}.wav".format(base_dir, vocal_pitch, acc_pitch)
cmd = "{} {} {} {}".format(gs_simple_mixer_path, vocal_path_2, acc_path_2, mix_path)
print("exec_cmd={}".format(cmd))
os.system(cmd)
if not os.path.exists(mix_path):
return gs_err_code_mix, None
# 转码
- mix_path_mp3 = mix_path.replace(".wav", ".mp3")
- cmd = "ffmpeg -i {} -ab 320k -y {} -loglevel fatal".format(mix_path, mix_path_mp3)
+ mix_path_mp3 = mix_path.replace(".wav", ".mp4")
+ cmd = "ffmpeg -i {} -b:a 128k -c:a aac -ar 44100 -ac 2 -y {} -loglevel fatal".format(mix_path, mix_path_mp3)
os.system(cmd)
if not os.path.exists(mix_path_mp3):
return gs_err_code_transcode, None
# 上传到cos
mix_name = os.path.basename(mix_path_mp3)
key = "av_res/svc_res_tone_shift/{}/{}".format(str(cid), mix_name)
if not upload_file2cos(key, mix_path_mp3):
return gs_err_code_upload, None
return gs_err_code_success, key
+ def upload_acc(self, cid, acc_path):
+ # 转码
+ mix_path_aac = acc_path.replace(".wav", ".m4a")
+ cmd = "ffmpeg -i {} -b:a 128k -c:a aac -ar 44100 -ac 2 -y {} -loglevel fatal".format(acc_path, mix_path_aac)
+ os.system(cmd)
+ if not os.path.exists(mix_path_aac):
+ return gs_err_code_transcode_acc, None
+
+ # 上传
+ mix_name = os.path.basename(mix_path_aac)
+ key = "av_res/svc_res_tone_shift/{}/{}".format(str(cid), mix_name)
+ if not upload_file2cos(key, mix_path_aac):
+ return gs_err_code_upload_acc, None
+ return gs_err_code_success, key
+
def process_one(self, cid, work_dir):
"""
:param cid:
:param work_dir:
:return:
"""
- src_mp3 = os.path.join(work_dir, "src.mp3")
+ src_mp3 = os.path.join(work_dir, "src.wav")
vocal_path = os.path.join(work_dir, "vocal.wav")
acc_path = os.path.join(work_dir, "acc.wav")
if not self.separate_inst.process(cid, src_mp3, vocal_path, acc_path):
return gs_err_code_separate, []
if not os.path.exists(vocal_path) or not os.path.exists(acc_path):
return gs_err_code_separate, []
# 当人声的平均能量小于一定值时,则认为无人声(0.01是经验值判定,样本分析来看)
# 无人声的样本[0.0056, 0.0003], 有人声的样本(目前最小)[0.046, 0.049]
print("power:{},{}".format(cid, get_mean_power(vocal_path)))
if get_mean_power(vocal_path) < 0.02:
return gs_err_code_duration_no_vocal, []
err, type1_mix_mp3 = self.mix(cid, vocal_path, acc_path, 1)
if err != gs_err_code_success:
return err, []
err, type2_mix_mp3 = self.mix(cid, vocal_path, acc_path, 2)
if err != gs_err_code_success:
return err, []
- return gs_err_code_success, [type1_mix_mp3, type2_mix_mp3]
+
+ # 上传伴奏文件
+ err, acc_path_m4a = self.upload_acc(cid, acc_path)
+ if err != gs_err_code_success:
+ return err, []
+ return gs_err_code_success, [type1_mix_mp3, type2_mix_mp3, acc_path_m4a]
def process_worker(self):
logging.info("start process_worker .....")
base_dir = "/tmp/tone_shift_one"
if not os.path.exists(base_dir):
os.makedirs(base_dir)
while True:
worker_st = time.time()
- cid, song_url = self.get_one_data()
- # cid, song_url = self.get_url_by_id('611752105022612883')
+ cid, song_url = self.get_one_data_logic()
+ # cid, song_url = self.get_url_by_id('611752105029706360')
if cid is None:
time.sleep(5)
logging.info("get one data is None ...")
continue
work_dir = os.path.join(base_dir, str(cid))
if os.path.exists(work_dir):
shutil.rmtree(work_dir)
os.makedirs(work_dir)
err = self.pre_process(work_dir, song_url)
if err != gs_err_code_success:
self.update_state(str(cid), -err)
continue
st = time.time()
err, data = self.process_one(str(cid), work_dir)
logging.info("process_finish,{},{}".format(cid, time.time() - st))
- if err == gs_err_code_success and len(data) == 2:
+ if err == gs_err_code_success and len(data) != 0:
sql = "update svc_queue_table set state={},update_time={},svc_url=\"{}\" where song_id = {}". \
format(gs_state_finish, int(time.time()), ",".join(data), str(cid))
banned_user_map['db'] = "av_db"
update_db(sql, banned_user_map)
else:
self.update_state(str(cid), -err)
shutil.rmtree(work_dir)
logging.info("process_finish,{},{}".format(cid, time.time() - worker_st))
if __name__ == '__main__':
ts = ToneShift()
ts.process_worker()
diff --git a/AutoCoverTool/ref/so_vits_svc/inference_main.py b/AutoCoverTool/ref/so_vits_svc/inference_main.py
index 20a9439..e1579ec 100644
--- a/AutoCoverTool/ref/so_vits_svc/inference_main.py
+++ b/AutoCoverTool/ref/so_vits_svc/inference_main.py
@@ -1,83 +1,83 @@
import io
import os
import sys
import logging
import time
from pathlib import Path
import librosa
import numpy as np
import soundfile
from inference import infer_tool
from inference import slicer
from inference.infer_tool import Svc
logging.getLogger('numba').setLevel(logging.WARNING)
-chunks_dict = infer_tool.read_temp("ref/so-vits-svc/inference/chunks_temp.json")
+chunks_dict = infer_tool.read_temp("ref/so_vits_svc/inference/chunks_temp.json")
def inf(model_path, config_path, raw_audio_path, dst_path, dev):
# model_path = "logs/32k/G_174000-Copy1.pth"
# config_path = "configs/config.json"
svc_model = Svc(model_path, config_path)
out_dir = os.path.dirname(dst_path)
print(dst_path)
os.makedirs(out_dir, exist_ok=True)
# 支持多个wav文件,放在raw文件夹下
tran = 0
spk_list = ['speaker0'] # 每次同时合成多语者音色
slice_db = -40 # 默认-40,嘈杂的音频可以-30,干声保留呼吸可以-50
wav_format = 'wav' # 音频输出格式
# infer_tool.fill_a_to_b(trans, clean_names)
# for clean_name, tran in zip(clean_names, trans):
# raw_audio_path = f"raw/{clean_name}"
# if "." not in raw_audio_path:
# raw_audio_path += ".wav"
infer_tool.format_wav(raw_audio_path)
wav_path = Path(raw_audio_path).with_suffix('.wav')
chunks = slicer.cut(wav_path, db_thresh=slice_db)
audio_data, audio_sr = slicer.chunks2audio(wav_path, chunks)
for spk in spk_list:
audio = []
for (slice_tag, data) in audio_data:
print(f'#=====segment start, {round(len(data) / audio_sr, 3)}s======')
length = int(np.ceil(len(data) / audio_sr * svc_model.target_sample))
raw_path = io.BytesIO()
soundfile.write(raw_path, data, audio_sr, format="wav")
raw_path.seek(0)
if slice_tag:
print('jump empty segment')
_audio = np.zeros(length)
else:
out_audio, out_sr = svc_model.infer(spk, tran, raw_path, dev == "test")
_audio = out_audio.cpu().numpy()
audio.extend(list(_audio))
soundfile.write(dst_path, audio, svc_model.target_sample, format=wav_format)
if __name__ == '__main__':
g_model = sys.argv[1] # 模型地址
g_config = sys.argv[2] # 配置文件地址
g_audio_path = sys.argv[3] # 输入的音频文件地址,wav
g_dst_path = sys.argv[4] # 输出的音频文件地址
if os.path.exists(g_dst_path):
print("{} success ...".format(g_dst_path))
exit(0)
g_dev = "prod"
if len(sys.argv) > 5:
g_dev = sys.argv[5]
g_aa, g_sr = librosa.load(g_audio_path)
d = librosa.get_duration(g_aa, g_sr)
# if g_dev != "test":
# if d > 250:
# print("{} too long".format(g_audio_path))
# exit(0)
st = time.time()
inf(g_model, g_config, g_audio_path, g_dst_path, g_dev)
print("{}, inference sp={}".format(g_audio_path, time.time() - st))
diff --git a/AutoCoverTool/ref/so_vits_svc/models.py b/AutoCoverTool/ref/so_vits_svc/models.py
index 09c4045..3e3498b 100644
--- a/AutoCoverTool/ref/so_vits_svc/models.py
+++ b/AutoCoverTool/ref/so_vits_svc/models.py
@@ -1,352 +1,357 @@
import copy
import math
import torch
from torch import nn
from torch.nn import functional as F
import attentions
import commons
import modules
from torch.nn import Conv1d, ConvTranspose1d, AvgPool1d, Conv2d
from torch.nn.utils import weight_norm, remove_weight_norm, spectral_norm
from commons import init_weights, get_padding
from vdecoder.hifigan.models import Generator
from utils import f0_to_coarse
class ResidualCouplingBlock(nn.Module):
def __init__(self,
channels,
hidden_channels,
kernel_size,
dilation_rate,
n_layers,
n_flows=4,
gin_channels=0):
super().__init__()
self.channels = channels
self.hidden_channels = hidden_channels
self.kernel_size = kernel_size
self.dilation_rate = dilation_rate
self.n_layers = n_layers
self.n_flows = n_flows
self.gin_channels = gin_channels
self.flows = nn.ModuleList()
for i in range(n_flows):
self.flows.append(modules.ResidualCouplingLayer(channels, hidden_channels, kernel_size, dilation_rate, n_layers, gin_channels=gin_channels, mean_only=True))
self.flows.append(modules.Flip())
def forward(self, x, x_mask, g=None, reverse=False):
if not reverse:
for flow in self.flows:
x, _ = flow(x, x_mask, g=g, reverse=reverse)
else:
for flow in reversed(self.flows):
x = flow(x, x_mask, g=g, reverse=reverse)
return x
class Encoder(nn.Module):
def __init__(self,
in_channels,
out_channels,
hidden_channels,
kernel_size,
dilation_rate,
n_layers,
gin_channels=0):
super().__init__()
self.in_channels = in_channels
self.out_channels = out_channels
self.hidden_channels = hidden_channels
self.kernel_size = kernel_size
self.dilation_rate = dilation_rate
self.n_layers = n_layers
self.gin_channels = gin_channels
self.pre = nn.Conv1d(in_channels, hidden_channels, 1)
self.enc = modules.WN(hidden_channels, kernel_size, dilation_rate, n_layers, gin_channels=gin_channels)
self.proj = nn.Conv1d(hidden_channels, out_channels * 2, 1)
def forward(self, x, x_lengths, g=None):
# print(x.shape,x_lengths.shape)
x_mask = torch.unsqueeze(commons.sequence_mask(x_lengths, x.size(2)), 1).to(x.dtype)
x = self.pre(x) * x_mask
x = self.enc(x, x_mask, g=g)
stats = self.proj(x) * x_mask
m, logs = torch.split(stats, self.out_channels, dim=1)
z = (m + torch.randn_like(m) * torch.exp(logs)) * x_mask
return z, m, logs, x_mask
class TextEncoder(nn.Module):
def __init__(self,
in_channels,
out_channels,
hidden_channels,
kernel_size,
dilation_rate,
n_layers,
gin_channels=0,
filter_channels=None,
n_heads=None,
p_dropout=None):
super().__init__()
self.in_channels = in_channels
self.out_channels = out_channels
self.hidden_channels = hidden_channels
self.kernel_size = kernel_size
self.dilation_rate = dilation_rate
self.n_layers = n_layers
self.gin_channels = gin_channels
self.pre = nn.Conv1d(in_channels, hidden_channels, 1)
self.proj = nn.Conv1d(hidden_channels, out_channels * 2, 1)
self.f0_emb = nn.Embedding(256, hidden_channels)
self.enc_ = attentions.Encoder(
hidden_channels,
filter_channels,
n_heads,
n_layers,
kernel_size,
p_dropout)
def forward(self, x, x_lengths, f0=None):
+ # x->(b,256,frame_num), x_lengths -> (b)
+ # commons.sequence_mask 对于batch层级有价值,x_lengths是每个batch中每一个元素的帧数
+ # 比如输入([3,5,2], 5)那么得到 3 * 5的True/False矩阵,其中第一层矩阵为3个true,2个false,第二层全true,第三层前两个true,其余false
+ # 作用一个批次中允许不同长度的数据一起训练,此时较短的乘以false,剔除影响
x_mask = torch.unsqueeze(commons.sequence_mask(x_lengths, x.size(2)), 1).to(x.dtype)
x = self.pre(x) * x_mask
x = x + self.f0_emb(f0).transpose(1,2)
x = self.enc_(x * x_mask, x_mask)
stats = self.proj(x) * x_mask
m, logs = torch.split(stats, self.out_channels, dim=1)
z = (m + torch.randn_like(m) * torch.exp(logs)) * x_mask
return z, m, logs, x_mask
class DiscriminatorP(torch.nn.Module):
def __init__(self, period, kernel_size=5, stride=3, use_spectral_norm=False):
super(DiscriminatorP, self).__init__()
self.period = period
self.use_spectral_norm = use_spectral_norm
norm_f = weight_norm if use_spectral_norm == False else spectral_norm
self.convs = nn.ModuleList([
norm_f(Conv2d(1, 32, (kernel_size, 1), (stride, 1), padding=(get_padding(kernel_size, 1), 0))),
norm_f(Conv2d(32, 128, (kernel_size, 1), (stride, 1), padding=(get_padding(kernel_size, 1), 0))),
norm_f(Conv2d(128, 512, (kernel_size, 1), (stride, 1), padding=(get_padding(kernel_size, 1), 0))),
norm_f(Conv2d(512, 1024, (kernel_size, 1), (stride, 1), padding=(get_padding(kernel_size, 1), 0))),
norm_f(Conv2d(1024, 1024, (kernel_size, 1), 1, padding=(get_padding(kernel_size, 1), 0))),
])
self.conv_post = norm_f(Conv2d(1024, 1, (3, 1), 1, padding=(1, 0)))
def forward(self, x):
fmap = []
# 1d to 2d
b, c, t = x.shape
if t % self.period != 0: # pad first
n_pad = self.period - (t % self.period)
x = F.pad(x, (0, n_pad), "reflect")
t = t + n_pad
x = x.view(b, c, t // self.period, self.period)
for l in self.convs:
x = l(x)
x = F.leaky_relu(x, modules.LRELU_SLOPE)
fmap.append(x)
x = self.conv_post(x)
fmap.append(x)
x = torch.flatten(x, 1, -1)
return x, fmap
class DiscriminatorS(torch.nn.Module):
def __init__(self, use_spectral_norm=False):
super(DiscriminatorS, self).__init__()
norm_f = weight_norm if use_spectral_norm == False else spectral_norm
self.convs = nn.ModuleList([
norm_f(Conv1d(1, 16, 15, 1, padding=7)),
norm_f(Conv1d(16, 64, 41, 4, groups=4, padding=20)),
norm_f(Conv1d(64, 256, 41, 4, groups=16, padding=20)),
norm_f(Conv1d(256, 1024, 41, 4, groups=64, padding=20)),
norm_f(Conv1d(1024, 1024, 41, 4, groups=256, padding=20)),
norm_f(Conv1d(1024, 1024, 5, 1, padding=2)),
])
self.conv_post = norm_f(Conv1d(1024, 1, 3, 1, padding=1))
def forward(self, x):
fmap = []
for l in self.convs:
x = l(x)
x = F.leaky_relu(x, modules.LRELU_SLOPE)
fmap.append(x)
x = self.conv_post(x)
fmap.append(x)
x = torch.flatten(x, 1, -1)
return x, fmap
class MultiPeriodDiscriminator(torch.nn.Module):
def __init__(self, use_spectral_norm=False):
super(MultiPeriodDiscriminator, self).__init__()
periods = [2,3,5,7,11]
discs = [DiscriminatorS(use_spectral_norm=use_spectral_norm)]
discs = discs + [DiscriminatorP(i, use_spectral_norm=use_spectral_norm) for i in periods]
self.discriminators = nn.ModuleList(discs)
def forward(self, y, y_hat):
y_d_rs = []
y_d_gs = []
fmap_rs = []
fmap_gs = []
for i, d in enumerate(self.discriminators):
y_d_r, fmap_r = d(y)
y_d_g, fmap_g = d(y_hat)
y_d_rs.append(y_d_r)
y_d_gs.append(y_d_g)
fmap_rs.append(fmap_r)
fmap_gs.append(fmap_g)
return y_d_rs, y_d_gs, fmap_rs, fmap_gs
-
-
+
+
class SpeakerEncoder(torch.nn.Module):
def __init__(self, mel_n_channels=80, model_num_layers=3, model_hidden_size=256, model_embedding_size=256):
super(SpeakerEncoder, self).__init__()
self.lstm = nn.LSTM(mel_n_channels, model_hidden_size, model_num_layers, batch_first=True)
self.linear = nn.Linear(model_hidden_size, model_embedding_size)
self.relu = nn.ReLU()
def forward(self, mels):
self.lstm.flatten_parameters()
_, (hidden, _) = self.lstm(mels)
embeds_raw = self.relu(self.linear(hidden[-1]))
return embeds_raw / torch.norm(embeds_raw, dim=1, keepdim=True)
-
+
def compute_partial_slices(self, total_frames, partial_frames, partial_hop):
mel_slices = []
for i in range(0, total_frames-partial_frames, partial_hop):
mel_range = torch.arange(i, i+partial_frames)
mel_slices.append(mel_range)
-
+
return mel_slices
-
+
def embed_utterance(self, mel, partial_frames=128, partial_hop=64):
mel_len = mel.size(1)
last_mel = mel[:,-partial_frames:]
-
+
if mel_len > partial_frames:
mel_slices = self.compute_partial_slices(mel_len, partial_frames, partial_hop)
mels = list(mel[:,s] for s in mel_slices)
mels.append(last_mel)
mels = torch.stack(tuple(mels), 0).squeeze(1)
-
+
with torch.no_grad():
partial_embeds = self(mels)
embed = torch.mean(partial_embeds, axis=0).unsqueeze(0)
#embed = embed / torch.linalg.norm(embed, 2)
else:
with torch.no_grad():
embed = self(last_mel)
-
+
return embed
class SynthesizerTrn(nn.Module):
"""
Synthesizer for Training
"""
- def __init__(self,
+ def __init__(self,
spec_channels,
segment_size,
inter_channels,
hidden_channels,
filter_channels,
n_heads,
n_layers,
kernel_size,
p_dropout,
- resblock,
- resblock_kernel_sizes,
- resblock_dilation_sizes,
- upsample_rates,
- upsample_initial_channel,
+ resblock,
+ resblock_kernel_sizes,
+ resblock_dilation_sizes,
+ upsample_rates,
+ upsample_initial_channel,
upsample_kernel_sizes,
gin_channels,
ssl_dim,
n_speakers,
**kwargs):
super().__init__()
self.spec_channels = spec_channels
self.inter_channels = inter_channels
self.hidden_channels = hidden_channels
self.filter_channels = filter_channels
self.n_heads = n_heads
self.n_layers = n_layers
self.kernel_size = kernel_size
self.p_dropout = p_dropout
self.resblock = resblock
self.resblock_kernel_sizes = resblock_kernel_sizes
self.resblock_dilation_sizes = resblock_dilation_sizes
self.upsample_rates = upsample_rates
self.upsample_initial_channel = upsample_initial_channel
self.upsample_kernel_sizes = upsample_kernel_sizes
self.segment_size = segment_size
self.gin_channels = gin_channels
self.ssl_dim = ssl_dim
self.emb_g = nn.Embedding(n_speakers, gin_channels)
self.enc_p_ = TextEncoder(ssl_dim, inter_channels, hidden_channels, 5, 1, 16,0, filter_channels, n_heads, p_dropout)
hps = {
"sampling_rate": 32000,
"inter_channels": 192,
"resblock": "1",
"resblock_kernel_sizes": [3, 7, 11],
"resblock_dilation_sizes": [[1, 3, 5], [1, 3, 5], [1, 3, 5]],
"upsample_rates": [10, 8, 2, 2],
"upsample_initial_channel": 512,
"upsample_kernel_sizes": [16, 16, 4, 4],
"gin_channels": 256,
}
self.dec = Generator(h=hps)
self.enc_q = Encoder(spec_channels, inter_channels, hidden_channels, 5, 1, 16, gin_channels=gin_channels)
self.flow = ResidualCouplingBlock(inter_channels, hidden_channels, 5, 1, 4, gin_channels=gin_channels)
def forward(self, c, f0, spec, g=None, mel=None, c_lengths=None, spec_lengths=None):
- # hubert特征, f0, 幅度谱特征, 说话人id,mel谱特征
+ # hubert特征(b,256,frame_num), f0 (frame_num), 幅度谱特征, 说话人id,mel谱特征
if c_lengths == None:
- c_lengths = (torch.ones(c.size(0)) * c.size(-1)).to(c.device)
+ c_lengths = (torch.ones(c.size(0)) * c.size(-1)).to(c.device) # (b, frame_num)
if spec_lengths == None:
spec_lengths = (torch.ones(spec.size(0)) * spec.size(-1)).to(spec.device)
+ # 说话人信息embding
g = self.emb_g(g).transpose(1,2)
z_ptemp, m_p, logs_p, _ = self.enc_p_(c, c_lengths, f0=f0_to_coarse(f0))
- z, m_q, logs_q, spec_mask = self.enc_q(spec, spec_lengths, g=g)
+ z, m_q, logs_q, spec_mask = self.enc_q(spec, spec_lengths, g=g)
z_p = self.flow(z, spec_mask, g=g)
z_slice, pitch_slice, ids_slice = commons.rand_slice_segments_with_pitch(z, f0, spec_lengths, self.segment_size)
# o = self.dec(z_slice, g=g)
o = self.dec(z_slice, g=g, f0=pitch_slice)
return o, ids_slice, spec_mask, (z, z_p, m_p, logs_p, m_q, logs_q)
def infer(self, c, f0, g=None, mel=None, c_lengths=None):
if c_lengths == None:
c_lengths = (torch.ones(c.size(0)) * c.size(-1)).to(c.device)
g = self.emb_g(g).transpose(1,2)
z_p, m_p, logs_p, c_mask = self.enc_p_(c, c_lengths, f0=f0_to_coarse(f0))
z = self.flow(z_p, c_mask, g=g, reverse=True)
o = self.dec(z * c_mask, g=g, f0=f0)
return o
diff --git a/AutoCoverTool/script/get_song_url.py b/AutoCoverTool/script/get_song_url.py
index ab483db..6514536 100644
--- a/AutoCoverTool/script/get_song_url.py
+++ b/AutoCoverTool/script/get_song_url.py
@@ -1,827 +1,827 @@
"""
获取歌曲的地址
# song_src=2 是来源108和109的歌曲,未被洗过的
# song_src=1 是曲库给的
# song_src=3 # 用于轻变调的
"""
from script.common import *
from copy import deepcopy
from online.common import update_db
def get_url_by_song_id(song_id):
sql = "select task_url,starmaker_songid from silence where starmaker_songid = {} order by task_id desc limit 1".format(
song_id)
ban = deepcopy(banned_user_map)
ban["db"] = "starmaker_musicbook"
data = get_data_by_mysql(sql, ban)
if len(data) > 0:
return data[0][0]
return None
def process():
arr = [
"611752105020327762",
"611752105020332343",
"611752105020332580",
"611752105020382477",
"611752105020384960",
"611752105020390942",
"611752105020402448",
"611752105022612883",
"611752105022614531",
"611752105022647060",
"611752105022647065",
"611752105022647066",
"611752105022647079",
"611752105022704186",
"611752105022728482",
"611752105022728546",
"611752105022729259",
"611752105022729263",
"611752105022729268",
"611752105022731042",
"611752105022731053",
"611752105022731127",
"611752105022734755",
"611752105022736024",
"611752105022738473",
"611752105022739648",
"611752105022739650",
"611752105022740713",
"611752105022741712",
"611752105022743896",
"611752105022746068",
"611752105022746733",
"611752105022747108",
"611752105022753906",
"611752105022757968",
"611752105022763051",
"611752105022763880",
"611752105022763884",
"611752105022764224",
"611752105022764688",
"611752105022764801",
"611752105022765022",
"611752105022766341",
"611752105022767186",
"611752105022767294",
"611752105022768062",
"611752105022768419",
"611752105022768837",
"611752105022770004",
"611752105022770306",
"611752105022772154",
"611752105022773633",
"611752105022773776",
"611752105022774040",
"611752105022774127",
"611752105022774220",
"611752105022774502",
"611752105022775091",
"611752105022775486",
"611752105022775600",
"611752105022775907",
"611752105022775939",
"611752105022776719",
"611752105022776721",
"611752105022776761",
"611752105022776857",
"611752105022777051",
"611752105022777076",
"611752105022777120",
"611752105022777328",
"611752105022777496",
"611752105022777573",
"611752105022777600",
"611752105022777607",
"611752105022777608",
"611752105022777611",
"611752105022777835",
"611752105022778042",
"611752105022779020",
"611752105022779294",
"611752105022779784",
"611752105022780210",
"611752105022780284",
"611752105022780287",
"611752105022780345",
"611752105022780355",
"611752105022780818",
"611752105022780961",
"611752105022780965",
"611752105022781011",
"611752105022781144",
"611752105022781193",
"611752105022781267",
"611752105022781268",
"611752105022781374",
"611752105022781387",
"611752105022781807",
"611752105022782935",
"611752105022783480",
"611752105022783776",
"611752105022783967",
"611752105022784390",
"611752105022784996",
"611752105022785018",
"611752105022785313",
"611752105022785621",
"611752105022785681",
"611752105022812895",
"611752105022818025",
"611752105022823781",
"611752105022825467",
"611752105022835406",
"611752105022835415",
"611752105022835751",
"611752105022836470",
"611752105022837186",
"611752105022837452",
"611752105022837464",
"611752105022838205",
"611752105022838206",
"611752105022839030",
"611752105022839189",
"611752105022839975",
"611752105022840319",
"611752105022840550",
"611752105022840637",
"611752105022841089",
"611752105022841308",
"611752105022841355",
"611752105022842120",
"611752105022842184",
"611752105022842241",
"611752105022842989",
"611752105022843089",
"611752105022843139",
"611752105022843331",
"611752105022843710",
"611752105022843728",
"611752105022876795",
"611752105022973113",
"611752105023086347",
"611752105023091102",
"611752105023104185",
"611752105023162802",
"611752105023184121",
"611752105023219237",
"611752105023234496",
"611752105023246015",
"611752105023246857",
"611752105023258864",
"611752105023262008",
"611752105023301455",
"611752105023306231",
"611752105023329571",
"611752105023411931",
"611752105023449798",
"611752105023458990",
"611752105023610603",
"611752105023678577",
"611752105023683356",
"611752105023683357",
"611752105023725727",
"611752105023783626",
"611752105023841037",
"611752105023908922",
"611752105023929521",
"611752105024170140",
"611752105024183682",
"611752105024231227",
"611752105024415490",
"611752105024466658",
"611752105024618170",
"611752105024683212",
"611752105024728134",
"611752105024765795",
"611752105024766050",
"611752105025090763",
"611752105025188532",
"611752105025242121",
"611752105025348359",
"611752105025455871",
"611752105025458749",
"611752105025458753",
"611752105025458809",
"611752105025467555",
"611752105025475926",
"611752105025486355",
"611752105025492732",
"611752105025496983",
"611752105025503613",
"611752105025504662",
"611752105025506533",
"611752105025515144",
"611752105025520678",
"611752105025521388",
"611752105025524664",
"611752105025524932",
"611752105025526555",
"611752105025542775",
"611752105025542802",
"611752105025543710",
"611752105025555350",
"611752105025558173",
"611752105025565020",
"611752105025565029",
"611752105025565034",
"611752105025565044",
"611752105025578884",
"611752105025580424",
"611752105025581305",
"611752105025584544",
"611752105025720331",
"611752105025840622",
"611752105026003288",
"611752105026090255",
"611752105026110280",
"611752105026110299",
"611752105026110309",
"611752105026110320",
"611752105026110324",
"611752105026110363",
"611752105026110435",
"611752105026150525",
"611752105026152312",
"611752105026152320",
"611752105026180638",
"611752105026180797",
"611752105026205984",
"611752105026227884",
"611752105026343282",
"611752105026343284",
"611752105026388268",
"611752105026417620",
"611752105026449246",
"611752105026462848",
"611752105026465098",
"611752105026533365",
"611752105026533380",
"611752105026533386",
"611752105026533657",
"611752105026536897",
"611752105026536911",
"611752105026536913",
"611752105026577993",
"611752105026580839",
"611752105026614487",
"611752105026666894",
"611752105026666899",
"611752105026666904",
"611752105026666918",
"611752105026666950",
"611752105026666964",
"611752105026666995",
"611752105026667014",
"611752105026667025",
"611752105026716551",
"611752105026779831",
"611752105027030955",
"611752105027147459",
"611752105027186707",
"611752105027201043",
"611752105027216307",
"611752105027228689",
"611752105027228702",
"611752105027326105",
"611752105027460089",
"611752105027460125",
"611752105027484924",
"611752105027601574",
"611752105027648113",
"611752105027802526",
"611752105027854263",
"611752105028204403",
"611752105028408823",
"611752105028477541",
"611752105028507652",
"611752105028558157",
"611752105028593043",
"611752105028793344",
"611752105028815367",
"611752105028820643",
"611752105028820644",
"611752105028837845",
"611752105028858612",
"611752105028858622",
"611752105028878359",
"611752105028879009",
"611752105028916096",
"611752105028916098",
"611752105028975585",
"611752105028990740",
"611752105029006327",
"611752105029041707",
"611752105029047058",
"611752105029047269",
"611752105029054046",
"611752105029059915",
"611752105029090034",
"611752105029204262",
"611752105029272970",
"611752105029290667",
"611752105029291290",
"611752105029291293",
"611752105029291297",
"611752105029291304",
"611752105029306974",
"611752105029372452",
"611752105029432803",
"611752105029648535",
"611752105029648872",
"611752105029648891",
"611752105029788767",
"611752105029953987",
"611752105029954740",
"611752105029954853",
"611752105029955024",
"611752105029956615",
"611752105029990162",
"611752105029990799",
"611752105029991249",
"611752105030119229",
"611752105030146069",
"611752105030220820",
"611752105030228836",
"611752105030249168",
"611752105030249302",
"611752105030279605",
"61175210503042544",
"611752105030447267",
"611752105030449043",
"611752105030454452",
"611752105030470921",
"611752105030483301",
"611752105030483312",
"611752105030483313",
"611752105030483344",
"611752105030483414",
"611752105030483415",
"611752105030485565",
"611752105030485569",
"611752105030485602",
"611752105030485608",
"611752105030485620",
"611752105030485663",
"611752105030485711",
"611752105030485733",
"611752105030485745",
"611752105030485799",
"611752105030486000",
"611752105030486306",
"611752105030488510",
"611752105030488594",
"611752105030488665",
"611752105030488713",
"611752105030488727",
"611752105030488744",
"611752105030488814",
"611752105030488836",
"611752105030488852",
"611752105030488864",
"611752105030488880",
"611752105030488962",
"611752105030488997",
"611752105030489153",
"611752105030489354",
"611752105030489380",
"611752105030489394",
"611752105030489403",
"611752105030489415",
"611752105030494882",
"611752105030499117",
"611752105030499185",
"611752105030499265",
"611752105030499310",
"611752105030500582",
"611752105030501929",
"611752105030501994",
"611752105030502109",
"611752105030502463",
"611752105030503847",
"611752105030506310",
"611752105030507034",
"611752105030516849",
"611752105030517044",
"611752105030517093",
"611752105030532792",
"611752105030532858",
"611752105030532869",
"611752105030534180",
"611752105030534293",
"611752105030534503",
"611752105030535017",
"611752105030538184",
"611752105030544325",
"611752105030547499",
"611752105030547630",
"611752105030547632",
"611752105030547638",
"611752105030547849",
"611752105030547881",
"611752105030549919",
"611752105030554063",
"611752105030554076",
"611752105030556613",
"611752105030557261",
"611752105030557355",
"611752105030558647",
"611752105030558663",
"611752105030559471",
"611752105030559472",
"611752105030562192",
"611752105030562194",
"611752105030562196",
"611752105030562197",
"611752105030562199",
"611752105030562203",
"611752105030562205",
"611752105030562209",
"611752105030562211",
"611752105030562213",
"611752105030562214",
"611752105030562218",
"611752105030562221",
"611752105030562227",
"611752105030562228",
"611752105030562231",
"611752105030562234",
"611752105030562236",
"611752105030562239",
"611752105030562243",
"611752105030562245",
"611752105030562248",
"611752105030562251",
"611752105030562254",
"611752105030562255",
"611752105030562259",
"611752105030562262",
"611752105030562263",
"611752105030562266",
"611752105030562268",
"611752105030562271",
"611752105030562274",
"611752105030562277",
"611752105030562283",
"611752105030562286",
"611752105030562289",
"611752105030562291",
"611752105030562296",
"611752105030562302",
"611752105030562303",
"611752105030562306",
"611752105030562311",
"611752105030562314",
"611752105030562316",
"611752105030562322",
"611752105030562325",
"611752105030562327",
"611752105030562333",
"611752105030562335",
"611752105030562337",
"611752105030562338",
"611752105030562345",
"611752105030562351",
"611752105030562378",
"611752105030562380",
"611752105030562383",
"611752105030562386",
"611752105030562389",
"611752105030562391",
"611752105030562392",
"611752105030562397",
"611752105030562398",
"611752105030562399",
"611752105030562401",
"611752105030562404",
"611752105030562405",
"611752105030562411",
"611752105030562413",
"611752105030562414",
"611752105030562417",
"611752105030562419",
"611752105030562424",
"611752105030562425",
"611752105030562426",
"611752105030562428",
"611752105030562431",
"611752105030562448",
"611752105030562457",
"611752105030562459",
"611752105030562460",
"611752105030562463",
"611752105030562470",
"611752105030562472",
"611752105030562473",
"611752105030562483",
"611752105030562489",
"611752105030562493",
"611752105030562494",
"611752105030562499",
"611752105030562502",
"611752105030562504",
"611752105030562507",
"611752105030562512",
"611752105030562513",
"611752105030562517",
"611752105030562522",
"611752105030562919",
"611752105030562921",
"611752105030562924",
"611752105030562925",
"611752105030562929",
"611752105030562931",
"611752105030562936",
"611752105030562938",
"611752105030562939",
"611752105030562940",
"611752105030562943",
"611752105030562946",
"611752105030562950",
"611752105030562953",
"611752105030562954",
"611752105030562959",
"611752105030562960",
"611752105030562962",
"611752105030562968",
"611752105030562974",
"611752105030562978",
"611752105030562979",
"611752105030562981",
"611752105030562983",
"611752105030562986",
"611752105030562988",
"611752105030562999",
"611752105030563001",
"611752105030563003",
"611752105030563005",
"611752105030563006",
"611752105030563010",
"611752105030563014",
"611752105030563022",
"611752105030563025",
"611752105030563028",
"611752105030563031",
"611752105030563034",
"611752105030563035",
"611752105030563043",
"611752105030564818",
"611752105030568345",
"611752105030568348",
"611752105030578193",
"611752105030582372",
"611752105030590839",
"611752105030590840",
"611752105030590845",
"611752105030590847",
"611752105030595548",
"611752105030595730",
"611752105030597299",
"611752105030597505",
"611752105030605279",
"611752105030605833",
"611752105030606179",
"611752105030615341",
"611752105030617237",
"611752105030617286",
"611752105030617308",
"611752105030617321",
"611752105030617329",
"611752105030617332",
"611752105030617344",
"611752105030623889",
"611752105030623893",
"611752105030629479",
"611752105030629626",
"611752105030644584",
"611752105030644604",
"611752105030645910",
"611752105030645928",
"611752105030645939",
"611752105030645952",
"611752105030645965",
"611752105030645979",
"611752105030645993",
"611752105030646025",
"611752105030646052",
"611752105030646076",
"611752105030646106",
"611752105030646134",
"611752105030646147",
"611752105030647154",
"611752105030647258",
"611752105030647263",
"611752105030647335",
"611752105030647409",
"611752105030647439",
"611752105030647456",
"611752105030647469",
"611752105030647493",
"611752105030647496",
"611752105030647512",
"611752105030647526",
"611752105030647735",
"611752105030647850",
"611752105030647856",
"611752105030647863",
"611752105030649520",
"611752105030649525",
"611752105030649535",
"611752105030649557",
"611752105030649597",
"611752105030649603",
"611752105030649621",
"611752105030649627",
"611752105030649645",
"611752105030649647",
"611752105030649648",
"611752105030649650",
"611752105030649652",
"611752105030649657",
"611752105030649661",
"611752105030650191",
"611752105030650212",
"611752105030650762",
"611752105030650773",
"611752105030650788",
"611752105030650800",
"611752105030650807",
"611752105030652092",
"611752105030652107",
"611752105030652116",
"611752105030652135",
"611752105030652143",
"611752105030652148",
"611752105030652183",
"611752105030652188",
"611752105030652306",
"611752105030652522",
"611752105030652547",
"611752105030652554",
"611752105030652565",
"611752105030652580",
"611752105030652586",
"611752105030652606",
"611752105030652613",
"611752105030652619",
"611752105030652628",
"611752105030652635",
"611752105030652645",
"611752105030652657",
"611752105030652666",
"611752105030652675",
"611752105030652710",
"611752105030652734",
"611752105030652740",
"611752105030652759",
"611752105030652832",
"611752105030652843",
"611752105030652867",
"611752105030652890",
"611752105030652901",
"611752105030652955",
"611752105030652962",
"611752105030653015",
"611752105030653040",
"611752105030653077",
"611752105030653092",
"611752105030653100",
"611752105030653125",
"611752105030653141",
"611752105030653177",
"611752105030659127",
"611752105030659135",
"611752105030659138",
"611752105030659139",
"611752105030659140",
"611752105030659145",
"611752105030659146",
"611752105030659150",
"611752105030659157",
"611752105030659158",
"611752105030659160",
"611752105030659164",
"611752105030659167",
"611752105030659176",
"611752105030659178",
"611752105030659180",
"611752105030659183",
"611752105030659190",
"611752105030659197",
"611752105030659201",
"611752105030659205",
"611752105030659206",
"611752105030659210",
"611752105030659213",
"611752105030659214",
"611752105030659222",
"611752105030659228",
"611752105030659230",
"611752105030659235",
"611752105030659239",
"611752105030659241",
"611752105030659245",
"611752105030659247",
"611752105030659248",
"611752105030659249",
"611752105030659252",
"611752105030659253",
"611752105030659255",
"611752105030659259",
"611752105030659261",
"611752105030659263",
"611752105030659265",
"611752105030659266",
"611752105030659268",
"611752105030659271",
"611752105030659272",
"611752105030659275",
"611752105030659276",
"611752105030659279",
"611752105030659280",
"611752105030659285",
"611752105030659286",
"611752105030659287",
"611752105030659892",
"611752105030659898",
"611752105030659904",
"611752105030659907",
"611752105030659915",
"611752105030659923",
"611752105030659929",
"611752105030659936",
"611752105030659942",
"611752105030659957",
"611752105030659965",
"611752105030659974",
"611752105030659982",
"611752105030659986",
"611752105030659992",
"611752105030659998",
"611752105030660002",
"611752105030660009",
"611752105030660018",
"611752105030660030",
"611752105030660038",
"611752105030661242"
]
ban = deepcopy(banned_user_map)
ban["db"] = "av_db"
for sid in arr:
url = get_url_by_song_id(sid)
if url is not None:
print("out,{},{}".format(url, sid))
# 不在数据库中
sql = "select song_id from svc_queue_table where song_id={} and song_src=3".format(sid)
data = get_data_by_mysql(sql, ban)
if len(data) == 0:
tm = int(time.time())
sql = "replace INTO svc_queue_table (song_id, url, create_time, update_time, song_src) VALUES ({}, \"{}\",{}, {}, 3)" \
.format(sid, url, tm, tm)
update_db(sql, ban)
def get_data_from_song():
sql = """
select tb1.song_id, tb1.recording_count
from (
select song_id,recording_count
from starmaker.song
where song_src in (108,109) and song_status = 2
order by recording_count desc
) as tb1
left join
(
select song_id
from av_db.svc_queue_table
) as tb2
on tb1.song_id = tb2.song_id
where tb2.song_id is null
- order by tb1.recording_count desc limit 1000
+ order by tb1.recording_count desc limit 5000
"""
ban = deepcopy(banned_user_map)
ban_v1 = deepcopy(banned_user_map)
ban["db"] = "starmaker_musicbook"
ban_v1["db"] = "av_db"
data = get_data_by_mysql(sql, ban)
for dt in data:
sid = dt[0]
url = get_url_by_song_id(sid)
if url is not None:
print("out,{},{}".format(url, sid))
tm = int(time.time())
sql = "insert INTO svc_queue_table (song_id, url, create_time, update_time, song_src) VALUES ({}, \"{}\", {}, {}, 3)" \
.format(sid, url, tm, tm)
update_db(sql, ban_v1)
if __name__ == '__main__':
# get_diff_song()
get_data_from_song()
# process()

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 12, 08:30 (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1347157
Default Alt Text
(82 KB)

Event Timeline