第37回 レーティングに応じた重み付け再生する

今回はレーティングがついた曲の再生頻度を高める処理を追加する。

曲のレーティングだけなら再生する曲を決めるときに重み付けすればいいが、
アーティストのレーティングもあるとリアルタイムの重み付けは大変になりそうなので、
再生フォルダを読み込むときに重み付けデータ_listnRatingWeightItemを作成する形にした。
再生時にはGetNextIndex()でそれを加味して重み付けしている。

"重み"はGetRatingWeightPlayCount()で決め、今回は曲レーティングの5倍、アーティストレーティングの3倍で重み付けした。
(曲レーティング1なら5倍、曲レーティング5&アーティストレーティング5なら40倍の頻度で再生される)

■Form1.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Threading;
using System.Windows.Forms;
using WMPLib;

namespace MP3Player
{
	public partial class Form1 : Form
	{
		WindowsMediaPlayer _mediaPlayer = new WindowsMediaPlayer();

		System.Windows.Forms.Timer _timer = new System.Windows.Forms.Timer();

		public static Option _option = new Option();


		List<AudioItem> _listFiles;			//音楽ファイル一覧
		int _nCurrentIndex = -1;			//↑へのインデックス
		List<int> _listnRatingWeightItem = new List<int>();	//↑↑へのインデックス。レイティングで重み付けした数だけ格納		//追加


		List<int> _listPlayHistory = new List<int>();		//過去の再生曲
		List<int> _listPlayNext = new List<int>();			//未来の再生曲。なければランダム


		bool _bStopButtonPushed = false;	//「停止」ボタンを押したらtrue
		/// <summary>
		/// 設定フォルダから音楽ファイルリストを読み込む
		/// </summary>
		void CreateFileListAndPlay(bool bPlay)
		{
			buttonStop_Click(null, null);		//再生停止

			//再生リストのクリア
			_listPlayHistory.Clear();
			_listPlayNext.Clear();
			_listnRatingWeightItem.Clear();		//追加
			_nCurrentIndex = -1;

			_dlgCreateFileList.Init();
			_dlgCreateFileList.StartPosition = FormStartPosition.Manual;
			_dlgCreateFileList.Location = new Point(Location.X + 50, Location.Y + 50);
			_dlgCreateFileList.Show(this);

			Thread thread = new Thread(new ThreadStart(delegate
				{
					{
						DialogResult ret = MessageBox.Show("ファイル読み込みだけでなく、DB更新もしますか?\n(時間がかかります)", "ファイル読み込み", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
						if (ret == DialogResult.OK)
						{
							//DB更新
							MP3Info.RefreshAllInfo(false, _dlgCreateFileList);
						}
					}

					//mp3フォルダからの音楽ファイルリスト読み込み
					_listFiles = EnumFiles(_option.strFolder, _dlgCreateFileList, _listnRatingWeightItem);		//変更

					try
					{
						Invoke((MethodInvoker)delegate
						{
							_dlgCreateFileList.Close();
						});
					}
					catch (Exception)
					{
					}

					if (bPlay)
					{
						Invoke((MethodInvoker)delegate
						{
							Play();		//再生開始
						});
					}
				}));

			thread.Start();
		}
		/// <summary>
		/// 次の再生曲インデックスを決める
		/// </summary>
		int GetNextIndex()
		{
			if (_listFiles.Count == 0)
				return -1;

			int nIndex = 0;
			Random rnd = new Random(Environment.TickCount);

			bool bFound = false;

			for (int i = 0; i < 200; i++)		//200回曲検索試行
			{
				if (_listPlayNext.Count == 0)
				{
					//変更
					//未来の曲リストが空ならランダムで曲を決定
					//レーティングに応じた重み付けがされる
					nIndex = rnd.Next(0, _listFiles.Count + _listnRatingWeightItem.Count);

					if (nIndex >= _listFiles.Count)
						nIndex = _listnRatingWeightItem[nIndex - _listFiles.Count];
				}
				else
				{
					//未来の曲リストから次の曲を決定
					nIndex = _listPlayNext[0];
					_listPlayNext.RemoveAt(0);
				}

				//同じ曲は連続で演奏しない
				if (nIndex == _nCurrentIndex)
					continue;

				//NGファイル指定されていないかチェック
				if (_option.IsNGFile(_listFiles[nIndex]))
					continue;

				//mp3情報を取得
				string strTitle;
				string strArtist;
				string strAlbum;
				MP3Info.GetMp3Info(_listFiles[nIndex], out strTitle, out strArtist, out strAlbum);

				//アーティストがNG指定されていないかチェック
				if (_option.IsNGArtist(strArtist))
					continue;

				//曲名がNGワードを含まないかチェック
				if (_option.IsNGWord(strTitle))
					continue;

				//ファイル追加日時が再生条件を満たすかチェック
				if (_option.IsPlayDayTermOK(_listFiles[nIndex]) == false)
					continue;

				//曲レーティングが再生条件を満たすかチェック
				if (_option.IsPlayRatingOK(_listFiles[nIndex]) == false)
					continue;

				//アーティストレーティングが再生条件を満たすかチェック
				if (_option.IsPlayRatingArtistOK(strArtist) == false)
					continue;

				//いずれかのレーティングが再生条件を満たすかチェック
				if (_option.IsPlayRatingAnyOK(_listFiles[nIndex], strArtist) == false)
					continue;

				bFound = true;
				break;
			}

			if (bFound == false)
			{
				//次の再生曲を決定できなかった
				//過去の曲もしくはインデックスゼロを再生
				if (_listPlayHistory.Count > 0)
				{
					//過去の曲からランダムに決定
					nIndex = rnd.Next(0, _listPlayHistory.Count);
				}
				else
				{
					nIndex = 0;
				}
			}

			return nIndex;
		}



		/// <summary>
		/// フォルダ内のファイルを一覧して返す
		/// 
		/// dlg.bCancel==trueになったら処理を中断して抜ける
		/// </summary>
		List<AudioItem> EnumFiles(string strFolder, ProgressForm dlg = null, List<int> listnRatingWeightItem = null)		//変更
		{
			List<AudioItem> ret = new List<AudioItem>();

			//指定フォルダ以下の全子フォルダから全ファイルを抜き出す
			IEnumerable<string> listFiles = Directory.EnumerateFiles(strFolder, "*.*", SearchOption.AllDirectories);
			//↑の処理は遅いが途中で中断できない

			//追加
			AudioItem item;
			string strTitle;
			string strArtist;
			string strAlbum;
			int nCount;

			foreach (string strFile in listFiles)
			{
				if (dlg != null)
				{
					try
					{
						dlg.strProgress = "" + ret.Count;
						if (dlg.bCancel)
							break;
					}
					catch (Exception)
					{
					}
				}

				//見つかったファイルの拡張子を取り出し
				string strExt = Path.GetExtension(strFile).ToLower();
				if (strExt == "")
					continue;

				//mp3/m4aならそのまま追加
				if (strExt == ".mp3" || strExt == ".m4a")
				{
					//追加
					item = new AudioItem(strFile);

					MP3Info.GetMp3Info(item, out strTitle, out strArtist, out strAlbum);
					if (_option.IsNGFile(item) || _option.IsNGArtist(strArtist) || _option.IsNGWord(strTitle))
						continue;			//NGなら処理しない

					//レーティングで重みづけた再生回数リスト化
					if (listnRatingWeightItem != null)
					{
						nCount = GetRatingWeightPlayCount(item, strTitle, strArtist, strAlbum);
						for (int j = 0; j < nCount; j++)
						{
							listnRatingWeightItem.Add(ret.Count);		//ret.Count == この曲へのインデックス
						}
					}

					ret.Add(item);		//変更
					continue;
				}

				//ZIPファイルなら書庫に含まれるmp3/m4aファイルのエントリーを追加
				if (strExt == ".zip")
				{
					try
					{
						using (ZipArchive archive = ZipFile.OpenRead(strFile))
						{
							for (int i = 0; i < archive.Entries.Count; i++)
							{
								if (dlg != null)
								{
									try
									{
										dlg.strProgress = "" + ret.Count;
										if (dlg.bCancel)
											break;
									}
									catch (Exception)
									{
									}
								}

								string strExtension = Path.GetExtension(archive.Entries[i].FullName).ToLower();
								if (strExtension == ".mp3" || strExtension == ".m4a")
								{
									//追加
									item = new AudioItem(strFile, i);

									MP3Info.GetMp3Info(item, out strTitle, out strArtist, out strAlbum);
									if (_option.IsNGFile(item) || _option.IsNGArtist(strArtist) || _option.IsNGWord(strTitle))
										continue;			//NGなら処理しない

									//レーティングで重みづけた再生回数リスト化
									if (listnRatingWeightItem != null)
									{
										nCount = GetRatingWeightPlayCount(item, strTitle, strArtist, strAlbum);
										for (int j = 0; j < nCount; j++)
										{
											listnRatingWeightItem.Add(ret.Count);		//ret.Count == この曲へのインデックス
										}
									}

									ret.Add(item);		//変更
								}
							}
						}
					}
					catch (Exception)
					{
					}
				}

			}

			return ret;
		}



		//追加
		/// <summary>
		/// レーティングで重みづけた再生回数を決める
		/// </summary>
		int GetRatingWeightPlayCount(AudioItem item, string strTitle, string strArtist, string strAlbum)
		{
			int nRating = _option.GetRating(item);
			int nRatingArtist = _option.GetRatingArtist(strArtist);

			return (nRating * 5 + nRatingArtist * 3);
		}

プロジェクトファイルをダウンロード


カテゴリー「MP3プレーヤーを作る(C#)」 のエントリー