分离歌曲中的人声和背景音乐(tensorflow)

有没有好奇歌星们清唱的声音怎么样?这一讲,我们将歌曲的人声和背景音乐分离出来,使用的网络是RNN。接下来一一讲解怎么实现。

下载数据集

搞机器学习,首先想到的是怎么获取训练的数据,网上有开放的数据集MIR-1k,下载地址如下:
http://mirlab.org/dataset/public/MIR-1K.rar
下载完数据,解压到dataset/下,结构如下图所示
在这里插入图片描述
数据集里有很多文件夹,其他的我们不管,我们只用到Wavfile和UndividedWavfile文件夹下的文件。简单介绍一下数据集,打开Wavfile文件夹
在这里插入图片描述
里面有1000个音频文件,随便播放一个,请忽略里面五音不全的唱功(这里还是对得向该数据集的制作者致敬,感谢你们的付出),注意听会发现,有一个声道的数据是纯背景音乐,另一个声道的数据是纯人声。有了这个特性,我们就可以很好的利用了,后面详解代码再说。UndividedWavfile文件夹下也是类似的音频文件,只是数量只有110个,正好我们可以使用Wavfile文件夹下的数据做训练集,用UndividedWavfile文件夹下的数据做测试集。

思路

有了数据集,接下来还的有思路,俗称套路。首先,我们现在做的是音频的项目, 做音频的项目,首先就得想到将时域转到频域,再做分析。

而神经网络的套路也基本是下面的几步:

  1. 创建占位符、变量
  2. 设置学习率和batch size等参数
  3. 构建神经网络
  4. 设置损失函数
  5. 设置优化器
  6. 创建会话
  7. 利用神经网络开始训练数据,一般都是mini-batch的方法

具体到我们的这个项目,我们应该做以下事情

  1. 导入需要训练的数据集文件路径,存到列表中即可
  2. 导入训练集数据,每一个训练集文件都是一个双声道的音频文件,其中,第一个声道存的是背景音乐,第二个声道存的是纯人声;我们需要三组数据,第一组是将双声道转成单声道的数据,即让背景音乐和人声混合在一起 第二组数据是纯背景音乐,第三组数据是纯人声数据
  3. 通过上一步获取的数据都是时域的,我们要通过短时傅里叶变换将声音数据转到频域
  4. 初始化网络模型
  5. 获取mini-batch数据,开始进行迭代训练

train主框架

有了套路,就开始撸代码,先来看看训练train部分的代码,代码在train.py文件里

#可以通过命令设置的参数:
#dataset_dir : 数据集路径
#model_dir : 模型保存的文件夹
#model_filename : 模型保存的文件名
#dataset_sr : 数据集音频文件的采样率
#learning_rate : 学习率
#batch_size : 小批量训练数据的长度
#sample_frames : 每次训练获取多少帧数据
#iterations : 训练迭代次数
#dropout_rate : dropout率
def parse_arguments(argv):parser = argparse.ArgumentParser()parser.add_argument('--dataset_train_dir', type=str, help='数据集训练数据路径', default='./dataset/MIR-1K/Wavfile')parser.add_argument('--dataset_validate_dir', type=str, help='数据集验证数据路径', default='./dataset/MIR-1K/UndividedWavfile')parser.add_argument('--model_dir', type=str, help='模型保存的文件夹', default='model')parser.add_argument('--model_filename', type=str, help='模型保存的文件名', default='svmrnn.ckpt')parser.add_argument('--dataset_sr', type=int, help='数据集音频文件的采样率', default=16000)parser.add_argument('--learning_rate', type=float, help='学习率', default=0.0001)parser.add_argument('--batch_size', type=int, help='小批量训练数据的长度', default=64)parser.add_argument('--sample_frames', type=int, help='每次训练获取多少帧数据', default=10)parser.add_argument('--iterations', type=int, help='训练迭代次数', default=30000)parser.add_argument('--dropout_rate', type=float, help='dropout率', default=0.95)return parser.parse_args(argv)if __name__ == '__main__':main(parse_arguments(sys.argv[1:]))

上面一些参数都有注释,比较简单就不再解释了,来看main函数做了什么

#训练模型,需要做以下事情
#1. 导入需要训练的数据集文件路径,存到列表中即可
#2. 导入训练集数据,每一个训练集文件都是一个双声道的音频文件,
#   其中,第一个声道存的是背景音乐,第二个声道存的是纯人声,
#   我们需要三组数据,第一组是将双声道转成单声道的数据,即让背景音乐和人声混合在一起
#   第二组数据是纯背景音乐,第三组数据是纯人声数据
#3. 通过上一步获取的数据都是时域的,我们要通过短时傅里叶变换将声音数据转到频域
#4. 初始化网络模型
#5. 获取mini-batch数据,开始进行迭代训练def main(args):#先看数据集数据是否存在if not os.path.exists(args.dataset_train_dir) or not os.path.exists(args.dataset_validate_dir):raise NameError('数据集路径"./dataset/MIR-1K/Wavfile"或"./dataset/MIR-1K/UndividedWavfile"不存在!')# 1. 导入需要训练的数据集文件路径,存到列表中即可train_file_list = load_file(args.dataset_train_dir)valid_file_list = load_file(args.dataset_validate_dir)

上面做的很简单,将我们要训练和验证的文件路径导入到相应的列表里就可以了。然后设置一些参数

# 数据集的采样率
mir1k_sr = args.dataset_sr
# 用于短时傅里叶变换,窗口大小
n_fft = 1024
# 步幅;帧移对应卷积中的stride;
hop_length = n_fft // 4# Model parameters
# 学习率
learning_rate = args.learning_rate# 用于创建rnn节点数
num_hidden_units = [1024, 1024, 1024, 1024, 1024]
# batch 长度
batch_size = args.batch_size
# 获取多少帧数据
sample_frames = args.sample_frames
# 训练迭代次数
iterations = args.iterations
# dropout
dropout_rate = args.dropout_rate# 模型保存路径
model_dir = args.model_dir
model_filename = args.model_filename

接着,我们就需要读取音频文件了,音频文件里保存的是时域的数据,读取文件后,使用快速傅里叶变换将它们转到频域中

#导入训练数据集的wav数据,
#wavs_mono_train存的是单声道,wavs_music_train 存的是背景音乐,wavs_voice_train 存的是纯人声
wavs_mono_train, wavs_music_train, wavs_voice_train = load_wavs(filenames = train_file_list, sr = mir1k_sr)
# 通过短时傅里叶变换将声音转到频域
stfts_mono_train, stfts_music_train, stfts_voice_train = wavs_to_specs(wavs_mono=wavs_mono_train, wavs_music=wavs_music_train, wavs_voice=wavs_voice_train, n_fft=n_fft,hop_length=hop_length)# 跟上面一样,只不过这里是测试集的数据
wavs_mono_valid, wavs_music_valid, wavs_voice_valid = load_wavs(filenames=valid_file_list, sr=mir1k_sr)
stfts_mono_valid, stfts_music_valid, stfts_voice_valid = wavs_to_specs(wavs_mono=wavs_mono_valid, wavs_music=wavs_music_valid, wavs_voice=wavs_voice_valid, n_fft=n_fft,hop_length=hop_length)

上面load_wavs函数的作用是分别获取左右声道的音频数据,以及获取双声道合并成单声道后的音频数据,实现代码如下,存在utils.py文件里

#   导入训练集数据,每一个训练集文件都是一个双声道的音频文件,
#   其中,第一个声道存的是背景音乐,第二个声道存的是纯人声,
#   我们需要三组数据,第一组是将双声道转成单声道的数据,即让背景音乐和人声混合在一起
#   第二组数据是纯背景音乐,第三组数据是纯人声数据
def load_wavs(filenames, sr):wavs_mono = list()wavs_music = list()wavs_voice = list()#读取wav文件,首先要求源文件是有双声道的音频文件,一个声道存的是背景音乐,另一个声道存的是纯人声#然后,将音频转成单声道,存入 wavs_mono#将背景音乐存入 wavs_music,#将纯人声存入 wavs_voicefor filename in filenames:wav, _ = librosa.load(filename, sr = sr, mono = False)assert (wav.ndim == 2) and (wav.shape[0] == 2), '要求WAV文件有两个声道!'wav_mono = librosa.to_mono(wav) * 2wav_music = wav[0, :]wav_voice = wav[1, :]wavs_mono.append(wav_mono)wavs_music.append(wav_music)wavs_voice.append(wav_voice)return wavs_mono, wavs_music, wavs_voice

wavs_to_specs函数则通过快速傅里叶变换将音频数据转到频域,使用librosa库的stft函数就可以了,实现代码如下

#通过短时傅里叶变换将声音转到频域
def wavs_to_specs(wavs_mono, wavs_music, wavs_voice, n_fft = 1024, hop_length = None):stfts_mono = list()stfts_music = list()stfts_voice = list()for wav_mono, wav_music, wav_voice in zip(wavs_mono, wavs_music, wavs_voice):stft_mono = librosa.stft(wav_mono, n_fft = n_fft, hop_length = hop_length)stft_music = librosa.stft(wav_music, n_fft = n_fft, hop_length = hop_length)stft_voice = librosa.stft(wav_voice, n_fft = n_fft, hop_length = hop_length)stfts_mono.append(stft_mono)stfts_music.append(stft_music)stfts_voice.append(stft_voice)return stfts_mono, stfts_music, stfts_voice

接着,就要初始化神经网络模型了,具体的模型我们后面再说,先看怎么初始化,代码如下

#初始化模型
model =  SVMRNN(num_features = n_fft // 2 + 1, num_hidden_units = num_hidden_units)

就这么简单,然后,我们可能会在训练途中中断训练(比如断电啊),如果不边训练边保存模型,那么对于用CPU来训练的同学来说就非常痛苦了。所以,先加载模型,如果还没有模型,我们就初始化变量就OK了

# 加载模型,如果没有模型,则初始化所有变量
startepo = model.load(file_dir = model_dir)print('startepo:' + str(startepo))
然后,开始进入迭代训练的for循环中了,
#开始训练
for i in (range(iterations)):#从模型中断处开始训练if i < startepo:continue

在for循环中,获取下一个batch数据,这个数据是要喂给神经网络进行训练的,看过以前教程的对这一步应该比较熟悉了

# 获取下一batch数据
data_mono_batch, data_music_batch, data_voice_batch = get_next_batch(stfts_mono = stfts_mono_train, stfts_music = stfts_music_train, stfts_voice = stfts_voice_train,batch_size = batch_size, sample_frames = sample_frames)

那么这个batch怎么获取呢?我们是不是需要随机的获取一小段单声道的数据,和同个时间段对应的背景音乐的数据和人声数据就可以了?代码如下

#stfts_mono:单声道stft频域数据
#stfts_music:背景音乐stft频域数据
#stfts_music:人声stft频域数据
#batch_size:batch大小
#sample_frames:获取多少帧数据
def get_next_batch(stfts_mono, stfts_music, stfts_voice, batch_size = 64, sample_frames = 8):stft_mono_batch = list()stft_music_batch = list()stft_voice_batch = list()#随即选择batch_size个数据collection_size = len(stfts_mono)collection_idx = np.random.choice(collection_size, batch_size, replace = True)for idx in collection_idx:stft_mono = stfts_mono[idx]stft_music = stfts_music[idx]stft_voice = stfts_voice[idx]#有多少帧num_frames = stft_mono.shape[1]assert  num_frames >= sample_frames#随机获取sample_frames帧数据start = np.random.randint(num_frames - sample_frames + 1)end = start + sample_framesstft_mono_batch.append(stft_mono[:,start:end])stft_music_batch.append(stft_music[:,start:end])stft_voice_batch.append(stft_voice[:,start:end])#将数据转成np.array,再对形状做一些变换# Shape: [batch_size, n_frequencies, n_frames]stft_mono_batch = np.array(stft_mono_batch)stft_music_batch = np.array(stft_music_batch)stft_voice_batch = np.array(stft_voice_batch)# Shape for RNN: [batch_size, n_frames, n_frequencies]data_mono_batch = stft_mono_batch.transpose((0, 2, 1))data_music_batch = stft_music_batch.transpose((0, 2, 1))data_voice_batch = stft_voice_batch.transpose((0, 2, 1))return data_mono_batch, data_music_batch, data_voice_batch

这个separate_magnitude_phase函数的实现也很简单,代码如下

#通过短时傅里叶变换后的结果是复数的,而我们训练时,
#只需要考虑频率部分就可以了,所以将频率和相位分离出来
def separate_magnitude_phase(data):return np.abs(data), np.angle(data)

接着,就将数据喂给神经网络来进行训练了

#送入神经网络,开始训练
train_loss = model.train(x_mixed_src = x_mixed_src, y_music_src = y_music_src, y_voice_src = y_voice_src,learning_rate = learning_rate, dropout_rate = dropout_rate)

然后就是一些打印损失和测试模型的代码了

if i % 10 == 0:print('Step: %d Train Loss: %f' %(i, train_loss))if i % 200 == 0:#这里是测试模型准确率的print('==============================================')data_mono_batch, data_music_batch, data_voice_batch = get_next_batch(stfts_mono = stfts_mono_valid, stfts_music = stfts_music_valid,stfts_voice = stfts_voice_valid, batch_size = batch_size, sample_frames = sample_frames)x_mixed_src, _ = separate_magnitude_phase(data = data_mono_batch)y_music_src, _ = separate_magnitude_phase(data = data_music_batch)y_voice_src, _ = separate_magnitude_phase(data = data_voice_batch)y_music_src_pred, y_voice_src_pred, validate_loss = model.validate(x_mixed_src = x_mixed_src,y_music_src = y_music_src, y_voice_src = y_voice_src, dropout_rate = dropout_rate)print('Step: %d Validation Loss: %f' %(i, validate_loss))print('==============================================')if i % 200 == 0:model.save(directory = model_dir, filename = model_filename, global_step=i)

train.py的大致框架就如上所述了,我们接着来看神经网络模型怎么建的

神经网络SVMRNN类

我们将神经网络SVMRNN类写到model.py文件中,先来看初始化函数__init__

# num_features:音频特征数
# num_hidden_units:rnn 神经元数
# tensorboard_dir: tensorboard保存的路径
def __init__(self, num_features, num_hidden_units = [256, 256, 256]):# 保存传入的参数self.num_features = num_featuresself.num_rnn_layer = len(num_hidden_units)self.num_hidden_units = num_hidden_units# 设置变量# 训练了多少步self.g_step = tf.Variable(0, dtype=tf.int32, name='g_step')# 设置占位符# 学习率self.learning_rate = tf.placeholder(tf.float32, shape=[], name='learning_rate')#混合了背景音乐和人声的数据self.x_mixed_src = tf.placeholder(tf.float32, shape=[None, None, num_features], name='x_mixed_src')#背景音乐数据self.y_music_src = tf.placeholder(tf.float32, shape=[None, None, num_features], name='y_music_src')#人声数据self.y_voice_src = tf.placeholder(tf.float32, shape=[None, None, num_features], name='y_voice_src')#keep dropout,用于RNN网络的droupoutself.dropout_rate = tf.placeholder(tf.float32)#初始化神经网络self.y_pred_music_src, self.y_pred_voice_src = self.network_init()# 设置损失函数self.loss = self.loss_init()# 设置优化器self.optimizer = self.optimizer_init()#创建会话self.sess = tf.Session()#需要保存模型,所以获取saverself.saver = tf.train.Saver(max_to_keep=1)

设置变量、占位符,初始化神经网络,设置损失函数,设置优化器,创建会话,保存模型,是不是都是很熟悉的那一套啊?

顺着上面的代码,我们来看看初始化神经网络的函数network_init的实现

#构建神经网络
def network_init(self):rnn_layer = []#根据num_hidden_units的长度来决定创建几层RNN,每个RNN长度为sizefor size in self.num_hidden_units:#使用GRU,同时,加上dropoutlayer_cell = tf.nn.rnn_cell.GRUCell(size)layer_cell = tf.contrib.rnn.DropoutWrapper(layer_cell, input_keep_prob=self.dropout_rate)rnn_layer.append(layer_cell)#创建多层RNNmulti_rnn_cell = tf.nn.rnn_cell.MultiRNNCell(rnn_layer)outputs, state = tf.nn.dynamic_rnn(cell = multi_rnn_cell, inputs = self.x_mixed_src, dtype = tf.float32)#全连接层y_dense_music_src = tf.layers.dense(inputs = outputs,units = self.num_features,activation = tf.nn.relu,name = 'y_dense_music_src')y_dense_voice_src = tf.layers.dense(inputs = outputs,units = self.num_features,activation = tf.nn.relu,name = 'y_dense_voice_src')y_music_src = y_dense_music_src / (y_dense_music_src + y_dense_voice_src + np.finfo(float).eps) * self.x_mixed_srcy_voice_src = y_dense_voice_src / (y_dense_music_src + y_dense_voice_src + np.finfo(float).eps) * self.x_mixed_srcreturn y_music_src, y_voice_src

上面就是我们神经网络结构的核心了,N层RNN网络,再加一个全连接层,接着来看损失函数

#损失函数
def loss_init(self):with tf.variable_scope('loss') as scope:#求方差loss = tf.reduce_mean(tf.square(self.y_music_src - self.y_pred_music_src)+ tf.square(self.y_voice_src - self.y_pred_voice_src), name='loss')return loss

然后就是优化器

#优化器
def optimizer_init(self):ottimizer = tf.train.AdamOptimizer(learning_rate=self.learning_rate).minimize(self.loss)return ottimizer

保存和加载模型的函数

#保存模型
def save(self, directory, filename, global_step):#如果目录不存在,则创建if not os.path.exists(directory):os.makedirs(directory)self.saver.save(self.sess, os.path.join(directory, filename), global_step=global_step)return os.path.join(directory, filename)# 加载模型,如果没有模型,则初始化所有变量
def load(self, file_dir):# 初始化变量self.sess.run(tf.global_variables_initializer())# 没有模型的话,就重新初始化kpt = tf.train.latest_checkpoint(file_dir)print("kpt:", kpt)startepo = 0if kpt != None:self.saver.restore(self.sess, kpt)ind = kpt.find("-")startepo = int(kpt[ind + 1:])return startepo

然后就是训练、验证、测试模型的函数

#保存模型
def save(self, directory, filename, global_step):#如果目录不存在,则创建if not os.path.exists(directory):os.makedirs(directory)self.saver.save(self.sess, os.path.join(directory, filename), global_step=global_step)return os.path.join(directory, filename)# 加载模型,如果没有模型,则初始化所有变量
def load(self, file_dir):# 初始化变量self.sess.run(tf.global_variables_initializer())# 没有模型的话,就重新初始化kpt = tf.train.latest_checkpoint(file_dir)print("kpt:", kpt)startepo = 0if kpt != None:self.saver.restore(self.sess, kpt)ind = kpt.find("-")startepo = int(kpt[ind + 1:])return startepo

代码写完了,在终端执行python train.py就开始训练了
可以看到,损失在慢慢下降,说明我们的模型起到作用了,运行到最后损失大概再0.5-0.6之间

测试代码

上面只是在训练啊,我们要把它用起来啊,所以还要再写个测试代码test.py,跟train的代码有点类似,首先也是一些参数的设置

def parse_arguments(argv):parser = argparse.ArgumentParser()parser.add_argument('--input_dir', type=str, help='待测试的音频文件的文件夹,存放MP3文件', default='./songs/input')parser.add_argument('--output_dir', type=str, help='声乐分离后的视频文件目录,为WAV格式', default='./songs/output')parser.add_argument('--model_dir', type=str, help='模型保存的文件夹', default='./model')parser.add_argument('--model_filename', type=str, help='模型保存的文件名', default='svmrnn.ckpt')parser.add_argument('--dataset_sr', type=int, help='数据集音频文件的采样率', default=16000)parser.add_argument('--dropout_rate', type=float, help='dropout率', default=0.95)return parser.parse_args(argv)if __name__ == '__main__':main(parse_arguments(sys.argv[1:]))

如果想调整参数,在运行命令行的时候传入参数就可以了,接着来看main函数

def main(args):input_dir = args.input_diroutput_dir = args.output_dirdataset_sr = args.dataset_srmodel_dir = args.model_dirdropout_rate = args.dropout_rate#如果输入目录不存在,返回错误if not os.path.exists(input_dir):raise NameError('音频输入文件夹"./songs/input"不存在!')#输出文件夹不存在,则创建if not os.path.exists(output_dir):os.mkdir(output_dir)#找到要分离背景音乐和人声的音频文件song_filenames = list()for file in os.listdir(input_dir):if file.endswith('.mp3'):song_filenames.append(os.path.join(input_dir, file))

我们将待测试的音频文件放到songs/input文件夹下,最后得到的结果保存到songs/output文件夹下,所以先检查输入文件夹是否存在先,如果存在,将里面的MP3文件放到列表中,接着就是读取这些音频文件了

#加载输入音频文件
wavs_mono = list()
for filename in song_filenames:wav_mono, _ = librosa.load(filename, sr=dataset_sr, mono=True)wavs_mono.append(wav_mono)
然后,设置一些参数,接着把音频文件的数据从时域转到频域,
# 用于短时傅里叶变换,窗口大小
n_fft = 1024
# 步幅;帧移对应卷积中的stride;
hop_length = n_fft // 4
# 用于创建rnn节点数
num_hidden_units = [1024, 1024, 1024, 1024, 1024]#将其转到频域
stfts_mono = list()
for wav_mono in wavs_mono:stft_mono = librosa.stft(wav_mono, n_fft = n_fft, hop_length = hop_length)stfts_mono.append(stft_mono.transpose())

然后,初始化神经网络,并导入我们上面训练好的模型

#初始化神经网络
model = SVMRNN(num_features = n_fft // 2 + 1, num_hidden_units = num_hidden_units)
#导入模型
model.load(file_dir = model_dir)

接着就对文件一一处理了

for wav_filename, wav_mono, stft_mono in zip(song_filenames, wavs_mono, stfts_mono):wav_filename_base = os.path.basename(wav_filename)#单声道音频文件wav_mono_filename = wav_filename_base.split('.')[0] + '_mono.wav'#分离后的背景音乐音频文件wav_music_filename = wav_filename_base.split('.')[0] + '_music.wav'#分离后的人声音频文件wav_voice_filename = wav_filename_base.split('.')[0] + '_voice.wav'#要保存的文件的相对路径wav_mono_filepath = os.path.join(output_dir, wav_mono_filename)wav_music_hat_filepath = os.path.join(output_dir, wav_music_filename)wav_voice_hat_filepath = os.path.join(output_dir, wav_voice_filename)print('Processing %s ...' % wav_filename_base)stft_mono_magnitude, stft_mono_phase = separate_magnitude_phase(data = stft_mono)stft_mono_magnitude = np.array([stft_mono_magnitude])y_music_pred, y_voice_pred = model.test(x_mixed_src = stft_mono_magnitude, dropout_rate = dropout_rate)# 根据振幅和相位,转为复数,用于下面的逆短时傅里叶变换y_music_stft_hat = combine_magnitude_phase(magnitudes = y_music_pred[0], phases = stft_mono_phase)y_voice_stft_hat = combine_magnitude_phase(magnitudes = y_voice_pred[0], phases = stft_mono_phase)y_music_stft_hat = y_music_stft_hat.transpose()y_voice_stft_hat = y_voice_stft_hat.transpose()#逆短时傅里叶变换,将数据从频域转到时域y_music_hat = librosa.istft(y_music_stft_hat, hop_length = hop_length)y_voice_hat = librosa.istft(y_voice_stft_hat, hop_length = hop_length)#保存数据librosa.output.write_wav(wav_mono_filepath, wav_mono, dataset_sr)librosa.output.write_wav(wav_music_hat_filepath, y_music_hat, dataset_sr)librosa.output.write_wav(wav_voice_hat_filepath, y_voice_hat, dataset_sr)

代码写好后,将任意一个MP3文件放到input文件夹下,运行python test.py就开始工作了,得到结果如下

可以听到,提取出来的背景音乐还是有点人声的,不过相对原文件人声已经小很多了,而纯人声中,仔细听也还能听到很小很小的乐器的声音,毕竟我们的损失没有降到接近0,所以并不是太完美,但是效果还可以了

因为时间限制,只训练到了19200步,不过损失已经没有明显的下降了,源码链接如下:
点击下载
0zvm

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/52205.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

推荐一个在线实现音乐可视化的网站

场景&#xff1a; 可以录入麦克风、MP3等&#xff0c;实现音乐可视化 链接 https://www.uberviz.io/

7个好用到爆的音频、配乐素材网站,BGM都在这里了

现在只要有一部手机&#xff0c;人人都能成为视频创作者。一个好的视频不能缺少的就是内容、配乐&#xff0c;越来越注重版权的当下&#xff0c;音效素材使用不当造成侵权的案例层出不穷。为了避免侵权&#xff0c;找素材让很多创作者很头疼。 今天我就整理了7个可以免费下载&…

每个人都能制作的简易版QQ音乐(HTML+CSS+JQuery)

自制系列二它来了。 如果在制作过程中有如何问题你都可以私信我&#xff0c;我会答复你的。 今天中秋节&#xff0c;首先祝大家中秋节快乐&#xff01; 因为没什么礼物送给大家&#xff0c;所以在这里给大家安利一份简易版QQ音乐的制作&#xff0c;过程很简单&#xff0c;每…

音乐app、app原型、音乐原型、云音乐、听歌、电台、本地音乐、点赞、收藏、歌单广场、动态、社区、评论、歌词、歌手、主播、视频、云村、下载、翻唱、歌曲播放、订阅、频道、引导页、登录注册、axure原型

音乐app、app原型、音乐原型、云音乐、听歌、电台、本地音乐、点赞、收藏、歌单广场、动态、社区、评论、歌词、歌手、主播、视频、云村、下载、翻唱、歌曲播放、订阅、频道、引导页、登录注册、axure原型 Axure原型演示及下载地址&#xff1a; 登陆 (首次打开) (pmdaniu.com)…

音乐网站设计

设计内容&#xff1a; 音乐网站网站是一款提供在线播放音乐和下载音乐功能的网站&#xff0c;具有音乐排行榜、歌星排行榜、音乐分类三个板块&#xff0c;并提供查询功能&#xff0c;要求如下&#xff1a; ① 页面布局合理&#xff0c;色彩和谐&#xff0c;链接正确&#xff0c…

音乐app、音乐原型、在线音乐、云音乐、听歌、电台、本地音乐、点赞、收藏、歌单广场、动态、社区、评论、歌词、歌手、主播、视频、云村、下载、翻唱、歌曲播放、订阅、频道、引导页、登录注册、axure原型

音乐app、音乐原型、在线音乐、云音乐、听歌、电台、本地音乐、点赞、收藏、歌单广场、动态、社区、评论、歌词、歌手、主播、视频、云村、下载、翻唱、歌曲播放、订阅、频道、引导页、登录注册、axure原型、产品原型 Axure原型演示及下载地址&#xff1a;Axure Cloud - Gener…

【学习笔记】穿T恤听古典音乐

文章目录 1 走进古典音乐1.1 音乐中的自然法则1.2 音乐要素如何模仿1.3 模仿与超越 2 每一天的巴赫2.1 巴赫的故事与作品2.2 对位法2.3 数学之美 3 莫扎特&#xff1a;把日子过成歌剧3.1 《莫扎特传》序曲——唐璜3.2 历史地位与风格演变3.3 咏叹调与宣叙调3.4 《后宫诱逃》3.5…

如何找到能商用的背景纯音乐

很多时候&#xff0c;我们在网上下载的音乐都是不能商用的。如果要商用就必须向作者购买版权授权。对于一些自媒体、博主、小公司等&#xff0c;这将是一笔不菲的费用。那么&#xff0c;哪里有免费可商用的背景配乐吗&#xff1f; 有的&#xff0c;那就是版权协议为CC0的公共音…

设计师精选实用AI工具合集 | Midjourney 、GPT等...

作为一名设计师&#xff0c;我们都知道&#xff0c;在智能化技术的推动下及ChatGPT的突然爆火&#xff0c;越来越多的AI工具正在被设计师广泛应用于日常工作中。 在这里给设计师们介绍几款功能强大、易于使用的AI设计工具。 第一款&#xff0c;基于 GPT 的 Figma 配色生成插件…

比尔·盖茨退出微软董事会,回顾盖茨与微软的传奇故事

作者&#xff5c;年素清 责编&#xff5c;伍杏玲 出品&#xff5c;CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 头图&#xff5c;视觉中国 微软于周五宣布&#xff0c;公司联合创始人兼技术顾问比尔盖茨&#xff08;Bill Gates&#xff09;辞去微软董事会职务。 对于这…

后盖茨的IT世界

本文应《中华读书报》之邀所写。 图1 Joel Spolsky的新书More Joelon Software中文版,人民邮电出版社即将出版图2 The Big Switch,中文版,中信出版社 比尔盖茨今以壮岁之年隐退&#xff0c;不再掌管微软帝国的日常工作&#xff0c;标志着一个时代的结束。过渡从两年前就开始…

电子计算机比尔盖茨和微软品牌,尉迟:比尔盖茨卖安全套 牌子不能叫微软

核心提示&#xff1a;真正的土豪通常有更重要的事做&#xff0c;比方说比尔盖茨。IT男跨界转行做安全套。预计是明年2015年推出上市。但是估计不能延续以前的品牌&#xff0c;叫“微软安全套”&#xff0c;这个要改。 凤凰卫视9月27日《笑逐言开》&#xff0c;以下为文字实录&a…

比尔盖茨为什么能成为世界首富?

说到比尔盖茨的财富&#xff0c;很多人可能首先想到的是比尔盖茨精明的投资&#xff0c;因为这些年他通过跟巴菲特学投资&#xff0c;光靠投资就带来了超过700亿美元的财富&#xff0c;而微软所带来的财富只占其总财富的1/8左右。 但我想说的是&#xff0c;投资确实给比尔盖茨带…

你见过比尔盖茨38年前写的MicrosoftBasic代码吗

你见过比尔盖茨38年前写的MicrosoftBasic代码吗 2016-11-15 06:07 编辑&#xff1a; suiling 分类&#xff1a;程序人生 来源&#xff1a;w3cschoolcn 1 2830 程序员比尔盖茨 招聘信息&#xff1a; iOS开发工程师移动APP研发工程师产品经理/Product ManagerUnity开发工程师…

比尔盖茨/UNIX之父/Donald Knuth/Dijkstra等全球IT大师的编程名言

这不是一个bug,这只是一个未列出来的特性。——匿名 ​​ ​ Dennis Ritchie

比尔·盖茨1978年写的古老程序曝光:IT人膜拜

官方网站 www.itilzj.com 官方文库: wenku.itilzj.com 比尔盖茨31岁&#xff0c;就成为世界首富。很多人好奇&#xff0c;作为世界第一大PC系统的创始人&#xff0c;抛弃世界首富的头衔&#xff0c;单单从程序员角度来讨论&#xff0c;比尔盖茨的代码水平如何&#xff1f; 其实…

微软创始人 比尔·盖茨

比尔盖茨 比尔盖茨&#xff08;Bill Gates&#xff09;&#xff0c;全名威廉亨利盖茨&#xff08;William Henry Gates&#xff0c;1955年10月28日&#xff0d;&#xff09;&#xff0c;美国微软公司的董事长。他与保罗艾伦一起创建了微软公司&#xff0c;曾任微软CEO和首席软件…

有钱真的能为所欲为,微软用75亿美元解决了比尔盖茨的“心头大患”

全世界只有3.14 % 的人关注了 数据与算法之美 2018年6月4日&#xff0c;微软在官方博客上宣布&#xff1a;以75 亿美元的价格收购了全球最大的开源代码托管平台GitHub。 谁也没想到&#xff0c;微软和开源这场长达几十年的战争&#xff0c;到最后双方竟然喜结连理了。 不过&…

比尔盖茨聘请投资高手,26年亏掉4300亿美金!

作者| Mr.K 整理| Emma 来源| 技术领导力(ID&#xff1a;jishulingdaoli) 大年初五&#xff0c;聊聊挣钱的话题&#xff0c;先从比尔盖茨的故事说起&#xff1a; 2020年末&#xff0c;比尔盖茨身价1072亿美金&#xff0c;创了历史新高。其中&#xff0c;他名下微软3%的股票市…