C言語コンソールプログラムに基づく簡易MP 3音楽プレーヤー


これは私たちの小学期の最初の大きな宿題で、感じが深いので、このブログを書いて記念に残します.
内容:再生制御と音量調整機能を備えたコンソール音楽プレーヤーを設計し、再生制御のサブメニューで再生一時停止切り替え、現在の曲の停止、前の曲と次の曲の再生機能を実現する.メインメニューに入る前に、プロジェクトファイル内のすべてのフォルダを巡り、mp 3拡張子の音楽ファイルを画面に表示できます.
関連資料を調べる:
1.sprintf(wspprintf関数の使用)
(1)sprintf
関数機能:フォーマットされたデータを文字列に書き込む
関数プロトタイプ:intsprintf(char*buffer,const char*format[,argument]...);
戻り値:文字列長(strlen)
eg. 
   char* who = "I";
char* whom = "CSDN";
sprintf(s, "%s love %s.", who,whom);//生成:「I love CSDN.」この文字列はsに書きます
 
sprintf(s, "%10.3f", 3.1415626);//生成:3.142
(2)wsprintf
関数機能:一連の文字と数値をバッファに入力します.出力バッファの値は、フォーマット・ディスクリプタ("%)に依存します.文字が書き込まれている場合、この関数は書き込まれた文字の末尾に'0'を追加します.
戻り値:書き込みの長さですが、最後の'0'は含まれません.
関数プロトタイプ:intwsprintf(LPTSTR lpOut,//出力バッファ、最大1024バイト
LPCTSTR lpFmt,//形式文字列
...//パラメータリストを出力する必要があります//この関数のパラメータの個数は確定できません
2.mciSendString
mciSendStringはマルチメディアファイルを再生するためのAPI命令で、MPEG、AVI、WAV、MP 3などのマルチメディアファイルを再生することができる.使用時にヘッダファイルを含める必要があります.
3.VS 2010などのより高いバージョンのvisual studioコンパイラのUnicode文字符号化は2バイトを占有し、これとVC 6.0が1バイトで異なるため、コンソールプログラムが音楽を再生できない可能性があります.
4.コンパイラIDEの適合システムについて、VC 6.0中国語版はwin 10システム上で運行することができなくて、ネット上で1つの英語のバッグをダウンロードして元の漢化のバッグをカバーすればいいです.
小結
先生が私たちにコード構造をコードして最適化する過程で、私はどのようにC言語のいくつかの基本的な文法点で実用的なソフトウェアを構築するかを体得しました.これは大学1年生になってから初めて応用に近い実戦プロジェクトです.
4日間の段階別モジュール符号化過程においても、C言語の配列、ポインタ、関数などの内容がどのように工程実践と結合し、アーキテクチャを最適化し、異なるモジュールの結合度を低減し、コンパイラの誤り訂正特性を利用して、コードの頑丈性と誤り許容性を高めるかを認識した.
1.簡単なソフトウェアのメニュー選択は常に条件文を使用し、メニューオプションが多すぎる場合、switchはif-else文より効率が高い(switch-case文は目標に直行し、if-else文は順番に逐次検索する.しかし、switchの入口変数は整数データまたは単一文字でしかなく、これはその限界である).
2.モジュール化プログラミングは常にヘッダファイル分割の方法を使用し、1つのヘッダファイルには一般的にこのファイルが外部に提供するインタフェース(他のファイルで使用する変数と関数宣言)を書く.
3.ソフトウェア開発において、制御変数と関数の役割ドメインと生存期間を限定することがしばしば必要である.C言語に関連する2つのキーワードはstaticとexternである.複数のメニューで1つの変数を共有する必要があるか、または1つの状態を共通に使用する必要がある場合、静的ローカル変数は、静的ローカル変数が明示的に付与されていない場合にコンパイルされると自動的に0が付与され、次回定義される関数内で前回実行された値が保持され、自動変数が初期値が付与されていない場合は不確定な値であるため、静的ローカル変数は常に使用されます.論理的正確性にかかわらず、PlayControl Menu()関数内の再生状態列挙変数は、再生、一時停止、停止の3つの機能が共有され、変更に共通するためstaticとして設定されるなど、関数が保持されず、関数に入るたびに解放空間が申請される.
externのグローバル変数は、コードのカプセル化性を低下させるため、externを使用しない方法は、通常、C++クラスのメンバーアクセス権限の考え方を参考にして、外部で簡単に変更できないデータにgetXX関数インタフェースを設定します.(例えば、このエンジニアリングコードが最も称賛に値するのは、後期モジュール化の過程で、プレイリストに関連するすべての配列、変数、およびPlayInterface.cにおけるPlayControl Menu関数におけるリスト変換に関するコードセグメントを抽出し、基本操作でgetXX関数を記述し、PlayList.cファイルに独立してカプセル化し、曲番号がMp 3 Player.c、PlayList.cの2つになることを回避することである.ファイル共有でグローバル変数を設定せざるを得ない場合.)
4.その他のいくつかの小さな注意点:
(1)ループ判定条件における変数については,工程実践では通常ループ外で−1に初期化されているが,これは−1がメモリに符号化されたバイナリ形式がすべて1である特性を利用して,予知不可能な論理誤りを最大限に回避する.
(2)scanfは、バックを押してからバッファに一時保存されている文字を送信するにはgetch関数を使用します.これにより、キーを押すとすぐにコマンドを送信できますが、getch()の原理は、任意のキーを押してから、そのキー文字に対応するASCIIコードを変数に付与することですので、int型左値変数には暗黙的なタイプ変換に注意してください
(eg.実行番号1対応メニューバーオプション、int input;input=getch()-48;//“1”->49)
(3)使用可能なsystem(「cls」)文は画面を空にし、画面に現在のレベルのメニューのみを表示させ、インタフェースをより簡潔にする.
 
自分の問題:
1.次の曲の前の曲の変換機能の作成を開始するときに、一つのメニューが一つの関数に対応すると思い、PlayInterface.c内にはLastSong()とNextSong()の2つの関数が書き換えられている.プログラミングの過程で、現在の曲の再生プロセスを停止し、次の拡張子mp 3というファイルを開き、MCIライブラリに再生命令を送信する2つのより基本的なステップに分解できることを認識しました.ただし、前の機能が書かれている関数を呼び出すのではなく、前の関数のコードセグメントを直接コピーして変更を追加します.その結果、次の曲と前の曲の切り替えは無理に実現できますが、2つの問題があります.
(1)自分のプログラミングの考え方は正しいが、「3」または「4」キーを押した後、次の曲や前の曲を直接再生することはできず、「1」(再生/一時停止切り替えキー)を1回押さなければ次の曲が鳴らない.
(2)そこで間違いを犯して、他に何か異常があるか見て、放送状態を一時停止にし、31313131(プレイリストは3曲しかない)というリストを順番に押してループし、1曲目の歌が前に一時停止した場所で放送され続け、その後、すべての歌がこのような状況になっていることを発見し、すべての歌が次の曲に切り替わってから終了していないことを示した.実際のニーズに合わない.
コードを修正しstop(),play(),pause()関数を再利用して上記の問題を解決した.
これは,コードの再利用性を合理的に利用して同じタスクを抽出することを示す.多層ネスト関数を呼び出して効率に影響を与える心配はありません.
実際には、コードの冗長性を排除し、アーキテクチャを改善し、プログラムの実行効率を高める方法です.
 
2.クリーンコマンドラインclsを使用しても、現在再生されている曲が画面上で瞬時に消えるなどのヒント情報があり、C++PRIMERでwhile遅延サイクルを作成する方法を調べました.システムクロックパルスを利用して定義された定数CLOCKS_PER_SEC(1秒あたりのシステム時間単位数)は、実際の秒数に変換されます.
コードは次のとおりです.
//システムクロックを利用して、フォルダに含まれるmp 3曲ファイル名を1つずつ表示
       clock_tdelay=2.0*CLOCKS_PER_SEC;//システムクロックパルス数に変換
       clock_tstart=clock();
       while(clock()-start
              ;
    printf("%s",FindFileData.cFileName);
      //FindFileData.cFileNameはファイル名です
 
このプレーヤーには2つの向上点があり、まず削除リストを動的に追加することはできないが、配列は削除の効率が低いため、この機能を実現するには新しいデータ構造チェーンテーブルが必要である.また、1曲が放送された後に次の曲を自動的に再生することはできませんが、このプレーヤーはgetch()関数を使ってメニュー選択を行い、プログラムは常に入力を待っている状態で、プロセスが占有され、1曲が放送されたかどうかを監視することができません.そのため、より複雑なマルチスレッドプログラミングを使用する必要があります.これは後で解決します.
要するに、このようなプロジェクトをして思考、デバッグ、自主的に問題を発見して解決する能力と学習の主体性から全方位的に私のソフトウェアコードの実践能力を鍛えました.
次のコード
main.c
#include"Mp3Player.h"
#include
int main()
{
	
	find(".\\music");
	MainMenu();
	return 0;
}

Mp3Player.h
//                
extern void MainMenu();

Mp3Player.c
#include
#include
#include
#include
#include"PlayInterface.h"
#include"PlayList.h"
#include"ShowDelay.h"
/*getch():
     :conio.h
    :          ,        
( getch();         ,          ;
 ch=getch();           ,         ASCII   ch,        。)
    :intgetch(void)
   :     

  :getchar()                  ASCII ,     -1。
*/
//#define STATUS_STOP 0
//#define STATUS_PLAY 1
//#define STATUS_PAUSE 2
enum STATUS{
	STATUS_STOP=0,
	STATUS_PLAY,
	STATUS_PAUSE
};//              

//    
static void PlayControlMenu();//static           
static void SoundControlMenu();
void MainMenu();

void PlayControlMenu()
{
	char *name="Hero.mp3";
	//char name1[]="Hero.mp3";
	
	//char *names[10]={"Hero.mp3","Baby.mp3"};   10       
	
	int input2 = -1;
	static enum STATUS status = STATUS_STOP;//     status      ,0,1,2      ,  ,  (        )
	
	while (input2 != 0)
	{
		printf(" %d  -- %s
", getCurNo() + 1, getName()); showdelay(0.5); system("cls"); printf("1. /
"); printf("2.
"); printf("3.
"); printf("4.
"); printf("0.
"); input2=_getch()-48;//“1”->49 switch(input2) { case 1:printf("1. /
"); // if(status!=STATUS_PLAY) { printf("
"); showdelay(0.3); play(getName()); status=STATUS_PLAY; } else { printf("
"); showdelay(0.3); pause(getName()); status=STATUS_PAUSE; } break; case 2: printf("2.
"); stop(getName()); // status = STATUS_STOP; showdelay(0.3); break; case 3:printf("3.
"); stop(getName()); curNoDown(); play(getName()); break; case 4:printf("4.
"); stop(getName()); curNoUp(); play(getName()); break; case 0:printf("0.
"); break; default: printf("
"); break; } } } void SoundControlMenu() { int input3 = -1; while (input3 != 0) { system("cls"); printf(" %d -- %s
", getCurNo() + 1, getName()); printf("1.
"); printf("2.
"); printf("0.
"); input3=_getch()-48; switch(input3) { case 1:printf("1.
"); VolumnUp(getName()); break; case 2:printf("2.
"); VolumnDown(getName()); break; case 0:printf("0.
"); break; default: printf("
"); break; } } } void MainMenu() { // -1, -1 , 1, //eg.1 00000001, 11111110, 11111111, -1 11111111. // input int ,4 , 32 1, 0XFFFFFFFF。 int input = -1; //int input=0; while(input != 0) { system("cls"); printf("1.
"); printf("2.
"); printf("0.
"); //scanf("%d",&input); input=_getch(); input-=48; switch(input) { case 1:printf("1.
"); // PlayControlMenu(); break; case 2:printf("2.
"); // SoundControlMenu(); break; //default: case 0:printf("0.
"); break; default: printf("
"); break; } } } PlayInterface.h extern void play(const char *name); // extern void pause(const char *name); // extern void stop(const char *name); // extern void VolumnUp(const char *name); // extern void VolumnDown(const char *name); // PlayerInterface.c #include #include #include // getch() #include #include #include // mci #pragma comment(lib, "winmm.lib") // / MCI ,mciSendString winmm.lib #define MAX_SONG 3 //extern int serial_num; //extern enum STATUS status; // void play(const char *name) // { char cmd[MAX_PATH] = {0}; char pathname[MAX_PATH] = {0}; // //intprintf(const char*); //intsprintf(char* ,const char*,...); wsprintf(pathname, ".\\music\\%s", name); // GetShortPathName , , 。 // : , : , : 。 // ? ? ? GetShortPathName(pathname, pathname, MAX_PATH);// // MCI ,cmd , printf() wsprintf(cmd, "open %s", pathname); // 。 // 、 , 、 MCI , 、 , 、 ,NULL mciSendString(cmd, "", 0, NULL); wsprintf(cmd, "play %s", pathname); mciSendString(cmd, "", 0, NULL); } // , curno void pause(const char *name) // { char cmd[MAX_PATH] = {0}; char pathname[MAX_PATH] = {0}; // wsprintf(pathname, ".\\music\\%s", name); // GetShortPathName , , 。 // : , : , : 。 GetShortPathName(pathname, pathname, MAX_PATH); wsprintf(cmd, "pause %s", pathname); mciSendString(cmd,"",0,NULL); } // , curno void stop(const char *name) { char cmd[MAX_PATH] = {0}; char pathname[MAX_PATH] = {0}; // wsprintf(pathname, ".\\music\\%s", name); // GetShortPathName , , 。 // : , : , : 。 GetShortPathName(pathname, pathname, MAX_PATH); wsprintf(cmd, "stop %s", pathname); mciSendString(cmd,"",0,NULL); wsprintf(cmd, "close %s", pathname); mciSendString(cmd,"",0,NULL); } /* void nextSong(char *name) { char cmd[MAX_PATH] = {0}; char pathname[MAX_PATH] = {0}; // wsprintf(pathname, ".\\music\\%s", name); GetShortPathName(pathname, pathname, MAX_PATH); wsprintf(cmd, "stop %s", pathname); mciSendString(cmd,"",0,NULL); // wsprintf(pathname, ".\\music\\%s", name+1); GetShortPathName(pathname, pathname, MAX_PATH); wsprintf(cmd, "open %s", pathname); mciSendString(cmd, "", 0, NULL); wsprintf(cmd, "play %s", pathname); mciSendString(cmd, "", 0, NULL); // +1, , if(serial_num0) serial_num--; else serial_num=MAX_SONG-1; } */ void VolumnUp(const char *name) { char path[MAX_PATH] = {0}; char cmd[MAX_PATH] = {0}; char res[MAX_PATH] = {0}; int volumn = 0; // sprintf(path, ".\\music\\%s", name); // GetShortPathName , , 。 // : , : , : 。 GetShortPathName(path, path, MAX_PATH); sprintf(cmd, "status %s volume", path); mciSendString(cmd, res, MAX_PATH, NULL); // , volumn = atoi(res); volumn += 100; // sprintf(cmd, "setaudio %s volume to %d", path, volumn); // mciSendString(cmd, "", 0, NULL); } void VolumnDown(const char *name) { char path[MAX_PATH] = {0}; char cmd[MAX_PATH] = {0}; char res[MAX_PATH] = {0}; int volumn = 0; // sprintf(path, ".\\music\\%s", name); // GetShortPathName , , 。 // : , : , : 。 GetShortPathName(path, path, MAX_PATH); sprintf(cmd, "status %s volume", path); mciSendString(cmd, res, MAX_PATH, NULL); // res , , atoi() volumn = atoi(res); volumn -= 100; // MCI sprintf(cmd, "setaudio %s volume to %d", path, volumn); mciSendString(cmd, "", 0, NULL); } PlayList.h extern void find(char * lpPath); // mp3 extern char *getName(); // extern int getCurNo(); // extern void curNoDown(); // , +1 extern void curNoUp(); // , -1 PlayList.c #include #include"ShowDelay.h" #define MAX_SONG 10 static char names[MAX_SONG][100]={"Beautiful Times.mp3","Fireflies.mp3","Hero.mp3",};// 10 static int serial_num = 0;// , static int total = 0; // char *getName() { return names[serial_num]; } int getCurNo() { return serial_num; } void curNoDown() // { serial_num++; if(serial_num==3) serial_num=0; } void curNoUp() // { serial_num--; if(serial_num==-1) serial_num=2; } // , windows API void find(char * lpPath) { char szFind[MAX_PATH],szFile[MAX_PATH]; WIN32_FIND_DATA FindFileData; HANDLE hFind; strcpy(szFind,lpPath); strcat(szFind,"\\*.mp3"); hFind = FindFirstFile(szFind,&FindFileData); if(INVALID_HANDLE_VALUE == hFind) return; while(TRUE) { if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if(FindFileData.cFileName[0]!='.') { strcpy(szFile,lpPath); strcat(szFile,"\\"); strcat(szFile,FindFileData.cFileName); find(szFile); } } else { showdelay(1.5); printf("%s
",FindFileData.cFileName); // FindFileData.cFileName // &names[1][0]/names[1]/(name+1) strcpy(names[total],FindFileData.cFileName); total++; } if(!FindNextFile(hFind,&FindFileData)) break; } } ShowDelay.h extern void showdelay(float sec); ShowDelay.c #include void showdelay(float sec) { clock_t delay=sec*CLOCKS_PER_SEC;// clock_t start=clock(); while(clock()-start