a
Dependencies: SRC_STM32F7 F746-GUI SD_PlayerSkeleton F746-SAI-IO
main.cpp
- Committer:
- fundokukiri
- Date:
- 2019-06-10
- Revision:
- 0:a26ecfb99239
File content as of revision 0:a26ecfb99239:
//-------------------------------------------------------------------- #include "VolumeCtrl.hpp" #include "FileSelectorWav.hpp" #include "SD_PlayerSkeleton.hpp" #include "SD_WavReader.hpp" using namespace Mikami; int main() { VolumeCtrl myPlayer("Music Player"); myPlayer.Execute(); } //------------------------------------------------- //Chương trình con điều chỉnh biên độ âm thanh namespace Mikami { // Thực thi xử lý tín hiệu cho một khối void VolumeCtrl::SignalProcessing() { // Đọc giá trị dữ liệu âm thanh nổi của một khối từ SD và biến nó thành đơn âm sdReader_.ReadAndToMono(sn_); while (!mySai_.IsXferred()) {} // Chờ cho đến khi truyền dữ liệu hoàn tất for (int n=0; n<BUFF_SIZE_; n++) { int16_t data = volume_*sn_[n]; //Thay đổi âm lượng đầu ra mySai_.Output(data, data); } //-------------------------------------------------------------- } // Điều chỉnh âm lượng void VolumeCtrl::Modefy() { if (myBar_.Slide()) volume_ = myBar_.GetValue(); } // Hiển thị khi phát một bài hát void VolumeCtrl::Display() { Label musicTitle(207, 80, GetFileNameNoExt(), Label::CENTER, Font16); ctrl_.Draw(); myBar_.Redraw(); } } //-------------------------------------------------------------- namespace Mikami { FileSelector::FileSelector(uint8_t x0, uint8_t y0, int maxFiles, int maxNameLength, SD_WavReader &reader) : X_(x0), Y_(y0), MAX_FILES_(maxFiles), MAX_NAME_LENGTH_(maxNameLength), fileNames_(maxFiles), fileNameLabels_(MAX_LIST_PAGE_), next_(50, 238, 64, 36, 2, (string[]){"<", ">"}, 10, 0, 2, -1, Font24), pageLabel_(210, 250, Label::LEFT, Font16), lcd_(GuiBase::GetLcd()), sdReader_(reader), page_(1), nOld_(-1), kOld_(-1) { Array<string> nonString(MAX_LIST_PAGE_, ""); rect_ = new ButtonGroup(X_, Y_, W_H_, W_H_, MAX_LIST_PAGE_, nonString, 0, V_L_-W_H_, 1, -1, Font12, 0, GuiBase::ENUM_BACK, BASE_COLOR_, TOUCHED_COLOR_); rect_->EraseAll(); next_.EraseAll(); // Tạo Label for (int n=0; n<MAX_LIST_PAGE_; n++) fileNameLabels_[n] = new Label(X_+30, Y_+5+V_L_*n, "", Label::LEFT, Font16, BASE_COLOR_); } FileSelector::~FileSelector() { delete rect_; for (int n=0; n<MAX_LIST_PAGE_; n++) delete fileNameLabels_[n]; } // Lập danh sách các tập tin. Trả về false nếu tệp WAV không tồn tại bool FileSelector::CreateTable() { DIR* dp = opendir("/sd"); fileCount_ = 0; if (dp != NULL) { dirent* entry; for (int n=0; n<256; n++) { entry = readdir(dp); if (entry == NULL) break; string strName = entry->d_name; if ( (strName.find(".wav") != string::npos) || (strName.find(".WAV") != string::npos) ) { sdReader_.Open(strName); // mở tập tin // Loại trừ các tệp không phải PCM, âm thanh nổi 16 bit, tần số lấy mẫu 44,1 kHz if (sdReader_.IsWavFile()) fileNames_[fileCount_++] = strName; sdReader_.Close(); } if (fileCount_ >= MAX_FILES_) break; } closedir(dp); } else return false; // nếu thẻ SD không được cài đặt if (fileCount_ == 0) return false; //Nếu tệp WAV tương ứng không tồn tại div_t m = div(fileCount_, MAX_LIST_PAGE_); maxPage_ = (m.rem == 0) ? m.quot : m.quot+1; return true; //Khi tệp WAV tương ứng tồn tại } // chọn tập tin bool FileSelector::Select(string &fileName) { int m; if (next_.GetTouchedNumber(m)) { if (m==0) page_--; else page_++; DisplayFileList(false); nOld_ = -1; wait_ms(300); } int n; if (rect_->GetTouchedNumber(n)) { int k = (page_ - 1)*MAX_LIST_PAGE_ + n; fileNameLabels_[n]->Draw(GetFileNameNoExt(k), TOUCHED_COLOR_); fileName = fileNames_[k]; // Trả về màu của tên tệp đã chọn trước đó trên cùng một trang if (nOld_ != -1) fileNameLabels_[nOld_]->Draw(GetFileNameNoExt(kOld_), BASE_COLOR_); if (page_ == maxPage_) // xóa hình chữ nhật phụ trên trang cuối for (int j=fileCount_ % MAX_LIST_PAGE_ + 1; j < MAX_LIST_PAGE_; j++) rect_->Erase(j); nOld_ = n; kOld_ = k; wait_ms(300); return true; } else return false; } // Hiển thị danh sách các tập tin void FileSelector::DisplayFileList(bool sortEnable) { if (sortEnable) std::sort((string *)fileNames_, (string *)fileNames_+fileCount_); Erase(X_, Y_, MAX_NAME_LENGTH_*((sFONT *)(&Font16))->Width, 272-Y_); div_t m = div(fileCount_, MAX_LIST_PAGE_); int count = (m.quot >= page_) ? MAX_LIST_PAGE_ : m.rem; for (int n=0; n<count; n++) rect_->Draw(n); for (int n=0; n<count; n++) fileNameLabels_[n]->Draw(GetFileNameNoExt(n+(page_-1)*MAX_LIST_PAGE_)); // Hiển thị trang trước, nút chọn trang tiếp theo, v.v. next_.InactivateAll(); if (page_ > 1) next_.Activate(0); // "<" hợp lệ if (page_ < maxPage_) next_.Activate(1); // ">" hợp lệ char page[6]; sprintf(page, "%d/%d", page_, maxPage_); pageLabel_.Draw(page); } // xóa danh sách các tập tin void FileSelector::Erase(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color) { lcd_.SetTextColor(color); lcd_.FillRect(x, y, width, height); } // Lấy tên tệp với phần mở rộng bị xóa string FileSelector::GetFileNameNoExt(int n) { string name = fileNames_[n]; int k = name.rfind("."); if (k != string::npos) return name.erase(k); else return name; } } //-------------------------------------------------------------- //chương trình hiển thị giao diện & điều khiển namespace Mikami { SD_PlayerSkeleton::SD_PlayerSkeleton(string str, bool resetButton) : BUFF_SIZE_(2048), sn_(BUFF_SIZE_), mySai_(SaiIO::OUTPUT, BUFF_SIZE_, AUDIO_FREQUENCY_44K), sdReader_(BUFF_SIZE_), fileName_(""), title_(214, 4, str, Label::CENTER, Font16), selector_(0, 22, 256, 37, sdReader_), menu_(BG_LEFT_, 2, BG_WIDTH_, BG_HEIGHT_, 5, (string[]){"SELECT", "PLAY", "PAUSE", "RESUME", "STOP"}, 0, 2, 1) { menu_.InactivateAll(); menu_.Activate(0); if (!selector_.CreateTable()) BlinkLabel errLabel(240, 100, "SD CARD ERROR", Label::CENTER); if (resetButton) reset_ = new ResetButton(); else reset_ = NULL; } // thực thi xử lý trình phát SD void SD_PlayerSkeleton::Execute() { bool playOk = false; int32_t loopCount; while (true) { if (playOk) // Trong trường hợp PLAY sau PAUSE loopCount = SD_Open(); else // Nếu không PLAY sau PAUSE { if (0 == WaitTouched()) SelectFile(); loopCount = SD_Open(); while (1 != WaitTouched()) {} // Đợi cho đến khi PLAY được chạm } Display(); // Xử lý hiển thị dành riêng cho ứng dụng (chức năng ảo) if (reset_ != NULL) reset_->Draw(); menu_.Inactivate(0); // SELECT bị vô hiệu hóa menu_.Activate(2); // PAUSE bị vô hiệu hóa menu_.Activate(4); // STOP bị vô hiệu hóa playOk = false; bool stopOk = false; Clear(); // Quá trình xóa ứng dụng cụ thể (chức năng ảo) mySai_.PlayOut(); // Play // Lặp lại cho đến khi hết dữ liệu tệp for (int k=0; k<loopCount; k++) { int touch42 = -1; menu_.GetTouchedNumber(touch42); if (touch42 == 4) break; // STOP if (touch42 == 2) // PAUSE Xử lý khi chạm vào nút { menu_.Inactivate(2); // PAUSE Nút không hợp lệ menu_.Activate(3); // RESUME Đã bật nút mySai_.PauseOut(); // PLAY Đợi cho đến khi 'RESUME' hoặc 'STOP' được chạm vào switch (WaitTouched()) { case 1: playOk = true; // PLAY từ đầu break; case 3: mySai_.ResumeOut(); // Tiếp tục PLAY từ điểm PAUSE menu_.Activate(2); menu_.Inactivate(3); menu_.TouchedColor(1); break; case 4: stopOk = true; // STOP break; } } if (playOk || stopOk) break; DoIfHandled(); // Xử lý tín hiệu cho một khối dành riêng cho ứng dụng (hàm ảo thuần túy) SignalProcessing(); } mySai_.StopOut(); if (!playOk) menu_.Activate(0); // SELECT hợp lệ menu_.Draw(1); // Khởi tạo màu của nút PLAY for (int n=2; n<5; n++) // Các nút khác bị vô hiệu hóa menu_.Inactivate(n); sdReader_.Close(); // Đóng tệp SD } } // Lấy tên tệp đã chọn mà không cần phần mở rộng string SD_PlayerSkeleton::GetFileNameNoExt() { string fName = fileName_; int k = fName.rfind("."); if (k != string::npos) return fName.erase(k); else return fName; } // Mở tệp thẻ SD int32_t SD_PlayerSkeleton::SD_Open() { if (fileName_.empty()) SelectFile(); sdReader_.Open(fileName_); sdReader_.IsWavFile(); return sdReader_.GetSize()/BUFF_SIZE_; } // Lựa chọn tập tin void SD_PlayerSkeleton::SelectFile() { selector_.DisplayFileList(); title_.Draw("Select file"); menu_.Inactivate(0); // SELECT vô hiệu hóa menu_.Inactivate(1); // PLAY vô hiệu hóa do if (selector_.Select(fileName_)) menu_.Activate(1); // PLAY đã bật while (!menu_.Touched(1)); // PLAY Lặp lại cho đến khi nút được chạm selector_.Erase(0, 0, BG_LEFT_-4, 272); title_.Draw(); } // Xử lý khi bảng điều khiển được vận hành void SD_PlayerSkeleton::DoIfHandled() { if (reset_ != NULL) reset_->DoIfTouched(); Modefy(); // Ứng dụng thay đổi tham số cụ thể (chức năng ảo) } //Đợi trong khi thực hiện Do IfHandled () cho đến khi bất kỳ nút nào trên menu được chạm vào int SD_PlayerSkeleton::WaitTouched() { int touchNum; while (!menu_.GetTouchedNumber(touchNum)) DoIfHandled(); return touchNum; } } //------------------------------------------------- //chương trình con đọc file WAV-PCM-16bit-44.1KHz namespace Mikami { SD_WavReader::SD_WavReader(int32_t bufferSize) : STR_("sd"), ok_(false) { sd_ = new SDFileSystem(STR_.c_str()); sd_->mount(); buffer.SetSize(bufferSize*2); } SD_WavReader::~SD_WavReader() { sd_->unmount(); delete sd_; } void SD_WavReader::Open(const string fileName) { string name = (string)"/" + STR_ + "/" + fileName; fp_ = fopen(name.c_str(), "rb"); if (fp_ == NULL) ErrorMsg("Loi The SD!!!"); } // Đọc một phần của tiêu đề tệp "RIFFxxxxWAVEfmt" // Giá trị trả về: true nếu âm thanh nổi 16 bit, tần số lấy mẫu là 44,1 kHz bool SD_WavReader::IsWavFile() { char data[17]; fread(data, 1, 16, fp_); // Đọc 16 byte string strRead = ""; for (int n=0; n<4; n++) strRead += data[n]; // Không kiểm tra 4 ký tự giữa for (int n=8; n<16; n++) strRead += data[n]; // Kiểm tra xem "RIFF", "WAVE", "fmt" có tồn tại không if (strRead != "RIFFWAVEfmt ") return false; // có được kích thước của fmt chunck uint32_t fmtChunkSize; fread(&fmtChunkSize, sizeof(uint32_t), 1, fp_); // Xác nhận rằng đó là PCM, Stereo, 44.1 kHz, 16 bit WaveFormatEx fmtData; fread(&fmtData, fmtChunkSize, 1, fp_); if ((fmtData.wFormatTag != 1) || (fmtData.nChannels != 2) || (fmtData.nSamplesPerSec != AUDIO_FREQUENCY_44K) || (fmtData.wBitsPerSample != 16) ) return false; // Tìm dữ liệu char dataId[5]; dataId[4] = 0; fread(dataId, 1, 4, fp_); if ("data" != (string)dataId) for (int n=0; n<100; n++) { char oneByte; fread(&oneByte, 1, 1, fp_); for (int k=0; k<3; k++) dataId[k] = dataId[k+1]; dataId[3] = oneByte; if ("data" == (string)dataId) break; if (n == 99) return false; } // Nhận kích thước dữ liệu (byte) int32_t sizeByte; fread(&sizeByte, sizeof(int32_t), 1, fp_); size_ = sizeByte/4; ok_ = true; return true; } // Nhận dữ liệu âm thanh nổi từ tập tin void SD_WavReader::ReadStereo(Array<int16_t>& dataL, Array<int16_t>& dataR) { if (!ok_) ErrorMsg("Get data FAILED"); uint32_t size = dataL.Length(); fread(buffer, sizeof(int16_t), size*2, fp_); for (int n=0; n<size; n++) { dataL[n] = buffer[2*n]; dataR[n] = buffer[2*n+1]; } } // Chuyển đổi dữ liệu từ tập tin sang đơn âm void SD_WavReader::ReadAndToMono(Array<int16_t>& data) { if (!ok_) ErrorMsg("Get data FAILED"); uint32_t size = data.Length(); fread(buffer, sizeof(int16_t), size*2, fp_); for (int n=0; n<size; n++) data[n] = (buffer[2*n] + buffer[2*n+1])/2; } // Thu thập kích thước dữ liệu (số điểm lấy mẫu) int32_t SD_WavReader::GetSize() { if (!ok_) ErrorMsg("Get data size FAILED"); return size_; } }