├── .gitattributes ├── .gitignore ├── README.md ├── Screenshots ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png └── 7.png └── Sources ├── FlacPic.h ├── ICO ├── AllRepeat.png ├── CSkin.png ├── Close.png ├── Mini.png ├── Mute.png ├── Next.png ├── Open.png ├── Order.png ├── Pause.png ├── Play.png ├── PlayList.png ├── Pre.png ├── Repeat.png ├── ShadowPlayer.ico ├── Shuffle.png ├── Single.png ├── Stop.png ├── Vol.png └── backup │ ├── Mute.png │ ├── Open.png │ ├── Pause.png │ ├── Play.png │ ├── Stop.png │ └── Vol.png ├── ID3v2Pic.h ├── MyGlobalShortCut ├── MyGlobalShortCut.cpp ├── MyGlobalShortCut.h ├── MyWinEventFilter.cpp └── MyWinEventFilter.h ├── ShadowPlayer.pro ├── ShadowPlayer.rc ├── bass.h ├── bass.lib ├── bass_aac.h ├── bass_aac.lib ├── bass_alac.h ├── bass_alac.lib ├── bass_ape.h ├── bass_ape.lib ├── bass_fx.h ├── bass_fx.lib ├── bass_tta.h ├── bass_tta.lib ├── bassflac.h ├── bassflac.lib ├── basswma.h ├── basswma.lib ├── basswv.h ├── basswv.lib ├── fftdisplay.cpp ├── fftdisplay.h ├── image ├── OSD.png ├── ShadowPlayer.png └── Skin1.jpg ├── lrcbar.cpp ├── lrcbar.h ├── lrcbar.ui ├── lyrics.cpp ├── lyrics.h ├── main.cpp ├── osd.cpp ├── osd.h ├── osd.ui ├── player.cpp ├── player.h ├── playlist.cpp ├── playlist.h ├── playlist.ui ├── res.qrc ├── shadowlabel.cpp ├── shadowlabel.h ├── shadowplayer.cpp ├── shadowplayer.h ├── shadowplayer.ui ├── spslider.cpp ├── spslider.h ├── tags.h └── tags.lib /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ShadowPlayer 2 | 一个基于Qt5.3.1和BASS库的简易播放器。 3 | 4 | ## Windows二进制程序下载 5 | 请访问 http://pan.baidu.com/s/1ntOeCf3 6 | 7 | ## 分支版本 8 | * [BLumia修改版](https://github.com/Blumia/ShadowPlayer-BLumia) 9 | 10 | ## 功能特点 11 | * 无损音频播放 12 | * 可作为Windows文件关联来使用     13 | (防多开 + 进程间通信实现在一个窗口打开多个文件) 14 | * 变速播放 15 | * 倒放 16 | * 播放列表,支持拖放添加,支持批量操作 17 | * 均衡器和混响 18 | * 滚动歌词 19 | * 桌面歌词,可设置字体和阴影样式 20 | * 可更换播放器背景图片 21 | * 全局热键控制播放 22 | * 带有 __物理效果__ 的频谱分析 23 | * ID3、Flac专辑封面显示 24 | * 无序播放 25 | * OSD显示当前播放曲目 26 | * 任务栏播放进度及状态显示 27 | * 任务栏控制按钮 28 | * 拖放操作,拖入文件自动加载(自动识别歌词、背景图片、音频文件) 29 | * 桌面歌词过长时,自动滚动歌词 30 | 31 | ## 代码里能够拿出去用的东西,均为作者实现(或绘制) 32 | * ID3/FLAC专辑封面提取 33 | * 带物理效果的频谱显示控件(频谱需要自己计算) 34 | * 横向点击定位进度条(稍作修改可以支持纵向) 35 | * 带阴影的QLabel控件(支持三种阴影模式,无阴影、描边和斜45投影) 36 | * 控件图标 37 | 38 | 本播放器的进度条可以直接点击定位。 39 | 40 | ## 截图 41 | ![主界面](https://github.com/ShadowPower/ShadowPlayer/raw/master/Screenshots/1.png) 42 | 43 | ![播放状态](https://github.com/ShadowPower/ShadowPlayer/raw/master/Screenshots/2.png) 44 | 45 | ![右键菜单](https://github.com/ShadowPower/ShadowPlayer/raw/master/Screenshots/3.png) 46 | 47 | ![播放列表](https://github.com/ShadowPower/ShadowPlayer/raw/master/Screenshots/4.png) 48 | 49 | ![更换背景图片以及桌面歌词](https://github.com/ShadowPower/ShadowPlayer/raw/master/Screenshots/5.png) 50 | 51 | ![透明背景](https://github.com/ShadowPower/ShadowPlayer/raw/master/Screenshots/6.png) 52 | 53 | ![桌面歌词字体设置](https://github.com/ShadowPower/ShadowPlayer/raw/master/Screenshots/7.png) 54 | -------------------------------------------------------------------------------- /Screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Screenshots/1.png -------------------------------------------------------------------------------- /Screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Screenshots/2.png -------------------------------------------------------------------------------- /Screenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Screenshots/3.png -------------------------------------------------------------------------------- /Screenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Screenshots/4.png -------------------------------------------------------------------------------- /Screenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Screenshots/5.png -------------------------------------------------------------------------------- /Screenshots/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Screenshots/6.png -------------------------------------------------------------------------------- /Screenshots/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Screenshots/7.png -------------------------------------------------------------------------------- /Sources/FlacPic.h: -------------------------------------------------------------------------------- 1 | /* 2 | FLAC标签图片提取库 Ver 1.0 3 | 从FLAC文件中稳定、快捷、高效、便捷地提取出图片数据 4 | 支持BMP、JPEG、PNG、GIF图片格式 5 | 可将图片数据提取到文件或内存中,并能安全地释放内存 6 | 使用方式与ID3v2版本相同 7 | ShadowPower 于2014/8/1 夜间 8 | */ 9 | 10 | #ifndef _ShadowPower_FLACPIC___ 11 | #define _ShadowPower_FLACPIC___ 12 | #define _CRT_SECURE_NO_WARNINGS 13 | #ifndef NULL 14 | #define NULL 0 15 | #endif 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | typedef unsigned char byte; 22 | using namespace std; 23 | 24 | namespace spFLAC { 25 | //Flac元数据块头部结构体定义 26 | struct FlacMetadataBlockHeader 27 | { 28 | byte flag; //标志位,高1位:是否为最后一个数据块,低7位:数据块类型 29 | byte length[3]; //数据块长度,不含数据块头部 30 | }; 31 | 32 | byte *pPicData = 0; //指向图片数据的指针 33 | int picLength = 0; //存放图片数据长度 34 | char picFormat[4] = {}; //存放图片数据的格式(扩展名) 35 | 36 | //检测图片格式,参数1:数据,返回值:是否成功(不是图片则失败) 37 | bool verificationPictureFormat(char *data) 38 | { 39 | //支持格式:JPEG/PNG/BMP/GIF 40 | byte jpeg[2] = { 0xff, 0xd8 }; 41 | byte png[8] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a }; 42 | byte gif[6] = { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }; 43 | byte gif2[6] = { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }; 44 | byte bmp[2] = { 0x42, 0x4d }; 45 | memset(&picFormat, 0, 4); 46 | if (memcmp(data, &jpeg, 2) == 0) 47 | { 48 | strcpy(picFormat, "jpg"); 49 | } 50 | else if (memcmp(data, &png, 8) == 0) 51 | { 52 | strcpy(picFormat, "png"); 53 | } 54 | else if (memcmp(data, &gif, 6) == 0 || memcmp(data, &gif2, 6) == 0) 55 | { 56 | strcpy(picFormat, "gif"); 57 | } 58 | else if (memcmp(data, &bmp, 2) == 0) 59 | { 60 | strcpy(picFormat, "bmp"); 61 | } 62 | else 63 | { 64 | return false; 65 | } 66 | 67 | return true; 68 | } 69 | 70 | //安全释放内存 71 | void freePictureData() 72 | { 73 | if (pPicData) 74 | { 75 | delete pPicData; 76 | } 77 | pPicData = 0; 78 | picLength = 0; 79 | memset(&picFormat, 0, 4); 80 | } 81 | 82 | //将图片提取到内存,参数1:文件路径,成功返回true 83 | bool loadPictureData(const char *inFilePath) 84 | { 85 | freePictureData(); 86 | FILE *fp = NULL; 87 | fp = fopen(inFilePath, "rb"); 88 | if (!fp) //如果打开失败 89 | { 90 | fp = NULL; 91 | return false; 92 | } 93 | fseek(fp, 0, SEEK_SET); //设文件流指针到文件头部 94 | byte magic[4] = {}; //存放校验数据 95 | memset(&magic, 0, 4); 96 | fread(&magic, 4, 1, fp); //读入校验数据 97 | byte fLaC[4] = { 0x66, 0x4c, 0x61, 0x43 }; 98 | if (memcmp(&magic, &fLaC, 4) == 0) 99 | { 100 | //数据校验正确,文件类型为Flac 101 | FlacMetadataBlockHeader fmbh; //创建Flac元数据块头部结构体 102 | memset(&fmbh, 0, 4); //清空内存 103 | fread(&fmbh, 4, 1, fp); //读入头部数据 104 | //计算数据块长度,不含头部 105 | int blockLength = fmbh.length[0] * 0x10000 + fmbh.length[1] * 0x100 + fmbh.length[2]; 106 | int loopCount = 0; //循环计数,防死 107 | while ((fmbh.flag & 0x7f) != 6) 108 | { 109 | //如果数据类型不是图片,此处循环执行 110 | loopCount++; 111 | if (loopCount > 40) 112 | { 113 | //循环40次没有遇到末尾就直接停止 114 | fclose(fp); 115 | fp = NULL; 116 | return false; //可能文件不正常 117 | } 118 | fseek(fp, blockLength, SEEK_CUR); //跳过数据块 119 | if ((fmbh.flag & 0x80) == 0x80) 120 | { 121 | //已经是最后一个数据块了,仍然不是图片 122 | fclose(fp); 123 | fp = NULL; 124 | return false; //没有找到图片数据 125 | } 126 | //取得下一数据块头部 127 | memset(&fmbh, 0, 4); //清空内存 128 | fread(&fmbh, 4, 1, fp); //读入头部数据 129 | blockLength = fmbh.length[0] * 0x10000 + fmbh.length[1] * 0x100 + fmbh.length[2];//计算数据块长度 130 | } 131 | //此时已到图片数据块 132 | 133 | int nonPicDataLength = 0; //非图片数据长度 134 | fseek(fp, 4, SEEK_CUR); //信仰之跃 135 | nonPicDataLength += 4; 136 | char nextJumpLength[4]; //下次要跳的长度 137 | fread(&nextJumpLength, 4, 1, fp); //读取安全跳跃距离 138 | nonPicDataLength += 4; 139 | int jumpLength = nextJumpLength[0] * 0x1000000 + nextJumpLength[1] * 0x10000 + nextJumpLength[2] * 0x100 + nextJumpLength[3];//计算数据块长度 140 | fseek(fp, jumpLength, SEEK_CUR); //Let's Jump!! 141 | nonPicDataLength += jumpLength; 142 | fread(&nextJumpLength, 4, 1, fp); 143 | nonPicDataLength += 4; 144 | jumpLength = nextJumpLength[0] * 0x1000000 + nextJumpLength[1] * 0x10000 + nextJumpLength[2] * 0x100 + nextJumpLength[3]; 145 | fseek(fp, jumpLength, SEEK_CUR); //Let's Jump too!! 146 | nonPicDataLength += jumpLength; 147 | fseek(fp, 20, SEEK_CUR); //信仰之跃 148 | nonPicDataLength += 20; 149 | 150 | //非主流情况检测+获得文件格式 151 | char tempData[20] = {}; 152 | memset(tempData, 0, 20); 153 | fread(&tempData, 8, 1, fp); 154 | fseek(fp, -8, SEEK_CUR); //回到原位 155 | //判断40次,一位一位跳到文件头 156 | bool ok = false; //是否正确识别出文件头 157 | for (int i = 0; i < 40; i++) 158 | { 159 | //校验文件头 160 | if (verificationPictureFormat(tempData)) 161 | { 162 | ok = true; 163 | break; 164 | } 165 | else 166 | { 167 | //如果校验失败尝试继续向后校验 168 | fseek(fp, 1, SEEK_CUR); 169 | nonPicDataLength++; 170 | fread(&tempData, 8, 1, fp); 171 | fseek(fp, -8, SEEK_CUR); 172 | } 173 | } 174 | 175 | if (!ok) 176 | { 177 | fclose(fp); 178 | fp = NULL; 179 | freePictureData(); 180 | return false; //无法识别的数据 181 | } 182 | 183 | //-----抵达图片数据区----- 184 | picLength = blockLength - nonPicDataLength; //计算图片数据长度 185 | pPicData = new byte[picLength]; //动态分配图片数据内存空间 186 | memset(pPicData, 0, picLength); //清空图片数据内存 187 | fread(pPicData, picLength, 1, fp); //得到图片数据 188 | //------------------------ 189 | fclose(fp); //操作已完成,关闭文件。 190 | } 191 | else 192 | { 193 | //校验失败,不是Flac 194 | fclose(fp); 195 | fp = NULL; 196 | freePictureData(); 197 | return false; 198 | } 199 | return true; 200 | } 201 | 202 | //取得图片数据的长度 203 | int getPictureLength() 204 | { 205 | return picLength; 206 | } 207 | 208 | //取得指向图片数据的指针 209 | byte *getPictureDataPtr() 210 | { 211 | return pPicData; 212 | } 213 | 214 | //取得图片数据的扩展名(指针) 215 | char *getPictureFormat() 216 | { 217 | return picFormat; 218 | } 219 | 220 | bool writePictureDataToFile(const char *outFilePath) 221 | { 222 | FILE *fp = NULL; 223 | if (picLength > 0) 224 | { 225 | fp = fopen(outFilePath, "wb"); //打开目标文件 226 | if (fp) //打开成功 227 | { 228 | fwrite(pPicData, picLength, 1, fp); //写入文件 229 | fclose(fp); //关闭 230 | return true; 231 | } 232 | else 233 | { 234 | return false; //文件打开失败 235 | } 236 | } 237 | else 238 | { 239 | return false; //没有图像数据 240 | } 241 | } 242 | 243 | //提取图片文件,参数1:输入文件,参数2:输出文件,返回值:是否成功 244 | bool extractPicture(const char *inFilePath, const char *outFilePath) 245 | { 246 | if (loadPictureData(inFilePath)) //如果取得图片数据成功 247 | { 248 | if (writePictureDataToFile(outFilePath)) 249 | { 250 | return true; //文件写出成功 251 | } 252 | else 253 | { 254 | return false; //文件写出失败 255 | } 256 | } 257 | else 258 | { 259 | return false; //无图片数据 260 | } 261 | freePictureData(); 262 | } 263 | } 264 | #endif 265 | -------------------------------------------------------------------------------- /Sources/ICO/AllRepeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/AllRepeat.png -------------------------------------------------------------------------------- /Sources/ICO/CSkin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/CSkin.png -------------------------------------------------------------------------------- /Sources/ICO/Close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Close.png -------------------------------------------------------------------------------- /Sources/ICO/Mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Mini.png -------------------------------------------------------------------------------- /Sources/ICO/Mute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Mute.png -------------------------------------------------------------------------------- /Sources/ICO/Next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Next.png -------------------------------------------------------------------------------- /Sources/ICO/Open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Open.png -------------------------------------------------------------------------------- /Sources/ICO/Order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Order.png -------------------------------------------------------------------------------- /Sources/ICO/Pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Pause.png -------------------------------------------------------------------------------- /Sources/ICO/Play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Play.png -------------------------------------------------------------------------------- /Sources/ICO/PlayList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/PlayList.png -------------------------------------------------------------------------------- /Sources/ICO/Pre.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Pre.png -------------------------------------------------------------------------------- /Sources/ICO/Repeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Repeat.png -------------------------------------------------------------------------------- /Sources/ICO/ShadowPlayer.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/ShadowPlayer.ico -------------------------------------------------------------------------------- /Sources/ICO/Shuffle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Shuffle.png -------------------------------------------------------------------------------- /Sources/ICO/Single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Single.png -------------------------------------------------------------------------------- /Sources/ICO/Stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Stop.png -------------------------------------------------------------------------------- /Sources/ICO/Vol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/Vol.png -------------------------------------------------------------------------------- /Sources/ICO/backup/Mute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/backup/Mute.png -------------------------------------------------------------------------------- /Sources/ICO/backup/Open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/backup/Open.png -------------------------------------------------------------------------------- /Sources/ICO/backup/Pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/backup/Pause.png -------------------------------------------------------------------------------- /Sources/ICO/backup/Play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/backup/Play.png -------------------------------------------------------------------------------- /Sources/ICO/backup/Stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/backup/Stop.png -------------------------------------------------------------------------------- /Sources/ICO/backup/Vol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/ICO/backup/Vol.png -------------------------------------------------------------------------------- /Sources/ID3v2Pic.h: -------------------------------------------------------------------------------- 1 | /* 2 | ID3v2标签图片提取库 Ver 1.0 3 | 支持ID3v2所有版本 4 | 从ID3v2标签中稳定、快捷、高效、便捷地提取出图片数据 5 | 支持BMP、JPEG、PNG、GIF图片格式 6 | 可将图片数据提取到文件或内存中,并能安全地释放内存 7 | ShadowPower 于2014/8/1 上午 8 | */ 9 | 10 | #ifndef _ShadowPower_ID3V2PIC___ 11 | #define _ShadowPower_ID3V2PIC___ 12 | #define _CRT_SECURE_NO_WARNINGS 13 | #ifndef NULL 14 | #define NULL 0 15 | #endif 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | typedef unsigned char byte; 22 | using namespace std; 23 | 24 | namespace spID3 { 25 | //ID3v2标签头部结构体定义 26 | struct ID3V2Header 27 | { 28 | char identi[3];//ID3头部校验,必须为“ID3”否则认为不存在ID3标签 29 | byte major; //ID3版本号,3是ID3v2.3,4是ID3v2.4,以此类推 30 | byte revsion; //ID3副版本号,此版本为00 31 | byte flags; //标志位 32 | byte size[4]; //标签大小,不含标签头的10个字节 33 | }; 34 | 35 | //ID3v2标签帧头部结构体定义 36 | struct ID3V2FrameHeader 37 | { 38 | char FrameId[4];//标识符,用于描述此标签帧的内容类型 39 | byte size[4]; //标签帧的大小,不含标签头的10个字节 40 | byte flags[2]; //标志位 41 | }; 42 | 43 | struct ID3V22FrameHeader 44 | { 45 | char FrameId[3];//标识符,用于描述此标签帧的内容类型 46 | byte size[3]; //标签帧的大小,不含标签头的6个字节 47 | }; 48 | 49 | byte *pPicData = 0; //指向图片数据的指针 50 | int picLength = 0; //存放图片数据长度 51 | char picFormat[4] = {}; //存放图片数据的格式(扩展名) 52 | 53 | //检测图片格式,参数1:数据,返回值:是否成功(不是图片则失败) 54 | bool verificationPictureFormat(char *data) 55 | { 56 | //支持格式:JPEG/PNG/BMP/GIF 57 | byte jpeg[2] = { 0xff, 0xd8 }; 58 | byte png[8] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a }; 59 | byte gif[6] = { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }; 60 | byte gif2[6] = { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }; 61 | byte bmp[2] = { 0x42, 0x4d }; 62 | memset(&picFormat, 0, 4); 63 | if (memcmp(data, &jpeg, 2) == 0) 64 | { 65 | strcpy(picFormat, "jpg"); 66 | } 67 | else if (memcmp(data, &png, 8) == 0) 68 | { 69 | strcpy(picFormat, "png"); 70 | } 71 | else if (memcmp(data, &gif, 6) == 0 || memcmp(data, &gif2, 6) == 0) 72 | { 73 | strcpy(picFormat, "gif"); 74 | } 75 | else if (memcmp(data, &bmp, 2) == 0) 76 | { 77 | strcpy(picFormat, "bmp"); 78 | } 79 | else 80 | { 81 | return false; 82 | } 83 | 84 | return true; 85 | } 86 | 87 | //安全释放内存 88 | void freePictureData() 89 | { 90 | if (pPicData) 91 | { 92 | delete pPicData; 93 | } 94 | pPicData = 0; 95 | picLength = 0; 96 | memset(&picFormat, 0, 4); 97 | } 98 | 99 | //将图片提取到内存,参数1:文件路径,成功返回true 100 | bool loadPictureData(const char *inFilePath) 101 | { 102 | freePictureData(); 103 | FILE *fp = NULL; //初始化文件指针,置空 104 | fp = fopen(inFilePath, "rb"); //以只读&二进制方式打开文件 105 | if (!fp) //如果打开失败 106 | { 107 | fp = NULL; 108 | return false; 109 | } 110 | fseek(fp, 0, SEEK_SET); //设文件流指针到文件头部(印象中打开之后默认在尾部) 111 | 112 | //读取 113 | ID3V2Header id3v2h; //创建一个ID3v2标签头结构体 114 | memset(&id3v2h, 0, 10); //内存填0,10个字节 115 | fread(&id3v2h, 10, 1, fp); //把文件头部10个字节写入结构体内存 116 | 117 | //文件头识别 118 | if (strncmp(id3v2h.identi, "ID3", 3) != 0) 119 | { 120 | fclose(fp); 121 | fp = NULL; 122 | return false;//没有ID3标签 123 | } 124 | 125 | //能运行到这里应该已经成功打开文件了 126 | 127 | //计算整个标签长度,每个字节仅7位有效 128 | int tagTotalLength = (id3v2h.size[0] & 0x7f) * 0x200000 + (id3v2h.size[1] & 0x7f) * 0x4000 + (id3v2h.size[2] & 0x7f) * 0x80 + (id3v2h.size[3] & 0x7f); 129 | 130 | if (id3v2h.major == 3 || id3v2h.major == 4) //ID3v2.3 或 ID3v2.4 131 | { 132 | ID3V2FrameHeader id3v2fh; //创建一个ID3v2标签帧头结构体 133 | memset(&id3v2fh, 0, 10); 134 | 135 | bool hasExtendedHeader = ((id3v2h.flags >> 6 & 0x1) == 1);//是否有扩展头 136 | 137 | if (hasExtendedHeader) 138 | { 139 | //如果有扩展头 140 | byte extendedHeaderSize[4] = {}; 141 | memset(&extendedHeaderSize, 0, 4); 142 | fread(&extendedHeaderSize, 4, 1, fp); 143 | //取得扩展头大小(不含以上数据) 144 | int extendedHeaderLength = extendedHeaderSize[0] * 0x1000000 + extendedHeaderSize[1] * 0x10000 + extendedHeaderSize[2] * 0x100 + extendedHeaderSize[3]; 145 | //跳过扩展头 146 | fseek(fp, extendedHeaderLength, SEEK_CUR); 147 | } 148 | 149 | fread(&id3v2fh, 10, 1, fp); //将数据写到ID3V2FrameHeader结构体中 150 | int curDataLength = 10; //存放当前已经读取的数据大小,刚才已经读入10字节 151 | while ((strncmp(id3v2fh.FrameId, "APIC", 4) != 0))//如果帧头没有APIC标识符则循环执行 152 | { 153 | if (curDataLength > tagTotalLength) 154 | { 155 | fclose(fp); 156 | fp = NULL; 157 | return false; //未发现图片数据 158 | } 159 | //计算帧数据长度 160 | //使用int,不溢出的上限约2GB(标签帧没有这么大吧……) 161 | int frameLength = id3v2fh.size[0] * 0x1000000 + id3v2fh.size[1] * 0x10000 + id3v2fh.size[2] * 0x100 + id3v2fh.size[3]; 162 | fseek(fp, frameLength, SEEK_CUR); //向前跳跃到下一个帧头 163 | memset(&id3v2fh, 0, 10); //清除帧头结构体数据 164 | fread(&id3v2fh, 10, 1, fp); //重新读取数据 165 | curDataLength += frameLength + 10; //记录当前所在的ID3标签位置,以便退出循环 166 | } 167 | 168 | //计算一下当前图片帧的数据长度 169 | int frameLength = id3v2fh.size[0] * 0x1000000 + id3v2fh.size[1] * 0x10000 + id3v2fh.size[2] * 0x100 + id3v2fh.size[3]; 170 | 171 | /* 172 | 这是ID3v2.3图片帧的结构: 173 | 174 |
175 | 头部10个字节的帧头 176 | 177 | Text encoding $xx 178 | 要跳过一个字节(文字编码) 179 | 180 | MIME type $00 181 | 跳过(文本 + /0),这里可得到文件格式 182 | 183 | Picture type $xx 184 | 跳过一个字节(图片类型) 185 | 186 | Description $00 (00) 187 | 跳过(文本 + /0),这里可得到描述信息 188 | 189 | Picture data 190 | 这是真正的图片数据 191 | */ 192 | int nonPicDataLength = 0; //非图片数据的长度 193 | fseek(fp, 1, SEEK_CUR); //信仰之跃 194 | nonPicDataLength++; 195 | 196 | char tempData[20] = {}; //临时存放数据的空间 197 | char mimeType[20] = {}; //图片类型 198 | int mimeTypeLength = 0; //图片类型文本长度 199 | 200 | fread(&tempData, 20, 1, fp);//取得一小段数据 201 | fseek(fp, -20, SEEK_CUR); //回到原位 202 | 203 | strcpy(mimeType, tempData); //复制出一个字符串 204 | mimeTypeLength = strlen(mimeType) + 1; //测试字符串长度,补上末尾00 205 | fseek(fp, mimeTypeLength, SEEK_CUR); //跳到此数据之后 206 | nonPicDataLength += mimeTypeLength; //记录长度 207 | 208 | fseek(fp, 1, SEEK_CUR); //再一次信仰之跃 209 | nonPicDataLength++; 210 | 211 | int temp = 0; //记录当前字节数据的变量 212 | fread(&temp, 1, 1, fp); //读取一个字节 213 | nonPicDataLength++; //+1 214 | while (temp) //循环到temp为0 215 | { 216 | fread(&temp, 1, 1, fp); //如果不是0继续读一字节的数据 217 | nonPicDataLength++; //计数 218 | } 219 | //跳过了Description文本,以及末尾的\0 220 | 221 | //非主流情况检测+获得文件格式 222 | memset(tempData, 0, 20); 223 | fread(&tempData, 8, 1, fp); 224 | fseek(fp, -8, SEEK_CUR); //回到原位 225 | //判断40次,一位一位跳到文件头 226 | bool ok = false; //是否正确识别出文件头 227 | for (int i = 0; i < 40; i++) 228 | { 229 | //校验文件头 230 | if (verificationPictureFormat(tempData)) 231 | { 232 | ok = true; 233 | break; 234 | } 235 | else 236 | { 237 | //如果校验失败尝试继续向后校验 238 | fseek(fp, 1, SEEK_CUR); 239 | nonPicDataLength++; 240 | fread(&tempData, 8, 1, fp); 241 | fseek(fp, -8, SEEK_CUR); 242 | } 243 | } 244 | 245 | if (!ok) 246 | { 247 | fclose(fp); 248 | fp = NULL; 249 | freePictureData(); 250 | return false; //无法识别的数据 251 | } 252 | //-----真正的图片数据----- 253 | picLength = frameLength - nonPicDataLength; //计算图片数据长度 254 | pPicData = new byte[picLength]; //动态分配图片数据内存空间 255 | memset(pPicData, 0, picLength); //清空图片数据内存 256 | fread(pPicData, picLength, 1, fp); //得到图片数据 257 | //------------------------ 258 | fclose(fp); //操作已完成,关闭文件。 259 | } 260 | else if (id3v2h.major == 2) 261 | { 262 | //ID3v2.2 263 | ID3V22FrameHeader id3v2fh; //创建一个ID3v2.2标签帧头结构体 264 | memset(&id3v2fh, 0, 6); 265 | fread(&id3v2fh, 6, 1, fp); //将数据写到ID3V2.2FrameHeader结构体中 266 | int curDataLength = 6; //存放当前已经读取的数据大小,刚才已经读入6字节 267 | while ((strncmp(id3v2fh.FrameId, "PIC", 3) != 0))//如果帧头没有PIC标识符则循环执行 268 | { 269 | if (curDataLength > tagTotalLength) 270 | { 271 | fclose(fp); 272 | fp = NULL; 273 | return false; //未发现图片数据 274 | } 275 | //计算帧数据长度 276 | int frameLength = id3v2fh.size[0] * 0x10000 + id3v2fh.size[1] * 0x100 + id3v2fh.size[2]; 277 | fseek(fp, frameLength, SEEK_CUR); //向前跳跃到下一个帧头 278 | memset(&id3v2fh, 0, 6); //清除帧头结构体数据 279 | fread(&id3v2fh, 6, 1, fp); //重新读取数据 280 | curDataLength += frameLength + 6; //记录当前所在的ID3标签位置,以便退出循环 281 | } 282 | 283 | int frameLength = id3v2fh.size[0] * 0x10000 + id3v2fh.size[1] * 0x100 + id3v2fh.size[2]; //如果读到了图片帧,计算帧长 284 | 285 | /* 286 | 数据格式: 287 | 288 | Attached picture "PIC" 289 | Frame size $xx xx xx 290 | Text encoding $xx 291 | Image format $xx xx xx 292 | Picture type $xx 293 | Description $00 (00) 294 | Picture data 295 | */ 296 | 297 | int nonPicDataLength = 0; //非图片数据的长度 298 | fseek(fp, 1, SEEK_CUR); //信仰之跃 Text encoding 299 | nonPicDataLength++; 300 | 301 | char imageType[4] = {}; 302 | memset(&imageType, 0, 4); 303 | fread(&imageType, 3, 1, fp);//图像格式 304 | nonPicDataLength += 3; 305 | 306 | fseek(fp, 1, SEEK_CUR); //信仰之跃 Picture type 307 | nonPicDataLength++; 308 | 309 | int temp = 0; //记录当前字节数据的变量 310 | fread(&temp, 1, 1, fp); //读取一个字节 311 | nonPicDataLength++; //+1 312 | while (temp) //循环到temp为0 313 | { 314 | fread(&temp, 1, 1, fp); //如果不是0继续读一字节的数据 315 | nonPicDataLength++; //计数 316 | } 317 | //跳过了Description文本,以及末尾的\0 318 | 319 | //非主流情况检测 320 | char tempData[20] = {}; 321 | memset(tempData, 0, 20); 322 | fread(&tempData, 8, 1, fp); 323 | fseek(fp, -8, SEEK_CUR); //回到原位 324 | //判断40次,一位一位跳到文件头 325 | bool ok = false; //是否正确识别出文件头 326 | for (int i = 0; i < 40; i++) 327 | { 328 | //校验文件头 329 | if (verificationPictureFormat(tempData)) 330 | { 331 | ok = true; 332 | break; 333 | } 334 | else 335 | { 336 | //如果校验失败尝试继续向后校验 337 | fseek(fp, 1, SEEK_CUR); 338 | nonPicDataLength++; 339 | fread(&tempData, 8, 1, fp); 340 | fseek(fp, -8, SEEK_CUR); 341 | } 342 | } 343 | 344 | if (!ok) 345 | { 346 | fclose(fp); 347 | fp = NULL; 348 | freePictureData(); 349 | return false; //无法识别的数据 350 | } 351 | //-----真正的图片数据----- 352 | picLength = frameLength - nonPicDataLength; //计算图片数据长度 353 | pPicData = new byte[picLength]; //动态分配图片数据内存空间 354 | memset(pPicData, 0, picLength); //清空图片数据内存 355 | fread(pPicData, picLength, 1, fp); //得到图片数据 356 | //------------------------ 357 | fclose(fp); //操作已完成,关闭文件。 358 | } 359 | else 360 | { 361 | //其余不支持的版本 362 | fclose(fp);//关闭 363 | fp = NULL; 364 | return false; 365 | } 366 | return true; 367 | } 368 | 369 | //取得图片数据的长度 370 | int getPictureLength() 371 | { 372 | return picLength; 373 | } 374 | 375 | //取得指向图片数据的指针 376 | byte *getPictureDataPtr() 377 | { 378 | return pPicData; 379 | } 380 | 381 | //取得图片数据的扩展名(指针) 382 | char *getPictureFormat() 383 | { 384 | return picFormat; 385 | } 386 | 387 | bool writePictureDataToFile(const char *outFilePath) 388 | { 389 | FILE *fp = NULL; 390 | if (picLength > 0) 391 | { 392 | fp = fopen(outFilePath, "wb"); //打开目标文件 393 | if (fp) //打开成功 394 | { 395 | fwrite(pPicData, picLength, 1, fp); //写入文件 396 | fclose(fp); //关闭 397 | return true; 398 | } 399 | else 400 | { 401 | return false; //文件打开失败 402 | } 403 | } 404 | else 405 | { 406 | return false; //没有图像数据 407 | } 408 | } 409 | 410 | //提取图片文件,参数1:输入文件,参数2:输出文件,返回值:是否成功 411 | bool extractPicture(const char *inFilePath, const char *outFilePath) 412 | { 413 | if (loadPictureData(inFilePath)) //如果取得图片数据成功 414 | { 415 | if (writePictureDataToFile(outFilePath)) 416 | { 417 | return true; //文件写出成功 418 | } 419 | else 420 | { 421 | return false; //文件写出失败 422 | } 423 | } 424 | else 425 | { 426 | return false; //无图片数据 427 | } 428 | freePictureData(); 429 | } 430 | } 431 | #endif 432 | -------------------------------------------------------------------------------- /Sources/MyGlobalShortCut/MyGlobalShortCut.cpp: -------------------------------------------------------------------------------- 1 | #include "MyGlobalShortCut.h" 2 | 3 | MyGlobalShortCut::~MyGlobalShortCut() 4 | { 5 | unregisterHotKey(); 6 | } 7 | MyGlobalShortCut::MyGlobalShortCut(QString key, QObject *app) 8 | { 9 | m_key = QKeySequence(key); 10 | m_filter = new MyWinEventFilter(this); 11 | m_app->installNativeEventFilter(m_filter); 12 | 13 | 14 | registerHotKey(); 15 | } 16 | 17 | void MyGlobalShortCut::activateShortcut() 18 | { 19 | emit activated(); 20 | } 21 | bool MyGlobalShortCut::registerHotKey() 22 | { 23 | Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier; 24 | key = (m_key.isEmpty() ? Qt::Key(0) : Qt::Key((m_key[0] ^ allMods) & m_key[0])); 25 | mods = m_key.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(m_key[0] & allMods); 26 | const quint32 nativeKey = nativeKeycode(key); 27 | const quint32 nativeMods = nativeModifiers(mods); 28 | 29 | shortcuts.insert(qMakePair(nativeKey, nativeMods),this); 30 | return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey); 31 | 32 | } 33 | bool MyGlobalShortCut::unregisterHotKey() 34 | { 35 | return UnregisterHotKey(0, (quint32)nativeModifiers(mods) ^ (quint32)nativeKeycode(key)); 36 | } 37 | quint32 MyGlobalShortCut::nativeKeycode(Qt::Key key) 38 | { 39 | switch (key) 40 | { 41 | case Qt::Key_Escape: 42 | return VK_ESCAPE; 43 | case Qt::Key_Tab: 44 | case Qt::Key_Backtab: 45 | return VK_TAB; 46 | case Qt::Key_Backspace: 47 | return VK_BACK; 48 | case Qt::Key_Return: 49 | case Qt::Key_Enter: 50 | return VK_RETURN; 51 | case Qt::Key_Insert: 52 | return VK_INSERT; 53 | case Qt::Key_Delete: 54 | return VK_DELETE; 55 | case Qt::Key_Pause: 56 | return VK_PAUSE; 57 | case Qt::Key_Print: 58 | return VK_PRINT; 59 | case Qt::Key_Clear: 60 | return VK_CLEAR; 61 | case Qt::Key_Home: 62 | return VK_HOME; 63 | case Qt::Key_End: 64 | return VK_END; 65 | case Qt::Key_Left: 66 | return VK_LEFT; 67 | case Qt::Key_Up: 68 | return VK_UP; 69 | case Qt::Key_Right: 70 | return VK_RIGHT; 71 | case Qt::Key_Down: 72 | return VK_DOWN; 73 | case Qt::Key_PageUp: 74 | return VK_PRIOR; 75 | case Qt::Key_PageDown: 76 | return VK_NEXT; 77 | case Qt::Key_F1: 78 | return VK_F1; 79 | case Qt::Key_F2: 80 | return VK_F2; 81 | case Qt::Key_F3: 82 | return VK_F3; 83 | case Qt::Key_F4: 84 | return VK_F4; 85 | case Qt::Key_F5: 86 | return VK_F5; 87 | case Qt::Key_F6: 88 | return VK_F6; 89 | case Qt::Key_F7: 90 | return VK_F7; 91 | case Qt::Key_F8: 92 | return VK_F8; 93 | case Qt::Key_F9: 94 | return VK_F9; 95 | case Qt::Key_F10: 96 | return VK_F10; 97 | case Qt::Key_F11: 98 | return VK_F11; 99 | case Qt::Key_F12: 100 | return VK_F12; 101 | case Qt::Key_F13: 102 | return VK_F13; 103 | case Qt::Key_F14: 104 | return VK_F14; 105 | case Qt::Key_F15: 106 | return VK_F15; 107 | case Qt::Key_F16: 108 | return VK_F16; 109 | case Qt::Key_F17: 110 | return VK_F17; 111 | case Qt::Key_F18: 112 | return VK_F18; 113 | case Qt::Key_F19: 114 | return VK_F19; 115 | case Qt::Key_F20: 116 | return VK_F20; 117 | case Qt::Key_F21: 118 | return VK_F21; 119 | case Qt::Key_F22: 120 | return VK_F22; 121 | case Qt::Key_F23: 122 | return VK_F23; 123 | case Qt::Key_F24: 124 | return VK_F24; 125 | case Qt::Key_Space: 126 | return VK_SPACE; 127 | case Qt::Key_Asterisk: 128 | return VK_MULTIPLY; 129 | case Qt::Key_Plus: 130 | return VK_ADD; 131 | case Qt::Key_Comma: 132 | return VK_SEPARATOR; 133 | case Qt::Key_Minus: 134 | return VK_SUBTRACT; 135 | case Qt::Key_Slash: 136 | return VK_DIVIDE; 137 | 138 | // numbers 139 | case Qt::Key_0: 140 | case Qt::Key_1: 141 | case Qt::Key_2: 142 | case Qt::Key_3: 143 | case Qt::Key_4: 144 | case Qt::Key_5: 145 | case Qt::Key_6: 146 | case Qt::Key_7: 147 | case Qt::Key_8: 148 | case Qt::Key_9: 149 | return key; 150 | 151 | // letters 152 | case Qt::Key_A: 153 | case Qt::Key_B: 154 | case Qt::Key_C: 155 | case Qt::Key_D: 156 | case Qt::Key_E: 157 | case Qt::Key_F: 158 | case Qt::Key_G: 159 | case Qt::Key_H: 160 | case Qt::Key_I: 161 | case Qt::Key_J: 162 | case Qt::Key_K: 163 | case Qt::Key_L: 164 | case Qt::Key_M: 165 | case Qt::Key_N: 166 | case Qt::Key_O: 167 | case Qt::Key_P: 168 | case Qt::Key_Q: 169 | case Qt::Key_R: 170 | case Qt::Key_S: 171 | case Qt::Key_T: 172 | case Qt::Key_U: 173 | case Qt::Key_V: 174 | case Qt::Key_W: 175 | case Qt::Key_X: 176 | case Qt::Key_Y: 177 | case Qt::Key_Z: 178 | return key; 179 | 180 | default: 181 | return 0; 182 | } 183 | } 184 | quint32 MyGlobalShortCut::nativeModifiers(Qt::KeyboardModifiers modifiers) 185 | { 186 | // MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN 187 | quint32 native = 0; 188 | if (modifiers & Qt::ShiftModifier) 189 | native |= MOD_SHIFT; 190 | if (modifiers & Qt::ControlModifier) 191 | native |= MOD_CONTROL; 192 | if (modifiers & Qt::AltModifier) 193 | native |= MOD_ALT; 194 | if (modifiers & Qt::MetaModifier) 195 | native |= MOD_WIN; 196 | // TODO: resolve these? 197 | //if (modifiers & Qt::KeypadModifier) 198 | //if (modifiers & Qt::GroupSwitchModifier) 199 | return native; 200 | } 201 | -------------------------------------------------------------------------------- /Sources/MyGlobalShortCut/MyGlobalShortCut.h: -------------------------------------------------------------------------------- 1 | 2 | // Qt 升级到5.x版本后 3 | // QAbstractEventDispatcher 中函数发生变动 4 | // 导致libqxt库中的qxtGlobalShortcut挂掉 5 | // 参考qxtGlobalShortcut写了一个全局热键类 6 | // 用法与qxtGlobalShortcut一致 7 | // 在 Win8.1 + Qt5.11 下能正常使用 8 | // by 迷路君 2014.03.27 9 | 10 | #pragma once 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | class MyGlobalShortCut : public QObject 18 | { 19 | Q_OBJECT 20 | public: 21 | 22 | 23 | MyGlobalShortCut(QString key,QObject* app); 24 | ~MyGlobalShortCut(); 25 | void activateShortcut(); 26 | bool registerHotKey(); 27 | bool unregisterHotKey(); 28 | QHash, MyGlobalShortCut*> shortcuts; 29 | private: 30 | QApplication *m_app; 31 | MyWinEventFilter *m_filter; 32 | QKeySequence m_key; 33 | Qt::Key key; 34 | Qt::KeyboardModifiers mods; 35 | static quint32 nativeKeycode(Qt::Key keycode); 36 | static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers); 37 | signals: 38 | void activated(); 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /Sources/MyGlobalShortCut/MyWinEventFilter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | MyWinEventFilter::~MyWinEventFilter() 6 | { 7 | 8 | } 9 | 10 | MyWinEventFilter::MyWinEventFilter(MyGlobalShortCut *shortcut) 11 | : m_shortcut(shortcut) 12 | { 13 | 14 | } 15 | 16 | 17 | bool MyWinEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *) 18 | { 19 | if(eventType == "windows_generic_MSG") 20 | { 21 | MSG *msg = static_cast(message); 22 | if(msg->message == WM_HOTKEY) 23 | { 24 | // if(msg->wParam == VK_F10) 25 | // { 26 | // m_shortcut->activateShortcut(); 27 | // return true; 28 | // } 29 | const quint32 keycode = HIWORD(msg->lParam); 30 | const quint32 modifiers = LOWORD(msg->lParam); 31 | bool res = m_shortcut->shortcuts.value(qMakePair(keycode, modifiers)); 32 | if(res) 33 | { 34 | m_shortcut ->activateShortcut(); 35 | return true; 36 | } 37 | } 38 | 39 | } 40 | return false; 41 | } 42 | -------------------------------------------------------------------------------- /Sources/MyGlobalShortCut/MyWinEventFilter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class MyGlobalShortCut; 5 | 6 | class MyWinEventFilter : public QAbstractNativeEventFilter 7 | { 8 | public: 9 | MyWinEventFilter(MyGlobalShortCut *shortcut); 10 | ~MyWinEventFilter(); 11 | virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *); 12 | private: 13 | MyGlobalShortCut *m_shortcut; 14 | }; 15 | -------------------------------------------------------------------------------- /Sources/ShadowPlayer.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2014-04-30T21:32:45 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui winextras 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = ShadowPlayer 12 | TEMPLATE = app 13 | 14 | 15 | SOURCES += main.cpp\ 16 | shadowplayer.cpp \ 17 | player.cpp \ 18 | lyrics.cpp \ 19 | lrcbar.cpp \ 20 | spslider.cpp \ 21 | playlist.cpp \ 22 | MyGlobalShortCut/MyGlobalShortCut.cpp \ 23 | MyGlobalShortCut/MyWinEventFilter.cpp \ 24 | osd.cpp \ 25 | fftdisplay.cpp \ 26 | shadowlabel.cpp 27 | 28 | HEADERS += shadowplayer.h \ 29 | player.h \ 30 | tags.h \ 31 | lyrics.h \ 32 | lrcbar.h \ 33 | spslider.h \ 34 | playlist.h \ 35 | MyGlobalShortCut/MyGlobalShortCut.h \ 36 | MyGlobalShortCut/MyWinEventFilter.h \ 37 | osd.h \ 38 | fftdisplay.h \ 39 | shadowlabel.h \ 40 | ID3v2Pic.h 41 | 42 | FORMS += shadowplayer.ui \ 43 | lrcbar.ui \ 44 | playlist.ui \ 45 | osd.ui 46 | 47 | INCLUDEPATH += $$PWD/ 48 | DEPENDPATH += $$PWD/ 49 | 50 | LIBS += -L$$PWD/ -lbass 51 | PRE_TARGETDEPS += $$PWD/bass.lib 52 | LIBS += -L$$PWD/ -ltags 53 | PRE_TARGETDEPS += $$PWD/tags.lib 54 | LIBS += -L$$PWD/ -lbass_ape 55 | PRE_TARGETDEPS += $$PWD/bass_ape.lib 56 | LIBS += -L$$PWD/ -lbass_aac 57 | PRE_TARGETDEPS += $$PWD/bass_aac.lib 58 | LIBS += -L$$PWD/ -lbass_alac 59 | PRE_TARGETDEPS += $$PWD/bass_alac.lib 60 | LIBS += -L$$PWD/ -lbass_tta 61 | PRE_TARGETDEPS += $$PWD/bass_tta.lib 62 | LIBS += -L$$PWD/ -lbassflac 63 | PRE_TARGETDEPS += $$PWD/bassflac.lib 64 | LIBS += -L$$PWD/ -lbasswma 65 | PRE_TARGETDEPS += $$PWD/basswma.lib 66 | LIBS += -L$$PWD/ -lbasswv 67 | PRE_TARGETDEPS += $$PWD/basswv.lib 68 | LIBS += -L$$PWD/ -lbass_fx 69 | PRE_TARGETDEPS += $$PWD/bass_fx.lib 70 | 71 | 72 | RESOURCES += \ 73 | res.qrc 74 | 75 | OTHER_FILES += \ 76 | ShadowPlayer.rc 77 | 78 | RC_FILE = ShadowPlayer.rc 79 | -------------------------------------------------------------------------------- /Sources/ShadowPlayer.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "ICO/ShadowPlayer.ico" 2 | -------------------------------------------------------------------------------- /Sources/bass.h: -------------------------------------------------------------------------------- 1 | /* 2 | BASS 2.4 C/C++ header file 3 | Copyright (c) 1999-2013 Un4seen Developments Ltd. 4 | 5 | See the BASS.CHM file for more detailed documentation 6 | */ 7 | 8 | #ifndef BASS_H 9 | #define BASS_H 10 | 11 | #ifdef _WIN32 12 | #include 13 | typedef unsigned __int64 QWORD; 14 | #else 15 | #include 16 | #define WINAPI 17 | #define CALLBACK 18 | typedef uint8_t BYTE; 19 | typedef uint16_t WORD; 20 | typedef uint32_t DWORD; 21 | typedef uint64_t QWORD; 22 | #ifndef __OBJC__ 23 | typedef int BOOL; 24 | #endif 25 | #ifndef TRUE 26 | #define TRUE 1 27 | #define FALSE 0 28 | #endif 29 | #define LOBYTE(a) (BYTE)(a) 30 | #define HIBYTE(a) (BYTE)((a)>>8) 31 | #define LOWORD(a) (WORD)(a) 32 | #define HIWORD(a) (WORD)((a)>>16) 33 | #define MAKEWORD(a,b) (WORD)(((a)&0xff)|((b)<<8)) 34 | #define MAKELONG(a,b) (DWORD)(((a)&0xffff)|((b)<<16)) 35 | #endif 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif 40 | 41 | #define BASSVERSION 0x204 // API version 42 | #define BASSVERSIONTEXT "2.4" 43 | 44 | #ifndef BASSDEF 45 | #define BASSDEF(f) WINAPI f 46 | #endif 47 | 48 | typedef DWORD HMUSIC; // MOD music handle 49 | typedef DWORD HSAMPLE; // sample handle 50 | typedef DWORD HCHANNEL; // playing sample's channel handle 51 | typedef DWORD HSTREAM; // sample stream handle 52 | typedef DWORD HRECORD; // recording handle 53 | typedef DWORD HSYNC; // synchronizer handle 54 | typedef DWORD HDSP; // DSP handle 55 | typedef DWORD HFX; // DX8 effect handle 56 | typedef DWORD HPLUGIN; // Plugin handle 57 | 58 | // Error codes returned by BASS_ErrorGetCode 59 | #define BASS_OK 0 // all is OK 60 | #define BASS_ERROR_MEM 1 // memory error 61 | #define BASS_ERROR_FILEOPEN 2 // can't open the file 62 | #define BASS_ERROR_DRIVER 3 // can't find a free/valid driver 63 | #define BASS_ERROR_BUFLOST 4 // the sample buffer was lost 64 | #define BASS_ERROR_HANDLE 5 // invalid handle 65 | #define BASS_ERROR_FORMAT 6 // unsupported sample format 66 | #define BASS_ERROR_POSITION 7 // invalid position 67 | #define BASS_ERROR_INIT 8 // BASS_Init has not been successfully called 68 | #define BASS_ERROR_START 9 // BASS_Start has not been successfully called 69 | #define BASS_ERROR_ALREADY 14 // already initialized/paused/whatever 70 | #define BASS_ERROR_NOCHAN 18 // can't get a free channel 71 | #define BASS_ERROR_ILLTYPE 19 // an illegal type was specified 72 | #define BASS_ERROR_ILLPARAM 20 // an illegal parameter was specified 73 | #define BASS_ERROR_NO3D 21 // no 3D support 74 | #define BASS_ERROR_NOEAX 22 // no EAX support 75 | #define BASS_ERROR_DEVICE 23 // illegal device number 76 | #define BASS_ERROR_NOPLAY 24 // not playing 77 | #define BASS_ERROR_FREQ 25 // illegal sample rate 78 | #define BASS_ERROR_NOTFILE 27 // the stream is not a file stream 79 | #define BASS_ERROR_NOHW 29 // no hardware voices available 80 | #define BASS_ERROR_EMPTY 31 // the MOD music has no sequence data 81 | #define BASS_ERROR_NONET 32 // no internet connection could be opened 82 | #define BASS_ERROR_CREATE 33 // couldn't create the file 83 | #define BASS_ERROR_NOFX 34 // effects are not available 84 | #define BASS_ERROR_NOTAVAIL 37 // requested data is not available 85 | #define BASS_ERROR_DECODE 38 // the channel is/isn't a "decoding channel" 86 | #define BASS_ERROR_DX 39 // a sufficient DirectX version is not installed 87 | #define BASS_ERROR_TIMEOUT 40 // connection timedout 88 | #define BASS_ERROR_FILEFORM 41 // unsupported file format 89 | #define BASS_ERROR_SPEAKER 42 // unavailable speaker 90 | #define BASS_ERROR_VERSION 43 // invalid BASS version (used by add-ons) 91 | #define BASS_ERROR_CODEC 44 // codec is not available/supported 92 | #define BASS_ERROR_ENDED 45 // the channel/file has ended 93 | #define BASS_ERROR_BUSY 46 // the device is busy 94 | #define BASS_ERROR_UNKNOWN -1 // some other mystery problem 95 | 96 | // BASS_SetConfig options 97 | #define BASS_CONFIG_BUFFER 0 98 | #define BASS_CONFIG_UPDATEPERIOD 1 99 | #define BASS_CONFIG_GVOL_SAMPLE 4 100 | #define BASS_CONFIG_GVOL_STREAM 5 101 | #define BASS_CONFIG_GVOL_MUSIC 6 102 | #define BASS_CONFIG_CURVE_VOL 7 103 | #define BASS_CONFIG_CURVE_PAN 8 104 | #define BASS_CONFIG_FLOATDSP 9 105 | #define BASS_CONFIG_3DALGORITHM 10 106 | #define BASS_CONFIG_NET_TIMEOUT 11 107 | #define BASS_CONFIG_NET_BUFFER 12 108 | #define BASS_CONFIG_PAUSE_NOPLAY 13 109 | #define BASS_CONFIG_NET_PREBUF 15 110 | #define BASS_CONFIG_NET_PASSIVE 18 111 | #define BASS_CONFIG_REC_BUFFER 19 112 | #define BASS_CONFIG_NET_PLAYLIST 21 113 | #define BASS_CONFIG_MUSIC_VIRTUAL 22 114 | #define BASS_CONFIG_VERIFY 23 115 | #define BASS_CONFIG_UPDATETHREADS 24 116 | #define BASS_CONFIG_DEV_BUFFER 27 117 | #define BASS_CONFIG_VISTA_TRUEPOS 30 118 | #define BASS_CONFIG_IOS_MIXAUDIO 34 119 | #define BASS_CONFIG_DEV_DEFAULT 36 120 | #define BASS_CONFIG_NET_READTIMEOUT 37 121 | #define BASS_CONFIG_VISTA_SPEAKERS 38 122 | #define BASS_CONFIG_IOS_SPEAKER 39 123 | #define BASS_CONFIG_HANDLES 41 124 | #define BASS_CONFIG_UNICODE 42 125 | #define BASS_CONFIG_SRC 43 126 | #define BASS_CONFIG_SRC_SAMPLE 44 127 | #define BASS_CONFIG_ASYNCFILE_BUFFER 45 128 | #define BASS_CONFIG_OGG_PRESCAN 47 129 | 130 | // BASS_SetConfigPtr options 131 | #define BASS_CONFIG_NET_AGENT 16 132 | #define BASS_CONFIG_NET_PROXY 17 133 | #define BASS_CONFIG_IOS_NOTIFY 46 134 | 135 | // BASS_Init flags 136 | #define BASS_DEVICE_8BITS 1 // 8 bit resolution, else 16 bit 137 | #define BASS_DEVICE_MONO 2 // mono, else stereo 138 | #define BASS_DEVICE_3D 4 // enable 3D functionality 139 | #define BASS_DEVICE_LATENCY 0x100 // calculate device latency (BASS_INFO struct) 140 | #define BASS_DEVICE_CPSPEAKERS 0x400 // detect speakers via Windows control panel 141 | #define BASS_DEVICE_SPEAKERS 0x800 // force enabling of speaker assignment 142 | #define BASS_DEVICE_NOSPEAKER 0x1000 // ignore speaker arrangement 143 | #define BASS_DEVICE_DMIX 0x2000 // use ALSA "dmix" plugin 144 | #define BASS_DEVICE_FREQ 0x4000 // set device sample rate 145 | 146 | // DirectSound interfaces (for use with BASS_GetDSoundObject) 147 | #define BASS_OBJECT_DS 1 // IDirectSound 148 | #define BASS_OBJECT_DS3DL 2 // IDirectSound3DListener 149 | 150 | // Device info structure 151 | typedef struct { 152 | #ifdef _WIN32_WCE 153 | const wchar_t *name; // description 154 | const wchar_t *driver; // driver 155 | #else 156 | const char *name; // description 157 | const char *driver; // driver 158 | #endif 159 | DWORD flags; 160 | } BASS_DEVICEINFO; 161 | 162 | // BASS_DEVICEINFO flags 163 | #define BASS_DEVICE_ENABLED 1 164 | #define BASS_DEVICE_DEFAULT 2 165 | #define BASS_DEVICE_INIT 4 166 | 167 | typedef struct { 168 | DWORD flags; // device capabilities (DSCAPS_xxx flags) 169 | DWORD hwsize; // size of total device hardware memory 170 | DWORD hwfree; // size of free device hardware memory 171 | DWORD freesam; // number of free sample slots in the hardware 172 | DWORD free3d; // number of free 3D sample slots in the hardware 173 | DWORD minrate; // min sample rate supported by the hardware 174 | DWORD maxrate; // max sample rate supported by the hardware 175 | BOOL eax; // device supports EAX? (always FALSE if BASS_DEVICE_3D was not used) 176 | DWORD minbuf; // recommended minimum buffer length in ms (requires BASS_DEVICE_LATENCY) 177 | DWORD dsver; // DirectSound version 178 | DWORD latency; // delay (in ms) before start of playback (requires BASS_DEVICE_LATENCY) 179 | DWORD initflags; // BASS_Init "flags" parameter 180 | DWORD speakers; // number of speakers available 181 | DWORD freq; // current output rate 182 | } BASS_INFO; 183 | 184 | // BASS_INFO flags (from DSOUND.H) 185 | #define DSCAPS_CONTINUOUSRATE 0x00000010 // supports all sample rates between min/maxrate 186 | #define DSCAPS_EMULDRIVER 0x00000020 // device does NOT have hardware DirectSound support 187 | #define DSCAPS_CERTIFIED 0x00000040 // device driver has been certified by Microsoft 188 | #define DSCAPS_SECONDARYMONO 0x00000100 // mono 189 | #define DSCAPS_SECONDARYSTEREO 0x00000200 // stereo 190 | #define DSCAPS_SECONDARY8BIT 0x00000400 // 8 bit 191 | #define DSCAPS_SECONDARY16BIT 0x00000800 // 16 bit 192 | 193 | // Recording device info structure 194 | typedef struct { 195 | DWORD flags; // device capabilities (DSCCAPS_xxx flags) 196 | DWORD formats; // supported standard formats (WAVE_FORMAT_xxx flags) 197 | DWORD inputs; // number of inputs 198 | BOOL singlein; // TRUE = only 1 input can be set at a time 199 | DWORD freq; // current input rate 200 | } BASS_RECORDINFO; 201 | 202 | // BASS_RECORDINFO flags (from DSOUND.H) 203 | #define DSCCAPS_EMULDRIVER DSCAPS_EMULDRIVER // device does NOT have hardware DirectSound recording support 204 | #define DSCCAPS_CERTIFIED DSCAPS_CERTIFIED // device driver has been certified by Microsoft 205 | 206 | // defines for formats field of BASS_RECORDINFO (from MMSYSTEM.H) 207 | #ifndef WAVE_FORMAT_1M08 208 | #define WAVE_FORMAT_1M08 0x00000001 /* 11.025 kHz, Mono, 8-bit */ 209 | #define WAVE_FORMAT_1S08 0x00000002 /* 11.025 kHz, Stereo, 8-bit */ 210 | #define WAVE_FORMAT_1M16 0x00000004 /* 11.025 kHz, Mono, 16-bit */ 211 | #define WAVE_FORMAT_1S16 0x00000008 /* 11.025 kHz, Stereo, 16-bit */ 212 | #define WAVE_FORMAT_2M08 0x00000010 /* 22.05 kHz, Mono, 8-bit */ 213 | #define WAVE_FORMAT_2S08 0x00000020 /* 22.05 kHz, Stereo, 8-bit */ 214 | #define WAVE_FORMAT_2M16 0x00000040 /* 22.05 kHz, Mono, 16-bit */ 215 | #define WAVE_FORMAT_2S16 0x00000080 /* 22.05 kHz, Stereo, 16-bit */ 216 | #define WAVE_FORMAT_4M08 0x00000100 /* 44.1 kHz, Mono, 8-bit */ 217 | #define WAVE_FORMAT_4S08 0x00000200 /* 44.1 kHz, Stereo, 8-bit */ 218 | #define WAVE_FORMAT_4M16 0x00000400 /* 44.1 kHz, Mono, 16-bit */ 219 | #define WAVE_FORMAT_4S16 0x00000800 /* 44.1 kHz, Stereo, 16-bit */ 220 | #endif 221 | 222 | // Sample info structure 223 | typedef struct { 224 | DWORD freq; // default playback rate 225 | float volume; // default volume (0-1) 226 | float pan; // default pan (-1=left, 0=middle, 1=right) 227 | DWORD flags; // BASS_SAMPLE_xxx flags 228 | DWORD length; // length (in bytes) 229 | DWORD max; // maximum simultaneous playbacks 230 | DWORD origres; // original resolution bits 231 | DWORD chans; // number of channels 232 | DWORD mingap; // minimum gap (ms) between creating channels 233 | DWORD mode3d; // BASS_3DMODE_xxx mode 234 | float mindist; // minimum distance 235 | float maxdist; // maximum distance 236 | DWORD iangle; // angle of inside projection cone 237 | DWORD oangle; // angle of outside projection cone 238 | float outvol; // delta-volume outside the projection cone 239 | DWORD vam; // voice allocation/management flags (BASS_VAM_xxx) 240 | DWORD priority; // priority (0=lowest, 0xffffffff=highest) 241 | } BASS_SAMPLE; 242 | 243 | #define BASS_SAMPLE_8BITS 1 // 8 bit 244 | #define BASS_SAMPLE_FLOAT 256 // 32-bit floating-point 245 | #define BASS_SAMPLE_MONO 2 // mono 246 | #define BASS_SAMPLE_LOOP 4 // looped 247 | #define BASS_SAMPLE_3D 8 // 3D functionality 248 | #define BASS_SAMPLE_SOFTWARE 16 // not using hardware mixing 249 | #define BASS_SAMPLE_MUTEMAX 32 // mute at max distance (3D only) 250 | #define BASS_SAMPLE_VAM 64 // DX7 voice allocation & management 251 | #define BASS_SAMPLE_FX 128 // old implementation of DX8 effects 252 | #define BASS_SAMPLE_OVER_VOL 0x10000 // override lowest volume 253 | #define BASS_SAMPLE_OVER_POS 0x20000 // override longest playing 254 | #define BASS_SAMPLE_OVER_DIST 0x30000 // override furthest from listener (3D only) 255 | 256 | #define BASS_STREAM_PRESCAN 0x20000 // enable pin-point seeking/length (MP3/MP2/MP1) 257 | #define BASS_MP3_SETPOS BASS_STREAM_PRESCAN 258 | #define BASS_STREAM_AUTOFREE 0x40000 // automatically free the stream when it stop/ends 259 | #define BASS_STREAM_RESTRATE 0x80000 // restrict the download rate of internet file streams 260 | #define BASS_STREAM_BLOCK 0x100000 // download/play internet file stream in small blocks 261 | #define BASS_STREAM_DECODE 0x200000 // don't play the stream, only decode (BASS_ChannelGetData) 262 | #define BASS_STREAM_STATUS 0x800000 // give server status info (HTTP/ICY tags) in DOWNLOADPROC 263 | 264 | #define BASS_MUSIC_FLOAT BASS_SAMPLE_FLOAT 265 | #define BASS_MUSIC_MONO BASS_SAMPLE_MONO 266 | #define BASS_MUSIC_LOOP BASS_SAMPLE_LOOP 267 | #define BASS_MUSIC_3D BASS_SAMPLE_3D 268 | #define BASS_MUSIC_FX BASS_SAMPLE_FX 269 | #define BASS_MUSIC_AUTOFREE BASS_STREAM_AUTOFREE 270 | #define BASS_MUSIC_DECODE BASS_STREAM_DECODE 271 | #define BASS_MUSIC_PRESCAN BASS_STREAM_PRESCAN // calculate playback length 272 | #define BASS_MUSIC_CALCLEN BASS_MUSIC_PRESCAN 273 | #define BASS_MUSIC_RAMP 0x200 // normal ramping 274 | #define BASS_MUSIC_RAMPS 0x400 // sensitive ramping 275 | #define BASS_MUSIC_SURROUND 0x800 // surround sound 276 | #define BASS_MUSIC_SURROUND2 0x1000 // surround sound (mode 2) 277 | #define BASS_MUSIC_FT2MOD 0x2000 // play .MOD as FastTracker 2 does 278 | #define BASS_MUSIC_PT1MOD 0x4000 // play .MOD as ProTracker 1 does 279 | #define BASS_MUSIC_NONINTER 0x10000 // non-interpolated sample mixing 280 | #define BASS_MUSIC_SINCINTER 0x800000 // sinc interpolated sample mixing 281 | #define BASS_MUSIC_POSRESET 0x8000 // stop all notes when moving position 282 | #define BASS_MUSIC_POSRESETEX 0x400000 // stop all notes and reset bmp/etc when moving position 283 | #define BASS_MUSIC_STOPBACK 0x80000 // stop the music on a backwards jump effect 284 | #define BASS_MUSIC_NOSAMPLE 0x100000 // don't load the samples 285 | 286 | // Speaker assignment flags 287 | #define BASS_SPEAKER_FRONT 0x1000000 // front speakers 288 | #define BASS_SPEAKER_REAR 0x2000000 // rear/side speakers 289 | #define BASS_SPEAKER_CENLFE 0x3000000 // center & LFE speakers (5.1) 290 | #define BASS_SPEAKER_REAR2 0x4000000 // rear center speakers (7.1) 291 | #define BASS_SPEAKER_N(n) ((n)<<24) // n'th pair of speakers (max 15) 292 | #define BASS_SPEAKER_LEFT 0x10000000 // modifier: left 293 | #define BASS_SPEAKER_RIGHT 0x20000000 // modifier: right 294 | #define BASS_SPEAKER_FRONTLEFT BASS_SPEAKER_FRONT|BASS_SPEAKER_LEFT 295 | #define BASS_SPEAKER_FRONTRIGHT BASS_SPEAKER_FRONT|BASS_SPEAKER_RIGHT 296 | #define BASS_SPEAKER_REARLEFT BASS_SPEAKER_REAR|BASS_SPEAKER_LEFT 297 | #define BASS_SPEAKER_REARRIGHT BASS_SPEAKER_REAR|BASS_SPEAKER_RIGHT 298 | #define BASS_SPEAKER_CENTER BASS_SPEAKER_CENLFE|BASS_SPEAKER_LEFT 299 | #define BASS_SPEAKER_LFE BASS_SPEAKER_CENLFE|BASS_SPEAKER_RIGHT 300 | #define BASS_SPEAKER_REAR2LEFT BASS_SPEAKER_REAR2|BASS_SPEAKER_LEFT 301 | #define BASS_SPEAKER_REAR2RIGHT BASS_SPEAKER_REAR2|BASS_SPEAKER_RIGHT 302 | 303 | #define BASS_ASYNCFILE 0x40000000 304 | #define BASS_UNICODE 0x80000000 305 | 306 | #define BASS_RECORD_PAUSE 0x8000 // start recording paused 307 | 308 | // DX7 voice allocation & management flags 309 | #define BASS_VAM_HARDWARE 1 310 | #define BASS_VAM_SOFTWARE 2 311 | #define BASS_VAM_TERM_TIME 4 312 | #define BASS_VAM_TERM_DIST 8 313 | #define BASS_VAM_TERM_PRIO 16 314 | 315 | // Channel info structure 316 | typedef struct { 317 | DWORD freq; // default playback rate 318 | DWORD chans; // channels 319 | DWORD flags; // BASS_SAMPLE/STREAM/MUSIC/SPEAKER flags 320 | DWORD ctype; // type of channel 321 | DWORD origres; // original resolution 322 | HPLUGIN plugin; // plugin 323 | HSAMPLE sample; // sample 324 | const char *filename; // filename 325 | } BASS_CHANNELINFO; 326 | 327 | // BASS_CHANNELINFO types 328 | #define BASS_CTYPE_SAMPLE 1 329 | #define BASS_CTYPE_RECORD 2 330 | #define BASS_CTYPE_STREAM 0x10000 331 | #define BASS_CTYPE_STREAM_OGG 0x10002 332 | #define BASS_CTYPE_STREAM_MP1 0x10003 333 | #define BASS_CTYPE_STREAM_MP2 0x10004 334 | #define BASS_CTYPE_STREAM_MP3 0x10005 335 | #define BASS_CTYPE_STREAM_AIFF 0x10006 336 | #define BASS_CTYPE_STREAM_CA 0x10007 337 | #define BASS_CTYPE_STREAM_MF 0x10008 338 | #define BASS_CTYPE_STREAM_WAV 0x40000 // WAVE flag, LOWORD=codec 339 | #define BASS_CTYPE_STREAM_WAV_PCM 0x50001 340 | #define BASS_CTYPE_STREAM_WAV_FLOAT 0x50003 341 | #define BASS_CTYPE_MUSIC_MOD 0x20000 342 | #define BASS_CTYPE_MUSIC_MTM 0x20001 343 | #define BASS_CTYPE_MUSIC_S3M 0x20002 344 | #define BASS_CTYPE_MUSIC_XM 0x20003 345 | #define BASS_CTYPE_MUSIC_IT 0x20004 346 | #define BASS_CTYPE_MUSIC_MO3 0x00100 // MO3 flag 347 | 348 | typedef struct { 349 | DWORD ctype; // channel type 350 | #ifdef _WIN32_WCE 351 | const wchar_t *name; // format description 352 | const wchar_t *exts; // file extension filter (*.ext1;*.ext2;etc...) 353 | #else 354 | const char *name; // format description 355 | const char *exts; // file extension filter (*.ext1;*.ext2;etc...) 356 | #endif 357 | } BASS_PLUGINFORM; 358 | 359 | typedef struct { 360 | DWORD version; // version (same form as BASS_GetVersion) 361 | DWORD formatc; // number of formats 362 | const BASS_PLUGINFORM *formats; // the array of formats 363 | } BASS_PLUGININFO; 364 | 365 | // 3D vector (for 3D positions/velocities/orientations) 366 | typedef struct BASS_3DVECTOR { 367 | #ifdef __cplusplus 368 | BASS_3DVECTOR() {}; 369 | BASS_3DVECTOR(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}; 370 | #endif 371 | float x; // +=right, -=left 372 | float y; // +=up, -=down 373 | float z; // +=front, -=behind 374 | } BASS_3DVECTOR; 375 | 376 | // 3D channel modes 377 | #define BASS_3DMODE_NORMAL 0 // normal 3D processing 378 | #define BASS_3DMODE_RELATIVE 1 // position is relative to the listener 379 | #define BASS_3DMODE_OFF 2 // no 3D processing 380 | 381 | // software 3D mixing algorithms (used with BASS_CONFIG_3DALGORITHM) 382 | #define BASS_3DALG_DEFAULT 0 383 | #define BASS_3DALG_OFF 1 384 | #define BASS_3DALG_FULL 2 385 | #define BASS_3DALG_LIGHT 3 386 | 387 | // EAX environments, use with BASS_SetEAXParameters 388 | enum 389 | { 390 | EAX_ENVIRONMENT_GENERIC, 391 | EAX_ENVIRONMENT_PADDEDCELL, 392 | EAX_ENVIRONMENT_ROOM, 393 | EAX_ENVIRONMENT_BATHROOM, 394 | EAX_ENVIRONMENT_LIVINGROOM, 395 | EAX_ENVIRONMENT_STONEROOM, 396 | EAX_ENVIRONMENT_AUDITORIUM, 397 | EAX_ENVIRONMENT_CONCERTHALL, 398 | EAX_ENVIRONMENT_CAVE, 399 | EAX_ENVIRONMENT_ARENA, 400 | EAX_ENVIRONMENT_HANGAR, 401 | EAX_ENVIRONMENT_CARPETEDHALLWAY, 402 | EAX_ENVIRONMENT_HALLWAY, 403 | EAX_ENVIRONMENT_STONECORRIDOR, 404 | EAX_ENVIRONMENT_ALLEY, 405 | EAX_ENVIRONMENT_FOREST, 406 | EAX_ENVIRONMENT_CITY, 407 | EAX_ENVIRONMENT_MOUNTAINS, 408 | EAX_ENVIRONMENT_QUARRY, 409 | EAX_ENVIRONMENT_PLAIN, 410 | EAX_ENVIRONMENT_PARKINGLOT, 411 | EAX_ENVIRONMENT_SEWERPIPE, 412 | EAX_ENVIRONMENT_UNDERWATER, 413 | EAX_ENVIRONMENT_DRUGGED, 414 | EAX_ENVIRONMENT_DIZZY, 415 | EAX_ENVIRONMENT_PSYCHOTIC, 416 | 417 | EAX_ENVIRONMENT_COUNT // total number of environments 418 | }; 419 | 420 | // EAX presets, usage: BASS_SetEAXParameters(EAX_PRESET_xxx) 421 | #define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F 422 | #define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F 423 | #define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F 424 | #define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F 425 | #define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F 426 | #define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F 427 | #define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F 428 | #define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F 429 | #define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F 430 | #define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F 431 | #define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F 432 | #define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F 433 | #define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F 434 | #define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F 435 | #define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F 436 | #define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F 437 | #define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F 438 | #define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F 439 | #define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F 440 | #define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F 441 | #define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F 442 | #define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F 443 | #define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F 444 | #define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F 445 | #define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F 446 | #define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F 447 | 448 | typedef DWORD (CALLBACK STREAMPROC)(HSTREAM handle, void *buffer, DWORD length, void *user); 449 | /* User stream callback function. NOTE: A stream function should obviously be as quick 450 | as possible, other streams (and MOD musics) can't be mixed until it's finished. 451 | handle : The stream that needs writing 452 | buffer : Buffer to write the samples in 453 | length : Number of bytes to write 454 | user : The 'user' parameter value given when calling BASS_StreamCreate 455 | RETURN : Number of bytes written. Set the BASS_STREAMPROC_END flag to end 456 | the stream. */ 457 | 458 | #define BASS_STREAMPROC_END 0x80000000 // end of user stream flag 459 | 460 | // special STREAMPROCs 461 | #define STREAMPROC_DUMMY (STREAMPROC*)0 // "dummy" stream 462 | #define STREAMPROC_PUSH (STREAMPROC*)-1 // push stream 463 | 464 | // BASS_StreamCreateFileUser file systems 465 | #define STREAMFILE_NOBUFFER 0 466 | #define STREAMFILE_BUFFER 1 467 | #define STREAMFILE_BUFFERPUSH 2 468 | 469 | // User file stream callback functions 470 | typedef void (CALLBACK FILECLOSEPROC)(void *user); 471 | typedef QWORD (CALLBACK FILELENPROC)(void *user); 472 | typedef DWORD (CALLBACK FILEREADPROC)(void *buffer, DWORD length, void *user); 473 | typedef BOOL (CALLBACK FILESEEKPROC)(QWORD offset, void *user); 474 | 475 | typedef struct { 476 | FILECLOSEPROC *close; 477 | FILELENPROC *length; 478 | FILEREADPROC *read; 479 | FILESEEKPROC *seek; 480 | } BASS_FILEPROCS; 481 | 482 | // BASS_StreamPutFileData options 483 | #define BASS_FILEDATA_END 0 // end & close the file 484 | 485 | // BASS_StreamGetFilePosition modes 486 | #define BASS_FILEPOS_CURRENT 0 487 | #define BASS_FILEPOS_DECODE BASS_FILEPOS_CURRENT 488 | #define BASS_FILEPOS_DOWNLOAD 1 489 | #define BASS_FILEPOS_END 2 490 | #define BASS_FILEPOS_START 3 491 | #define BASS_FILEPOS_CONNECTED 4 492 | #define BASS_FILEPOS_BUFFER 5 493 | #define BASS_FILEPOS_SOCKET 6 494 | 495 | typedef void (CALLBACK DOWNLOADPROC)(const void *buffer, DWORD length, void *user); 496 | /* Internet stream download callback function. 497 | buffer : Buffer containing the downloaded data... NULL=end of download 498 | length : Number of bytes in the buffer 499 | user : The 'user' parameter value given when calling BASS_StreamCreateURL */ 500 | 501 | // BASS_ChannelSetSync types 502 | #define BASS_SYNC_POS 0 503 | #define BASS_SYNC_END 2 504 | #define BASS_SYNC_META 4 505 | #define BASS_SYNC_SLIDE 5 506 | #define BASS_SYNC_STALL 6 507 | #define BASS_SYNC_DOWNLOAD 7 508 | #define BASS_SYNC_FREE 8 509 | #define BASS_SYNC_SETPOS 11 510 | #define BASS_SYNC_MUSICPOS 10 511 | #define BASS_SYNC_MUSICINST 1 512 | #define BASS_SYNC_MUSICFX 3 513 | #define BASS_SYNC_OGG_CHANGE 12 514 | #define BASS_SYNC_MIXTIME 0x40000000 // FLAG: sync at mixtime, else at playtime 515 | #define BASS_SYNC_ONETIME 0x80000000 // FLAG: sync only once, else continuously 516 | 517 | typedef void (CALLBACK SYNCPROC)(HSYNC handle, DWORD channel, DWORD data, void *user); 518 | /* Sync callback function. NOTE: a sync callback function should be very 519 | quick as other syncs can't be processed until it has finished. If the sync 520 | is a "mixtime" sync, then other streams and MOD musics can't be mixed until 521 | it's finished either. 522 | handle : The sync that has occured 523 | channel: Channel that the sync occured in 524 | data : Additional data associated with the sync's occurance 525 | user : The 'user' parameter given when calling BASS_ChannelSetSync */ 526 | 527 | typedef void (CALLBACK DSPPROC)(HDSP handle, DWORD channel, void *buffer, DWORD length, void *user); 528 | /* DSP callback function. NOTE: A DSP function should obviously be as quick as 529 | possible... other DSP functions, streams and MOD musics can not be processed 530 | until it's finished. 531 | handle : The DSP handle 532 | channel: Channel that the DSP is being applied to 533 | buffer : Buffer to apply the DSP to 534 | length : Number of bytes in the buffer 535 | user : The 'user' parameter given when calling BASS_ChannelSetDSP */ 536 | 537 | typedef BOOL (CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, DWORD length, void *user); 538 | /* Recording callback function. 539 | handle : The recording handle 540 | buffer : Buffer containing the recorded sample data 541 | length : Number of bytes 542 | user : The 'user' parameter value given when calling BASS_RecordStart 543 | RETURN : TRUE = continue recording, FALSE = stop */ 544 | 545 | // BASS_ChannelIsActive return values 546 | #define BASS_ACTIVE_STOPPED 0 547 | #define BASS_ACTIVE_PLAYING 1 548 | #define BASS_ACTIVE_STALLED 2 549 | #define BASS_ACTIVE_PAUSED 3 550 | 551 | // Channel attributes 552 | #define BASS_ATTRIB_FREQ 1 553 | #define BASS_ATTRIB_VOL 2 554 | #define BASS_ATTRIB_PAN 3 555 | #define BASS_ATTRIB_EAXMIX 4 556 | #define BASS_ATTRIB_NOBUFFER 5 557 | #define BASS_ATTRIB_CPU 7 558 | #define BASS_ATTRIB_SRC 8 559 | #define BASS_ATTRIB_MUSIC_AMPLIFY 0x100 560 | #define BASS_ATTRIB_MUSIC_PANSEP 0x101 561 | #define BASS_ATTRIB_MUSIC_PSCALER 0x102 562 | #define BASS_ATTRIB_MUSIC_BPM 0x103 563 | #define BASS_ATTRIB_MUSIC_SPEED 0x104 564 | #define BASS_ATTRIB_MUSIC_VOL_GLOBAL 0x105 565 | #define BASS_ATTRIB_MUSIC_VOL_CHAN 0x200 // + channel # 566 | #define BASS_ATTRIB_MUSIC_VOL_INST 0x300 // + instrument # 567 | 568 | // BASS_ChannelGetData flags 569 | #define BASS_DATA_AVAILABLE 0 // query how much data is buffered 570 | #define BASS_DATA_FLOAT 0x40000000 // flag: return floating-point sample data 571 | #define BASS_DATA_FFT256 0x80000000 // 256 sample FFT 572 | #define BASS_DATA_FFT512 0x80000001 // 512 FFT 573 | #define BASS_DATA_FFT1024 0x80000002 // 1024 FFT 574 | #define BASS_DATA_FFT2048 0x80000003 // 2048 FFT 575 | #define BASS_DATA_FFT4096 0x80000004 // 4096 FFT 576 | #define BASS_DATA_FFT8192 0x80000005 // 8192 FFT 577 | #define BASS_DATA_FFT16384 0x80000006 // 16384 FFT 578 | #define BASS_DATA_FFT_INDIVIDUAL 0x10 // FFT flag: FFT for each channel, else all combined 579 | #define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window 580 | #define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias 581 | #define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data 582 | 583 | // BASS_ChannelGetTags types : what's returned 584 | #define BASS_TAG_ID3 0 // ID3v1 tags : TAG_ID3 structure 585 | #define BASS_TAG_ID3V2 1 // ID3v2 tags : variable length block 586 | #define BASS_TAG_OGG 2 // OGG comments : series of null-terminated UTF-8 strings 587 | #define BASS_TAG_HTTP 3 // HTTP headers : series of null-terminated ANSI strings 588 | #define BASS_TAG_ICY 4 // ICY headers : series of null-terminated ANSI strings 589 | #define BASS_TAG_META 5 // ICY metadata : ANSI string 590 | #define BASS_TAG_APE 6 // APE tags : series of null-terminated UTF-8 strings 591 | #define BASS_TAG_MP4 7 // MP4/iTunes metadata : series of null-terminated UTF-8 strings 592 | #define BASS_TAG_VENDOR 9 // OGG encoder : UTF-8 string 593 | #define BASS_TAG_LYRICS3 10 // Lyric3v2 tag : ASCII string 594 | #define BASS_TAG_CA_CODEC 11 // CoreAudio codec info : TAG_CA_CODEC structure 595 | #define BASS_TAG_MF 13 // Media Foundation tags : series of null-terminated UTF-8 strings 596 | #define BASS_TAG_WAVEFORMAT 14 // WAVE format : WAVEFORMATEEX structure 597 | #define BASS_TAG_RIFF_INFO 0x100 // RIFF "INFO" tags : series of null-terminated ANSI strings 598 | #define BASS_TAG_RIFF_BEXT 0x101 // RIFF/BWF "bext" tags : TAG_BEXT structure 599 | #define BASS_TAG_RIFF_CART 0x102 // RIFF/BWF "cart" tags : TAG_CART structure 600 | #define BASS_TAG_RIFF_DISP 0x103 // RIFF "DISP" text tag : ANSI string 601 | #define BASS_TAG_APE_BINARY 0x1000 // + index #, binary APE tag : TAG_APE_BINARY structure 602 | #define BASS_TAG_MUSIC_NAME 0x10000 // MOD music name : ANSI string 603 | #define BASS_TAG_MUSIC_MESSAGE 0x10001 // MOD message : ANSI string 604 | #define BASS_TAG_MUSIC_ORDERS 0x10002 // MOD order list : BYTE array of pattern numbers 605 | #define BASS_TAG_MUSIC_INST 0x10100 // + instrument #, MOD instrument name : ANSI string 606 | #define BASS_TAG_MUSIC_SAMPLE 0x10300 // + sample #, MOD sample name : ANSI string 607 | 608 | // ID3v1 tag structure 609 | typedef struct { 610 | char id[3]; 611 | char title[30]; 612 | char artist[30]; 613 | char album[30]; 614 | char year[4]; 615 | char comment[30]; 616 | BYTE genre; 617 | } TAG_ID3; 618 | 619 | // Binary APE tag structure 620 | typedef struct { 621 | const char *key; 622 | const void *data; 623 | DWORD length; 624 | } TAG_APE_BINARY; 625 | 626 | // BWF "bext" tag structure 627 | #ifdef _MSC_VER 628 | #pragma warning(push) 629 | #pragma warning(disable:4200) 630 | #endif 631 | #pragma pack(push,1) 632 | typedef struct { 633 | char Description[256]; // description 634 | char Originator[32]; // name of the originator 635 | char OriginatorReference[32]; // reference of the originator 636 | char OriginationDate[10]; // date of creation (yyyy-mm-dd) 637 | char OriginationTime[8]; // time of creation (hh-mm-ss) 638 | QWORD TimeReference; // first sample count since midnight (little-endian) 639 | WORD Version; // BWF version (little-endian) 640 | BYTE UMID[64]; // SMPTE UMID 641 | BYTE Reserved[190]; 642 | #if defined(__GNUC__) && __GNUC__<3 643 | char CodingHistory[0]; // history 644 | #elif 1 // change to 0 if compiler fails the following line 645 | char CodingHistory[]; // history 646 | #else 647 | char CodingHistory[1]; // history 648 | #endif 649 | } TAG_BEXT; 650 | #pragma pack(pop) 651 | 652 | // BWF "cart" tag structures 653 | typedef struct 654 | { 655 | DWORD dwUsage; // FOURCC timer usage ID 656 | DWORD dwValue; // timer value in samples from head 657 | } TAG_CART_TIMER; 658 | 659 | typedef struct 660 | { 661 | char Version[4]; // version of the data structure 662 | char Title[64]; // title of cart audio sequence 663 | char Artist[64]; // artist or creator name 664 | char CutID[64]; // cut number identification 665 | char ClientID[64]; // client identification 666 | char Category[64]; // category ID, PSA, NEWS, etc 667 | char Classification[64]; // classification or auxiliary key 668 | char OutCue[64]; // out cue text 669 | char StartDate[10]; // yyyy-mm-dd 670 | char StartTime[8]; // hh:mm:ss 671 | char EndDate[10]; // yyyy-mm-dd 672 | char EndTime[8]; // hh:mm:ss 673 | char ProducerAppID[64]; // name of vendor or application 674 | char ProducerAppVersion[64]; // version of producer application 675 | char UserDef[64]; // user defined text 676 | DWORD dwLevelReference; // sample value for 0 dB reference 677 | TAG_CART_TIMER PostTimer[8]; // 8 time markers after head 678 | char Reserved[276]; 679 | char URL[1024]; // uniform resource locator 680 | #if defined(__GNUC__) && __GNUC__<3 681 | char TagText[0]; // free form text for scripts or tags 682 | #elif 1 // change to 0 if compiler fails the following line 683 | char TagText[]; // free form text for scripts or tags 684 | #else 685 | char TagText[1]; // free form text for scripts or tags 686 | #endif 687 | } TAG_CART; 688 | #ifdef _MSC_VER 689 | #pragma warning(pop) 690 | #endif 691 | 692 | // CoreAudio codec info structure 693 | typedef struct { 694 | DWORD ftype; // file format 695 | DWORD atype; // audio format 696 | const char *name; // description 697 | } TAG_CA_CODEC; 698 | 699 | #ifndef _WAVEFORMATEX_ 700 | #define _WAVEFORMATEX_ 701 | #pragma pack(push,1) 702 | typedef struct tWAVEFORMATEX 703 | { 704 | WORD wFormatTag; 705 | WORD nChannels; 706 | DWORD nSamplesPerSec; 707 | DWORD nAvgBytesPerSec; 708 | WORD nBlockAlign; 709 | WORD wBitsPerSample; 710 | WORD cbSize; 711 | } WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX; 712 | typedef const WAVEFORMATEX *LPCWAVEFORMATEX; 713 | #pragma pack(pop) 714 | #endif 715 | 716 | // BASS_ChannelGetLength/GetPosition/SetPosition modes 717 | #define BASS_POS_BYTE 0 // byte position 718 | #define BASS_POS_MUSIC_ORDER 1 // order.row position, MAKELONG(order,row) 719 | #define BASS_POS_OGG 3 // OGG bitstream number 720 | #define BASS_POS_DECODE 0x10000000 // flag: get the decoding (not playing) position 721 | #define BASS_POS_DECODETO 0x20000000 // flag: decode to the position instead of seeking 722 | 723 | // BASS_RecordSetInput flags 724 | #define BASS_INPUT_OFF 0x10000 725 | #define BASS_INPUT_ON 0x20000 726 | 727 | #define BASS_INPUT_TYPE_MASK 0xff000000 728 | #define BASS_INPUT_TYPE_UNDEF 0x00000000 729 | #define BASS_INPUT_TYPE_DIGITAL 0x01000000 730 | #define BASS_INPUT_TYPE_LINE 0x02000000 731 | #define BASS_INPUT_TYPE_MIC 0x03000000 732 | #define BASS_INPUT_TYPE_SYNTH 0x04000000 733 | #define BASS_INPUT_TYPE_CD 0x05000000 734 | #define BASS_INPUT_TYPE_PHONE 0x06000000 735 | #define BASS_INPUT_TYPE_SPEAKER 0x07000000 736 | #define BASS_INPUT_TYPE_WAVE 0x08000000 737 | #define BASS_INPUT_TYPE_AUX 0x09000000 738 | #define BASS_INPUT_TYPE_ANALOG 0x0a000000 739 | 740 | // DX8 effect types, use with BASS_ChannelSetFX 741 | enum 742 | { 743 | BASS_FX_DX8_CHORUS, 744 | BASS_FX_DX8_COMPRESSOR, 745 | BASS_FX_DX8_DISTORTION, 746 | BASS_FX_DX8_ECHO, 747 | BASS_FX_DX8_FLANGER, 748 | BASS_FX_DX8_GARGLE, 749 | BASS_FX_DX8_I3DL2REVERB, 750 | BASS_FX_DX8_PARAMEQ, 751 | BASS_FX_DX8_REVERB 752 | }; 753 | 754 | typedef struct { 755 | float fWetDryMix; 756 | float fDepth; 757 | float fFeedback; 758 | float fFrequency; 759 | DWORD lWaveform; // 0=triangle, 1=sine 760 | float fDelay; 761 | DWORD lPhase; // BASS_DX8_PHASE_xxx 762 | } BASS_DX8_CHORUS; 763 | 764 | typedef struct { 765 | float fGain; 766 | float fAttack; 767 | float fRelease; 768 | float fThreshold; 769 | float fRatio; 770 | float fPredelay; 771 | } BASS_DX8_COMPRESSOR; 772 | 773 | typedef struct { 774 | float fGain; 775 | float fEdge; 776 | float fPostEQCenterFrequency; 777 | float fPostEQBandwidth; 778 | float fPreLowpassCutoff; 779 | } BASS_DX8_DISTORTION; 780 | 781 | typedef struct { 782 | float fWetDryMix; 783 | float fFeedback; 784 | float fLeftDelay; 785 | float fRightDelay; 786 | BOOL lPanDelay; 787 | } BASS_DX8_ECHO; 788 | 789 | typedef struct { 790 | float fWetDryMix; 791 | float fDepth; 792 | float fFeedback; 793 | float fFrequency; 794 | DWORD lWaveform; // 0=triangle, 1=sine 795 | float fDelay; 796 | DWORD lPhase; // BASS_DX8_PHASE_xxx 797 | } BASS_DX8_FLANGER; 798 | 799 | typedef struct { 800 | DWORD dwRateHz; // Rate of modulation in hz 801 | DWORD dwWaveShape; // 0=triangle, 1=square 802 | } BASS_DX8_GARGLE; 803 | 804 | typedef struct { 805 | int lRoom; // [-10000, 0] default: -1000 mB 806 | int lRoomHF; // [-10000, 0] default: 0 mB 807 | float flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 808 | float flDecayTime; // [0.1, 20.0] default: 1.49s 809 | float flDecayHFRatio; // [0.1, 2.0] default: 0.83 810 | int lReflections; // [-10000, 1000] default: -2602 mB 811 | float flReflectionsDelay; // [0.0, 0.3] default: 0.007 s 812 | int lReverb; // [-10000, 2000] default: 200 mB 813 | float flReverbDelay; // [0.0, 0.1] default: 0.011 s 814 | float flDiffusion; // [0.0, 100.0] default: 100.0 % 815 | float flDensity; // [0.0, 100.0] default: 100.0 % 816 | float flHFReference; // [20.0, 20000.0] default: 5000.0 Hz 817 | } BASS_DX8_I3DL2REVERB; 818 | 819 | typedef struct { 820 | float fCenter; 821 | float fBandwidth; 822 | float fGain; 823 | } BASS_DX8_PARAMEQ; 824 | 825 | typedef struct { 826 | float fInGain; // [-96.0,0.0] default: 0.0 dB 827 | float fReverbMix; // [-96.0,0.0] default: 0.0 db 828 | float fReverbTime; // [0.001,3000.0] default: 1000.0 ms 829 | float fHighFreqRTRatio; // [0.001,0.999] default: 0.001 830 | } BASS_DX8_REVERB; 831 | 832 | #define BASS_DX8_PHASE_NEG_180 0 833 | #define BASS_DX8_PHASE_NEG_90 1 834 | #define BASS_DX8_PHASE_ZERO 2 835 | #define BASS_DX8_PHASE_90 3 836 | #define BASS_DX8_PHASE_180 4 837 | 838 | typedef void (CALLBACK IOSNOTIFYPROC)(DWORD status); 839 | /* iOS notification callback function. 840 | status : The notification (BASS_IOSNOTIFY_xxx) */ 841 | 842 | #define BASS_IOSNOTIFY_INTERRUPT 1 // interruption started 843 | #define BASS_IOSNOTIFY_INTERRUPT_END 2 // interruption ended 844 | 845 | BOOL BASSDEF(BASS_SetConfig)(DWORD option, DWORD value); 846 | DWORD BASSDEF(BASS_GetConfig)(DWORD option); 847 | BOOL BASSDEF(BASS_SetConfigPtr)(DWORD option, const void *value); 848 | void *BASSDEF(BASS_GetConfigPtr)(DWORD option); 849 | DWORD BASSDEF(BASS_GetVersion)(); 850 | int BASSDEF(BASS_ErrorGetCode)(); 851 | BOOL BASSDEF(BASS_GetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info); 852 | #if defined(_WIN32) && !defined(_WIN32_WCE) 853 | BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, HWND win, const GUID *dsguid); 854 | #else 855 | BOOL BASSDEF(BASS_Init)(int device, DWORD freq, DWORD flags, void *win, void *dsguid); 856 | #endif 857 | BOOL BASSDEF(BASS_SetDevice)(DWORD device); 858 | DWORD BASSDEF(BASS_GetDevice)(); 859 | BOOL BASSDEF(BASS_Free)(); 860 | #if defined(_WIN32) && !defined(_WIN32_WCE) 861 | void *BASSDEF(BASS_GetDSoundObject)(DWORD object); 862 | #endif 863 | BOOL BASSDEF(BASS_GetInfo)(BASS_INFO *info); 864 | BOOL BASSDEF(BASS_Update)(DWORD length); 865 | float BASSDEF(BASS_GetCPU)(); 866 | BOOL BASSDEF(BASS_Start)(); 867 | BOOL BASSDEF(BASS_Stop)(); 868 | BOOL BASSDEF(BASS_Pause)(); 869 | BOOL BASSDEF(BASS_SetVolume)(float volume); 870 | float BASSDEF(BASS_GetVolume)(); 871 | 872 | HPLUGIN BASSDEF(BASS_PluginLoad)(const char *file, DWORD flags); 873 | BOOL BASSDEF(BASS_PluginFree)(HPLUGIN handle); 874 | const BASS_PLUGININFO *BASSDEF(BASS_PluginGetInfo)(HPLUGIN handle); 875 | 876 | BOOL BASSDEF(BASS_Set3DFactors)(float distf, float rollf, float doppf); 877 | BOOL BASSDEF(BASS_Get3DFactors)(float *distf, float *rollf, float *doppf); 878 | BOOL BASSDEF(BASS_Set3DPosition)(const BASS_3DVECTOR *pos, const BASS_3DVECTOR *vel, const BASS_3DVECTOR *front, const BASS_3DVECTOR *top); 879 | BOOL BASSDEF(BASS_Get3DPosition)(BASS_3DVECTOR *pos, BASS_3DVECTOR *vel, BASS_3DVECTOR *front, BASS_3DVECTOR *top); 880 | void BASSDEF(BASS_Apply3D)(); 881 | #if defined(_WIN32) && !defined(_WIN32_WCE) 882 | BOOL BASSDEF(BASS_SetEAXParameters)(int env, float vol, float decay, float damp); 883 | BOOL BASSDEF(BASS_GetEAXParameters)(DWORD *env, float *vol, float *decay, float *damp); 884 | #endif 885 | 886 | HMUSIC BASSDEF(BASS_MusicLoad)(BOOL mem, const void *file, QWORD offset, DWORD length, DWORD flags, DWORD freq); 887 | BOOL BASSDEF(BASS_MusicFree)(HMUSIC handle); 888 | 889 | HSAMPLE BASSDEF(BASS_SampleLoad)(BOOL mem, const void *file, QWORD offset, DWORD length, DWORD max, DWORD flags); 890 | HSAMPLE BASSDEF(BASS_SampleCreate)(DWORD length, DWORD freq, DWORD chans, DWORD max, DWORD flags); 891 | BOOL BASSDEF(BASS_SampleFree)(HSAMPLE handle); 892 | BOOL BASSDEF(BASS_SampleSetData)(HSAMPLE handle, const void *buffer); 893 | BOOL BASSDEF(BASS_SampleGetData)(HSAMPLE handle, void *buffer); 894 | BOOL BASSDEF(BASS_SampleGetInfo)(HSAMPLE handle, BASS_SAMPLE *info); 895 | BOOL BASSDEF(BASS_SampleSetInfo)(HSAMPLE handle, const BASS_SAMPLE *info); 896 | HCHANNEL BASSDEF(BASS_SampleGetChannel)(HSAMPLE handle, BOOL onlynew); 897 | DWORD BASSDEF(BASS_SampleGetChannels)(HSAMPLE handle, HCHANNEL *channels); 898 | BOOL BASSDEF(BASS_SampleStop)(HSAMPLE handle); 899 | 900 | HSTREAM BASSDEF(BASS_StreamCreate)(DWORD freq, DWORD chans, DWORD flags, STREAMPROC *proc, void *user); 901 | HSTREAM BASSDEF(BASS_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags); 902 | HSTREAM BASSDEF(BASS_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user); 903 | HSTREAM BASSDEF(BASS_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *proc, void *user); 904 | BOOL BASSDEF(BASS_StreamFree)(HSTREAM handle); 905 | QWORD BASSDEF(BASS_StreamGetFilePosition)(HSTREAM handle, DWORD mode); 906 | DWORD BASSDEF(BASS_StreamPutData)(HSTREAM handle, const void *buffer, DWORD length); 907 | DWORD BASSDEF(BASS_StreamPutFileData)(HSTREAM handle, const void *buffer, DWORD length); 908 | 909 | BOOL BASSDEF(BASS_RecordGetDeviceInfo)(DWORD device, BASS_DEVICEINFO *info); 910 | BOOL BASSDEF(BASS_RecordInit)(int device); 911 | BOOL BASSDEF(BASS_RecordSetDevice)(DWORD device); 912 | DWORD BASSDEF(BASS_RecordGetDevice)(); 913 | BOOL BASSDEF(BASS_RecordFree)(); 914 | BOOL BASSDEF(BASS_RecordGetInfo)(BASS_RECORDINFO *info); 915 | const char *BASSDEF(BASS_RecordGetInputName)(int input); 916 | BOOL BASSDEF(BASS_RecordSetInput)(int input, DWORD flags, float volume); 917 | DWORD BASSDEF(BASS_RecordGetInput)(int input, float *volume); 918 | HRECORD BASSDEF(BASS_RecordStart)(DWORD freq, DWORD chans, DWORD flags, RECORDPROC *proc, void *user); 919 | 920 | double BASSDEF(BASS_ChannelBytes2Seconds)(DWORD handle, QWORD pos); 921 | QWORD BASSDEF(BASS_ChannelSeconds2Bytes)(DWORD handle, double pos); 922 | DWORD BASSDEF(BASS_ChannelGetDevice)(DWORD handle); 923 | BOOL BASSDEF(BASS_ChannelSetDevice)(DWORD handle, DWORD device); 924 | DWORD BASSDEF(BASS_ChannelIsActive)(DWORD handle); 925 | BOOL BASSDEF(BASS_ChannelGetInfo)(DWORD handle, BASS_CHANNELINFO *info); 926 | const char *BASSDEF(BASS_ChannelGetTags)(DWORD handle, DWORD tags); 927 | DWORD BASSDEF(BASS_ChannelFlags)(DWORD handle, DWORD flags, DWORD mask); 928 | BOOL BASSDEF(BASS_ChannelUpdate)(DWORD handle, DWORD length); 929 | BOOL BASSDEF(BASS_ChannelLock)(DWORD handle, BOOL lock); 930 | BOOL BASSDEF(BASS_ChannelPlay)(DWORD handle, BOOL restart); 931 | BOOL BASSDEF(BASS_ChannelStop)(DWORD handle); 932 | BOOL BASSDEF(BASS_ChannelPause)(DWORD handle); 933 | BOOL BASSDEF(BASS_ChannelSetAttribute)(DWORD handle, DWORD attrib, float value); 934 | BOOL BASSDEF(BASS_ChannelGetAttribute)(DWORD handle, DWORD attrib, float *value); 935 | BOOL BASSDEF(BASS_ChannelSlideAttribute)(DWORD handle, DWORD attrib, float value, DWORD time); 936 | BOOL BASSDEF(BASS_ChannelIsSliding)(DWORD handle, DWORD attrib); 937 | BOOL BASSDEF(BASS_ChannelSet3DAttributes)(DWORD handle, int mode, float min, float max, int iangle, int oangle, float outvol); 938 | BOOL BASSDEF(BASS_ChannelGet3DAttributes)(DWORD handle, DWORD *mode, float *min, float *max, DWORD *iangle, DWORD *oangle, float *outvol); 939 | BOOL BASSDEF(BASS_ChannelSet3DPosition)(DWORD handle, const BASS_3DVECTOR *pos, const BASS_3DVECTOR *orient, const BASS_3DVECTOR *vel); 940 | BOOL BASSDEF(BASS_ChannelGet3DPosition)(DWORD handle, BASS_3DVECTOR *pos, BASS_3DVECTOR *orient, BASS_3DVECTOR *vel); 941 | QWORD BASSDEF(BASS_ChannelGetLength)(DWORD handle, DWORD mode); 942 | BOOL BASSDEF(BASS_ChannelSetPosition)(DWORD handle, QWORD pos, DWORD mode); 943 | QWORD BASSDEF(BASS_ChannelGetPosition)(DWORD handle, DWORD mode); 944 | DWORD BASSDEF(BASS_ChannelGetLevel)(DWORD handle); 945 | DWORD BASSDEF(BASS_ChannelGetData)(DWORD handle, void *buffer, DWORD length); 946 | HSYNC BASSDEF(BASS_ChannelSetSync)(DWORD handle, DWORD type, QWORD param, SYNCPROC *proc, void *user); 947 | BOOL BASSDEF(BASS_ChannelRemoveSync)(DWORD handle, HSYNC sync); 948 | HDSP BASSDEF(BASS_ChannelSetDSP)(DWORD handle, DSPPROC *proc, void *user, int priority); 949 | BOOL BASSDEF(BASS_ChannelRemoveDSP)(DWORD handle, HDSP dsp); 950 | BOOL BASSDEF(BASS_ChannelSetLink)(DWORD handle, DWORD chan); 951 | BOOL BASSDEF(BASS_ChannelRemoveLink)(DWORD handle, DWORD chan); 952 | HFX BASSDEF(BASS_ChannelSetFX)(DWORD handle, DWORD type, int priority); 953 | BOOL BASSDEF(BASS_ChannelRemoveFX)(DWORD handle, HFX fx); 954 | 955 | BOOL BASSDEF(BASS_FXSetParameters)(HFX handle, const void *params); 956 | BOOL BASSDEF(BASS_FXGetParameters)(HFX handle, void *params); 957 | BOOL BASSDEF(BASS_FXReset)(HFX handle); 958 | 959 | #ifdef __cplusplus 960 | } 961 | 962 | #ifdef _WIN32 963 | /* 964 | static inline HPLUGIN BASS_PluginLoad(const WCHAR *file, DWORD flags) 965 | { 966 | return BASS_PluginLoad((const char*)file, flags|BASS_UNICODE); 967 | } 968 | 969 | static inline HMUSIC BASS_MusicLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD flags, DWORD freq) 970 | { 971 | return BASS_MusicLoad(mem, (const void*)file, offset, length, flags|BASS_UNICODE, freq); 972 | } 973 | 974 | static inline HSAMPLE BASS_SampleLoad(BOOL mem, const WCHAR *file, QWORD offset, DWORD length, DWORD max, DWORD flags) 975 | { 976 | return BASS_SampleLoad(mem, (const void*)file, offset, length, max, flags|BASS_UNICODE); 977 | } 978 | 979 | static inline HSTREAM BASS_StreamCreateFile(BOOL mem, const WCHAR *file, QWORD offset, QWORD length, DWORD flags) 980 | { 981 | return BASS_StreamCreateFile(mem, (const void*)file, offset, length, flags|BASS_UNICODE); 982 | } 983 | 984 | static inline HSTREAM BASS_StreamCreateURL(const WCHAR *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user) 985 | { 986 | return BASS_StreamCreateURL((const char*)url, offset, flags|BASS_UNICODE, proc, user); 987 | } 988 | */ 989 | #endif 990 | #endif 991 | 992 | #endif 993 | -------------------------------------------------------------------------------- /Sources/bass.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/bass.lib -------------------------------------------------------------------------------- /Sources/bass_aac.h: -------------------------------------------------------------------------------- 1 | #ifndef BASSAAC_H 2 | #define BASSAAC_H 3 | 4 | #include "bass.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #ifndef BASSAACDEF 11 | #define BASSAACDEF(f) WINAPI f 12 | #endif 13 | 14 | // Additional BASS_SetConfig options 15 | #define BASS_CONFIG_MP4_VIDEO 0x10700 // play the audio from MP4 videos 16 | #define BASS_CONFIG_AAC_MP4 0x10701 // support MP4 in BASS_AAC_StreamCreateXXX functions (no need for BASS_MP4_StreamCreateXXX) 17 | 18 | // Additional tags available from BASS_StreamGetTags (for MP4 files) 19 | #define BASS_TAG_MP4 7 // MP4/iTunes metadata 20 | 21 | #define BASS_AAC_STEREO 0x400000 // downmatrix to stereo 22 | 23 | // BASS_CHANNELINFO type 24 | #define BASS_CTYPE_STREAM_AAC 0x10b00 // AAC 25 | #define BASS_CTYPE_STREAM_MP4 0x10b01 // MP4 26 | 27 | 28 | HSTREAM BASSAACDEF(BASS_AAC_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags); 29 | HSTREAM BASSAACDEF(BASS_AAC_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user); 30 | HSTREAM BASSAACDEF(BASS_AAC_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *procs, void *user); 31 | HSTREAM BASSAACDEF(BASS_MP4_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags); 32 | HSTREAM BASSAACDEF(BASS_MP4_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *procs, void *user); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /Sources/bass_aac.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/bass_aac.lib -------------------------------------------------------------------------------- /Sources/bass_alac.h: -------------------------------------------------------------------------------- 1 | #ifndef BASSALAC_H 2 | #define BASSALAC_H 3 | 4 | #include "bass.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #ifndef BASSALACDEF 11 | #define BASSALACDEF(f) WINAPI f 12 | #endif 13 | 14 | #define BASS_TAG_MP4 7 // iTunes/MP4 metadata 15 | 16 | // BASS_CHANNELINFO type 17 | #define BASS_CTYPE_STREAM_ALAC 0x10e00 18 | 19 | 20 | HSTREAM BASSALACDEF(BASS_ALAC_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags); 21 | HSTREAM BASSALACDEF(BASS_ALAC_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user); 22 | HSTREAM BASSALACDEF(BASS_ALAC_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *procs, void *user); 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /Sources/bass_alac.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/bass_alac.lib -------------------------------------------------------------------------------- /Sources/bass_ape.h: -------------------------------------------------------------------------------- 1 | #ifndef BASSAPE_H 2 | #define BASSAPE_H 3 | 4 | #include "bass.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #ifndef BASSAPEDEF 11 | #define BASSAPEDEF(f) WINAPI f 12 | #endif 13 | 14 | // BASS_CHANNELINFO type 15 | #define BASS_CTYPE_STREAM_APE 0x10700 16 | 17 | 18 | HSTREAM BASSAPEDEF(BASS_APE_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags); 19 | HSTREAM BASSAPEDEF(BASS_APE_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *procs, void *user); 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /Sources/bass_ape.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/bass_ape.lib -------------------------------------------------------------------------------- /Sources/bass_fx.h: -------------------------------------------------------------------------------- 1 | /*=========================================================================== 2 | BASS_FX 2.4 - Copyright (c) 2002-2013 (: JOBnik! :) [Arthur Aminov, ISRAEL] 3 | [http://www.jobnik.org] 4 | 5 | bugs/suggestions/questions: 6 | forum : http://www.un4seen.com/forum/?board=1 7 | http://www.jobnik.org/smforum 8 | e-mail : bass_fx@jobnik.org 9 | -------------------------------------------------- 10 | 11 | NOTE: This header will work only with BASS_FX version 2.4.10 12 | Check www.un4seen.com or www.jobnik.org for any later versions. 13 | 14 | * Requires BASS 2.4 (available at http://www.un4seen.com) 15 | ===========================================================================*/ 16 | 17 | #ifndef BASS_FX_H 18 | #define BASS_FX_H 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #ifndef BASS_FXDEF 25 | #define BASS_FXDEF(f) WINAPI f 26 | #endif 27 | 28 | // Tempo / Reverse / BPM / Beat flag 29 | #define BASS_FX_FREESOURCE 0x10000 // Free the source handle as well? 30 | 31 | // BASS_FX Version 32 | DWORD BASS_FXDEF(BASS_FX_GetVersion)(); 33 | 34 | /*=========================================================================== 35 | DSP (Digital Signal Processing) 36 | ===========================================================================*/ 37 | 38 | /* 39 | Multi-channel order of each channel is as follows: 40 | 3 channels left-front, right-front, center. 41 | 4 channels left-front, right-front, left-rear/side, right-rear/side. 42 | 5 channels left-front, right-front, center, left-rear/side, right-rear/side. 43 | 6 channels (5.1) left-front, right-front, center, LFE, left-rear/side, right-rear/side. 44 | 8 channels (7.1) left-front, right-front, center, LFE, left-rear/side, right-rear/side, left-rear center, right-rear center. 45 | */ 46 | 47 | // DSP channels flags 48 | #define BASS_BFX_CHANALL -1 // all channels at once (as by default) 49 | #define BASS_BFX_CHANNONE 0 // disable an effect for all channels 50 | #define BASS_BFX_CHAN1 1 // left-front channel 51 | #define BASS_BFX_CHAN2 2 // right-front channel 52 | #define BASS_BFX_CHAN3 4 // see above info 53 | #define BASS_BFX_CHAN4 8 // see above info 54 | #define BASS_BFX_CHAN5 16 // see above info 55 | #define BASS_BFX_CHAN6 32 // see above info 56 | #define BASS_BFX_CHAN7 64 // see above info 57 | #define BASS_BFX_CHAN8 128 // see above info 58 | 59 | // if you have more than 8 channels (7.1), use this macro 60 | #define BASS_BFX_CHANNEL_N(n) (1<<((n)-1)) 61 | 62 | // DSP effects 63 | enum { 64 | BASS_FX_BFX_ROTATE = 0x10000, // A channels volume ping-pong / multi channel 65 | BASS_FX_BFX_ECHO, // Echo / 2 channels max (deprecated) 66 | BASS_FX_BFX_FLANGER, // Flanger / multi channel (deprecated) 67 | BASS_FX_BFX_VOLUME, // Volume / multi channel 68 | BASS_FX_BFX_PEAKEQ, // Peaking Equalizer / multi channel 69 | BASS_FX_BFX_REVERB, // Reverb / 2 channels max (deprecated) 70 | BASS_FX_BFX_LPF, // Low Pass Filter 24dB / multi channel (deprecated) 71 | BASS_FX_BFX_MIX, // Swap, remap and mix channels / multi channel 72 | BASS_FX_BFX_DAMP, // Dynamic Amplification / multi channel 73 | BASS_FX_BFX_AUTOWAH, // Auto Wah / multi channel 74 | BASS_FX_BFX_ECHO2, // Echo 2 / multi channel (deprecated) 75 | BASS_FX_BFX_PHASER, // Phaser / multi channel 76 | BASS_FX_BFX_ECHO3, // Echo 3 / multi channel (deprecated) 77 | BASS_FX_BFX_CHORUS, // Chorus/Flanger / multi channel 78 | BASS_FX_BFX_APF, // All Pass Filter / multi channel (deprecated) 79 | BASS_FX_BFX_COMPRESSOR, // Compressor / multi channel (deprecated) 80 | BASS_FX_BFX_DISTORTION, // Distortion / multi channel 81 | BASS_FX_BFX_COMPRESSOR2, // Compressor 2 / multi channel 82 | BASS_FX_BFX_VOLUME_ENV, // Volume envelope / multi channel 83 | BASS_FX_BFX_BQF, // BiQuad filters / multi channel 84 | BASS_FX_BFX_ECHO4 // Echo/Reverb / multi channel 85 | }; 86 | 87 | /* 88 | Deprecated effects in 2.4.10 version: 89 | ------------------------------------ 90 | BASS_FX_BFX_ECHO -> use BASS_FX_BFX_ECHO4 91 | BASS_FX_BFX_ECHO2 -> use BASS_FX_BFX_ECHO4 92 | BASS_FX_BFX_ECHO3 -> use BASS_FX_BFX_ECHO4 93 | BASS_FX_BFX_REVERB -> use BASS_FX_BFX_ECHO4 with fFeedback enabled 94 | BASS_FX_BFX_FLANGER -> use BASS_FX_BFX_CHORUS 95 | BASS_FX_BFX_COMPRESSOR -> use BASS_FX_BFX_COMPRESSOR2 96 | BASS_FX_BFX_APF -> use BASS_FX_BFX_BQF with BASS_BFX_BQF_ALLPASS filter 97 | BASS_FX_BFX_LPF -> use 2x BASS_FX_BFX_BQF with BASS_BFX_BQF_LOWPASS filter and appropriate fQ values 98 | */ 99 | 100 | // Rotate 101 | typedef struct { 102 | float fRate; // rotation rate/speed in Hz (A negative rate can be used for reverse direction) 103 | int lChannel; // BASS_BFX_CHANxxx flag/s (supported only even number of channels) 104 | } BASS_BFX_ROTATE; 105 | 106 | // Echo (deprecated) 107 | typedef struct { 108 | float fLevel; // [0....1....n] linear 109 | int lDelay; // [1200..30000] 110 | } BASS_BFX_ECHO; 111 | 112 | // Flanger (deprecated) 113 | typedef struct { 114 | float fWetDry; // [0....1....n] linear 115 | float fSpeed; // [0......0.09] 116 | int lChannel; // BASS_BFX_CHANxxx flag/s 117 | } BASS_BFX_FLANGER; 118 | 119 | // Volume 120 | typedef struct { 121 | int lChannel; // BASS_BFX_CHANxxx flag/s or 0 for global volume control 122 | float fVolume; // [0....1....n] linear 123 | } BASS_BFX_VOLUME; 124 | 125 | // Peaking Equalizer 126 | typedef struct { 127 | int lBand; // [0...............n] more bands means more memory & cpu usage 128 | float fBandwidth; // [0.1...........<10] in octaves - fQ is not in use (Bandwidth has a priority over fQ) 129 | float fQ; // [0...............1] the EE kinda definition (linear) (if Bandwidth is not in use) 130 | float fCenter; // [1Hz.. minElasticStep) 73 | elasticForce = peakSlideSpeed[i] * elasticCoefficient;//计算弹力 74 | 75 | peakSlideSpeed[i] = (fftBarPeakValue[i] - fftBarValue[i]) * forceD - elasticForce; //计算撞击+弹力产生的加速度 76 | fftBarPeakValue[i] = fftBarValue[i];//此次存在误差,下落过程产生的动量被忽略,导致动量损失 77 | } else { 78 | //下落 79 | if (fftBarPeakValue[i] > realityDown) //下落的情况,当前值是否比每次下落量还小 80 | { 81 | fftBarPeakValue[i] -= realityDown; //如果不是,可以下落(不会小于0) 82 | } else { 83 | fftBarPeakValue[i] = 0; //下落后将变为负值,不再下落(赋值0) 84 | } 85 | 86 | //下落过程加速 87 | if (peakSlideSpeed[i] + acc <= maxSpeed) 88 | peakSlideSpeed[i] += acc;//加速下落 89 | else 90 | peakSlideSpeed[i] = maxSpeed;//达到最大速度 91 | } 92 | } 93 | } 94 | 95 | //频谱条 限值 96 | void FFTDisplay::cutValue() 97 | { 98 | for (int i = 0; i < 29; i++) 99 | { 100 | //限制条取值范围 101 | if (fftBarValue[i] > 1) 102 | fftBarValue[i] = 1; 103 | else if (fftBarValue[i] < 0) 104 | fftBarValue[i] = 0; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Sources/fftdisplay.h: -------------------------------------------------------------------------------- 1 | #ifndef FFTDISPLAY_H 2 | #define FFTDISPLAY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class FFTDisplay : public QGroupBox 11 | { 12 | Q_OBJECT 13 | public: 14 | explicit FFTDisplay(QWidget *parent = 0); 15 | double fftBarValue[29];//存放频谱分析条的值 16 | void peakSlideDown();//下滑 17 | void cutValue();//限制最大最小值 18 | 19 | double acc, maxSpeed;//重力加速度,最大速度 20 | double speed;//基准速度。加速度为1时,按此速度下落/上升 21 | double forceD;//抛力系数 22 | double elasticCoefficient;//弹力系数 23 | double minElasticStep;//弹力禁用阀值 24 | 25 | signals: 26 | 27 | public slots: 28 | 29 | protected: 30 | void paintEvent(QPaintEvent *event); 31 | 32 | private: 33 | //数值除了绘图坐标,均为比值。 34 | int sx, sy, margin, width, height;//绘图相关,起始x,起始y,间距,宽度,高度 35 | double fftBarPeakValue[29];//存放频谱分析顶峰的值 36 | double peakSlideSpeed[29];//下滑速度 37 | }; 38 | 39 | #endif // FFTDISPLAY_H 40 | -------------------------------------------------------------------------------- /Sources/image/OSD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/image/OSD.png -------------------------------------------------------------------------------- /Sources/image/ShadowPlayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/image/ShadowPlayer.png -------------------------------------------------------------------------------- /Sources/image/Skin1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/image/Skin1.jpg -------------------------------------------------------------------------------- /Sources/lrcbar.cpp: -------------------------------------------------------------------------------- 1 | #include "lrcbar.h" 2 | #include "ui_lrcbar.h" 3 | 4 | LrcBar::LrcBar(Lyrics *lrc, Player *plr, QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::LrcBar) 7 | { 8 | ui->setupUi(this); 9 | lyrics = lrc;//绝对不可以delete,会发生核爆…… 10 | player = plr;//绝对不可以delete 11 | mouseEnter = false; 12 | shadowMode = 0;//0.右下双阴影 1.描边 13 | 14 | font.setFamily("微软雅黑"); 15 | font.setPointSize(30); 16 | font.setStyleStrategy(QFont::PreferAntialias);//是否抗锯齿取决于字体 17 | 18 | //歌词渐变色彩 19 | linearGradient.setColorAt(0, QColor(0, 128, 0)); 20 | linearGradient.setColorAt(1, QColor(0, 255, 0)); 21 | //二层歌词渐变色彩 22 | maskLinearGradient.setColorAt(0, QColor(255, 255, 0)); 23 | maskLinearGradient.setColorAt(0.5, QColor(255, 128, 0)); 24 | maskLinearGradient.setColorAt(01, QColor(255, 255, 0)); 25 | //计算渐变起点和终点 26 | QFontMetrics fm(font); 27 | linearGradient.setStart(0, this->height()/2 - fm.height()/2);//从字体顶部渐变到字体底部 28 | linearGradient.setFinalStop(0, this->height()/2 + fm.height()/2); 29 | maskLinearGradient.setStart(0, this->height()/2 - fm.height()/2); 30 | maskLinearGradient.setFinalStop(0, this->height()/2 + fm.height()/2); 31 | 32 | timer = new QTimer(); 33 | connect(timer, SIGNAL(timeout()), this, SLOT(UpdateTime())); 34 | timer->start(30); 35 | 36 | //设置起始位置 37 | this->setGeometry((QApplication::desktop()->screenGeometry().width() - this->width()) / 2, QApplication::desktop()->screenGeometry().height() - 130, this->width(), this->height()); 38 | this->setFixedSize(this->width(), this->height()); 39 | 40 | this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool); 41 | this->setAttribute(Qt::WA_TranslucentBackground);//背景透明 42 | } 43 | 44 | void LrcBar::UpdateTime() 45 | { 46 | if (this->isVisible()) 47 | { 48 | lyrics->updateTime(player->getCurTimeMS(), player->getTotalTimeMS());; 49 | this->repaint(); 50 | } 51 | } 52 | 53 | LrcBar::~LrcBar() 54 | { 55 | delete ui; 56 | } 57 | 58 | //窗口拖动相关 59 | void LrcBar::mousePressEvent(QMouseEvent *event) 60 | { 61 | if (event->button() == Qt::LeftButton) 62 | { 63 | pos = event->globalPos() - frameGeometry().topLeft(); 64 | //也可以使用pos = event->pos(); 65 | clickOnFrame = true; 66 | event->accept(); 67 | } 68 | } 69 | 70 | void LrcBar::mouseReleaseEvent(QMouseEvent *) 71 | { 72 | clickOnFrame = false; 73 | } 74 | 75 | void LrcBar::mouseMoveEvent(QMouseEvent *event) 76 | { 77 | if (event->buttons() & Qt::LeftButton && clickOnFrame) 78 | { 79 | move(event->globalPos() - pos); 80 | event->accept(); 81 | } 82 | } 83 | 84 | void LrcBar::paintEvent(QPaintEvent *) 85 | { 86 | QPainter painter(this); 87 | if (mouseEnter) 88 | { 89 | painter.setBrush(QBrush(QColor(255, 255, 255, 120))); 90 | painter.setPen(Qt::NoPen); 91 | painter.drawRect(0, 0, width(), height()); 92 | } 93 | 94 | //以下内容为歌词文本绘制 95 | QString curLrc = lyrics->getLrcString(0); 96 | if (curLrc.isEmpty()) 97 | { 98 | if (lyrics->isLrcEmpty()) 99 | { 100 | curLrc = "Shadow Player"; 101 | } else { 102 | curLrc = "(间奏……)"; 103 | } 104 | } 105 | painter.setFont(font); 106 | painter.setRenderHint(QPainter::Antialiasing, true);//绘图抗锯齿 107 | 108 | QFontMetrics fm(font);//字体参数,用于计算 109 | int lrcWidth = fm.width(curLrc);//歌词文本宽度 110 | double curTimePos = lyrics->getTimePos(player->getCurTimeMS());//当前时间点 111 | int maskWidth = lrcWidth * curTimePos;//计算出当前时间变色文本的宽度 112 | 113 | //原来的代码偶尔会有1像素点的误差,已删除,改用自己计算的中间位置 114 | //原先的实现方式是Qt::AlignCenter绘制固定文本,然后动态变色文本用自己计算的位置 115 | //某些特殊长度时,会出现1px的偏移 116 | 117 | if (fm.width(curLrc) < this->width()) 118 | { 119 | //如果文本宽度没有超出窗口宽度 120 | int startXPos = this->width()/2 - lrcWidth/2;//歌词起始点(绘制在中央) 121 | 122 | //绘制底层文字作为阴影 123 | switch (shadowMode) { 124 | case 0: 125 | //右下双阴影 126 | painter.setPen(QColor(0, 0, 0, 80)); 127 | painter.drawText(startXPos + 2, 2, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 128 | painter.setPen(QColor(0, 0, 0, 180)); 129 | painter.drawText(startXPos + 1, 1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 130 | break; 131 | case 1: 132 | //描边 133 | painter.setPen(QColor(0, 0, 0, 140)); 134 | painter.drawText(startXPos + 1, 1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 135 | painter.drawText(startXPos + 1, 0, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 136 | painter.drawText(startXPos + 1, -1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 137 | painter.drawText(startXPos, 1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 138 | painter.drawText(startXPos, -1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 139 | painter.drawText(startXPos - 1, 1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 140 | painter.drawText(startXPos - 1, 0, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 141 | painter.drawText(startXPos - 1, -1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 142 | break; 143 | default: 144 | break; 145 | } 146 | 147 | //绘制歌词文本 148 | painter.setPen(QPen(linearGradient, 0)); 149 | painter.drawText(startXPos, 0, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 150 | 151 | //绘制变色文本 152 | painter.setPen(QPen(maskLinearGradient, 0)); 153 | painter.drawText(startXPos, 0, maskWidth, this->height(), Qt::AlignVCenter, curLrc); 154 | } else { 155 | //如果文本宽度超出窗口宽度 156 | int rollXPos; 157 | 158 | //千千静听歌词滚动模式 159 | if (maskWidth < this->width() / 2) 160 | { 161 | //未达到中间宽度 162 | rollXPos = 0;//不移动 163 | } else if (lrcWidth - maskWidth < this->width() / 2) 164 | { 165 | //到达结尾部分 166 | rollXPos = this->width() - lrcWidth;//移动到最顶,不移动 167 | } else { 168 | //中间部分 169 | rollXPos = 0 - (maskWidth - this->width() / 2); 170 | } 171 | 172 | //这是原来的算法 173 | // int rollXPos = (this->width() - fm.width(curLrc)) * curTimePos; 174 | 175 | switch (shadowMode) { 176 | case 0: 177 | //右下双阴影 178 | painter.setPen(QColor(0, 0, 0, 80)); 179 | painter.drawText(rollXPos + 2, 2, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 180 | painter.setPen(QColor(0, 0, 0, 180)); 181 | painter.drawText(rollXPos + 1, 1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 182 | break; 183 | case 1: 184 | //描边 185 | painter.setPen(QColor(0, 0, 0, 140)); 186 | painter.drawText(rollXPos + 1, 1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 187 | painter.drawText(rollXPos - 1, -1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 188 | painter.drawText(rollXPos + 1, -1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 189 | painter.drawText(rollXPos - 1, 1, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 190 | break; 191 | default: 192 | break; 193 | } 194 | 195 | //绘制歌词文本 196 | painter.setPen(QPen(linearGradient, 0)); 197 | painter.drawText(rollXPos, 0, lrcWidth, this->height(), Qt::AlignVCenter, curLrc); 198 | 199 | //绘制变色文本 200 | painter.setPen(QPen(maskLinearGradient, 0)); 201 | painter.drawText(rollXPos, 0, maskWidth, this->height(), Qt::AlignVCenter, curLrc); 202 | 203 | } 204 | } 205 | 206 | void LrcBar::enterEvent(QEvent *) 207 | { 208 | mouseEnter = true; 209 | this->repaint(); 210 | } 211 | 212 | void LrcBar::leaveEvent(QEvent *) 213 | { 214 | mouseEnter = false; 215 | this->repaint(); 216 | } 217 | 218 | void LrcBar::contextMenuEvent(QContextMenuEvent *event) 219 | { 220 | QMenu menu; 221 | menu.addAction("设置字体", this, SLOT(settingFont())); 222 | menu.addAction("阴影模式(千千静听)", this, SLOT(enableShadow())); 223 | menu.addAction("描边模式(酷狗音乐)", this, SLOT(enableStroke())); 224 | menu.exec(event->globalPos()); 225 | } 226 | 227 | //更改字体 228 | void LrcBar::settingFont() 229 | { 230 | bool ok; 231 | QFont newFont = QFontDialog::getFont(&ok, font, this, "选择字体"); 232 | if(ok) 233 | { 234 | font = newFont; 235 | } 236 | //计算渐变起点和终点 237 | QFontMetrics fm(font); 238 | linearGradient.setStart(0, this->height()/2 - fm.height()/2);//从字体顶部渐变到字体底部 239 | linearGradient.setFinalStop(0, this->height()/2 + fm.height()/2); 240 | maskLinearGradient.setStart(0, this->height()/2 - fm.height()/2); 241 | maskLinearGradient.setFinalStop(0, this->height()/2 + fm.height()/2); 242 | } 243 | 244 | void LrcBar::enableShadow() 245 | { 246 | //阴影模式 247 | shadowMode = 0; 248 | } 249 | 250 | void LrcBar::enableStroke() 251 | { 252 | //描边模式 253 | shadowMode = 1; 254 | } 255 | -------------------------------------------------------------------------------- /Sources/lrcbar.h: -------------------------------------------------------------------------------- 1 | #ifndef LRCBAR_H 2 | #define LRCBAR_H 3 | 4 | #include 5 | #include "lyrics.h" 6 | #include "player.h" 7 | #include 8 | #include 9 | #include 10 | 11 | namespace Ui { 12 | class LrcBar; 13 | } 14 | 15 | class LrcBar : public QWidget 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | explicit LrcBar(Lyrics *lrc, Player *plr, QWidget *parent); 21 | ~LrcBar(); 22 | 23 | private slots: 24 | void UpdateTime(); 25 | void settingFont(); 26 | void enableShadow(); 27 | void enableStroke(); 28 | 29 | private: 30 | Ui::LrcBar *ui; 31 | QTimer *timer; 32 | Lyrics *lyrics; 33 | Player *player; 34 | QPoint pos;//用于窗口拖动,存储鼠标坐标 35 | bool clickOnFrame; 36 | bool mouseEnter; 37 | QLinearGradient linearGradient; 38 | QLinearGradient maskLinearGradient; 39 | QFont font;//字体 40 | int shadowMode;//阴影模式' 41 | 42 | protected: 43 | void paintEvent(QPaintEvent *); 44 | void mousePressEvent(QMouseEvent *event);//窗体拖动相关 45 | void mouseMoveEvent(QMouseEvent *event); 46 | void mouseReleaseEvent(QMouseEvent *); 47 | void enterEvent(QEvent *); 48 | void leaveEvent(QEvent *); 49 | void contextMenuEvent(QContextMenuEvent *event);//右键菜单 50 | }; 51 | 52 | #endif // LRCBAR_H 53 | -------------------------------------------------------------------------------- /Sources/lrcbar.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | LrcBar 4 | 5 | 6 | Qt::NonModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 1000 13 | 88 14 | 15 | 16 | 17 | 歌词 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Sources/lyrics.cpp: -------------------------------------------------------------------------------- 1 | #include "lyrics.h" 2 | 3 | Lyrics::Lyrics() 4 | { 5 | curLrcTime = 0; 6 | nextLrcTime = 0; 7 | } 8 | 9 | //歌词解析,传入参数:音频文件名 10 | bool Lyrics::resolve(QString fileName, bool isLrc) 11 | { 12 | //解决乱码:http://blog.csdn.net/locky1218/article/details/10568261 13 | //Lrc文件读入QMap:http://www.cnblogs.com/tornadomeet/archive/2012/09/23/2699077.html 14 | //解析方式和我原想的方式非常接近…… 15 | curLrcTime = 0; 16 | nextLrcTime = 0; 17 | lrcMap.clear(); 18 | timeList.clear(); 19 | if (fileName.isEmpty()) 20 | return false;//文件名不正确 21 | 22 | QFileInfo fileInfo(fileName); 23 | QString lrcFileName; 24 | 25 | if (!isLrc) 26 | { 27 | lrcFileName = fileInfo.path() + "/" + fileInfo.completeBaseName() + ".lrc";//打开同名lrc 28 | } else { 29 | lrcFileName = fileName; 30 | } 31 | 32 | QFile file(lrcFileName); 33 | 34 | if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) { 35 | return false;//打开lrc文件失败(歌词不存在,歌词文件被独占) 36 | } 37 | 38 | QTextStream textIn(&file);//使用QTextStream读取文本,即可解决ANSI编码问题 39 | QString allText = QString(textIn.readAll());//全部读取 40 | file.close(); 41 | QStringList lines = allText.split("\n");//按行分割文本; 42 | 43 | QRegExp rx("\\[\\d{2}:\\d{2}\\.\\d{2}\\]");//正则表达式匹配歌词时间(不支持[xxx:xx.xx]以上 44 | 45 | foreach(QString oneline, lines) 46 | { 47 | QString text = oneline; 48 | 49 | text.replace(rx, "");//删除正则表达式匹配部分(时间标签),此时text内容为歌词文本 50 | int pos = rx.indexIn(oneline, 0);//返回匹配位置,-1表示匹配失败 51 | 52 | //分段读取,写入Map 53 | while (pos != -1) 54 | { 55 | QString cap = rx.cap(0);//返回第0个表达式匹配的内容 56 | QRegExp rx2; 57 | rx2.setPattern("\\d{2}(?=:)"); 58 | rx2.indexIn(cap); 59 | int minute = rx2.cap(0).toInt(); 60 | rx2.setPattern("\\d{2}(?=\\.)"); 61 | rx2.indexIn(cap); 62 | int second = rx2.cap(0).toInt(); 63 | rx2.setPattern("\\d{2}(?=\\])"); 64 | rx2.indexIn(cap); 65 | int millisecond = rx2.cap(0).toInt(); 66 | int totalTime = minute * 60000 + second * 1000 + millisecond * 10; 67 | lrcMap.insert(totalTime, text); 68 | pos += rx.matchedLength(); 69 | pos = rx.indexIn(oneline, pos);//更改位置继续匹配 70 | } 71 | } 72 | 73 | if(!lrcMap.isEmpty()) 74 | { 75 | timeList = lrcMap.uniqueKeys();//得到时间列表以便搜索 76 | return true; 77 | } 78 | return false; 79 | } 80 | 81 | //载入程序目录下歌词文件夹中的歌词,文件存在返回true 82 | bool Lyrics::loadFromLrcDir(QString fileName) 83 | { 84 | QFileInfo fileInfo(fileName); 85 | fileName = QCoreApplication::applicationDirPath() + "/lyrics/" + fileInfo.completeBaseName() + ".lrc"; 86 | 87 | if (QFile(fileName).exists()) 88 | { 89 | resolve(fileName, true); 90 | return true;//文件存在 91 | } else { 92 | return false;//文件不存在 93 | } 94 | } 95 | 96 | bool Lyrics::loadFromFileRelativePath(QString fileName, QString path) 97 | { 98 | QFileInfo fileInfo(fileName); 99 | fileName = fileInfo.path() + path + fileInfo.completeBaseName() + ".lrc"; 100 | 101 | if (QFile(fileName).exists()) 102 | { 103 | resolve(fileName, true); 104 | return true;//文件存在 105 | } else { 106 | return false;//文件不存在 107 | } 108 | } 109 | 110 | //更新歌词显示时间 111 | void Lyrics::updateTime(int curms, int totalms) 112 | { 113 | if(!lrcMap.isEmpty()) 114 | { 115 | int time = 0; 116 | int nextTime = 0; 117 | //keys()方法返回lrcMap列表 118 | foreach (int value, lrcMap.keys()) 119 | { 120 | if (curms >= value) 121 | { 122 | time = value; 123 | } else { 124 | nextTime = value; 125 | break; 126 | } 127 | } 128 | curLrcTime = time;//记录要显示的歌词所在的时间 129 | 130 | if (nextTime != 0) 131 | nextLrcTime = nextTime;//如果有下一句歌词的话,设置时间 132 | else 133 | nextLrcTime = totalms;//否则设置下一句为总时间 134 | } 135 | } 136 | 137 | //取得curLrcTime下,指定偏移量的歌词 138 | QString Lyrics::getLrcString(int offset) 139 | { 140 | if(!lrcMap.isEmpty()) 141 | { 142 | int showTime = 0; 143 | 144 | int index = timeList.indexOf(curLrcTime);//取得当前歌词索引 145 | if(index + offset >= 0 && index + offset < timeList.size()) 146 | { 147 | showTime = timeList[index + offset];//取得偏移后,要显示的歌词时间 148 | } else { 149 | return "";//如果没有此索引,返回空字符串 150 | } 151 | 152 | return lrcMap.value(showTime);//返回要显示的歌词 153 | } else { 154 | return "";//如果没有歌词,返回空字符串 155 | } 156 | return "";//空Map返回空字符串 157 | } 158 | 159 | //返回输入时间在当前句子中的百分比,取值0~1 160 | double Lyrics::getTimePos(int ms) 161 | { 162 | if (!lrcMap.isEmpty()) 163 | { 164 | if (ms < curLrcTime) 165 | { 166 | return 0; 167 | } else if (ms > nextLrcTime) { 168 | return 1; 169 | } else { 170 | return (double)(ms - curLrcTime) / (nextLrcTime - curLrcTime); 171 | } 172 | } else { 173 | return 0;//使“Shadow Player”文本未填充 174 | } 175 | } 176 | 177 | bool Lyrics::isLrcEmpty() 178 | { 179 | return lrcMap.isEmpty(); 180 | } 181 | -------------------------------------------------------------------------------- /Sources/lyrics.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 歌词解析、读取类 3 | * 支持乱序歌词、多时间标签歌词 4 | * 注意:<*不支持100分钟以上歌词*> 5 | */ 6 | #ifndef LYRICS_H 7 | #define LYRICS_H 8 | #include 9 | #include 10 | #include 11 | 12 | class Lyrics 13 | { 14 | public: 15 | Lyrics(); 16 | bool resolve(QString fileName, bool isLrc = false);//歌词解析 ,isLrc:此文件是否为歌词文件,失败返回false 17 | bool loadFromLrcDir(QString fileName); 18 | bool loadFromFileRelativePath(QString fileName, QString path); 19 | void updateTime(int ms, int totalms);//刷新时间 20 | double getTimePos(int ms);//返回指定时间在当前语句中的位置 21 | QString getLrcString(int offset);//取得歌词文本,参数:行数偏移量,负值表示提前 22 | bool isLrcEmpty(); 23 | private: 24 | QMap lrcMap;//存放歌词的QMap 25 | QList timeList;//存放歌词时间的列表 26 | int curLrcTime;//目前将要显示的歌词时间 27 | int nextLrcTime;//下一句歌词的时间 28 | }; 29 | 30 | #endif // LYRICS_H 31 | -------------------------------------------------------------------------------- /Sources/main.cpp: -------------------------------------------------------------------------------- 1 | #include "shadowplayer.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef Q_OS_WIN32 //Windows 10 | #include 11 | bool checkOnly() 12 | { 13 | HANDLE playerMutex = CreateMutex(NULL, FALSE, L"shadowplayer"); 14 | if (GetLastError() == ERROR_ALREADY_EXISTS) 15 | { 16 | CloseHandle(playerMutex); 17 | playerMutex = NULL; 18 | return false;//存在 19 | } else { 20 | return true;//不存在 21 | } 22 | } 23 | #endif 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | QApplication a(argc, argv); 28 | 29 | //二次启动,防止多开并载入文件 30 | if(!checkOnly()) 31 | { 32 | QString file = QString::fromLocal8Bit(argv[1]); 33 | 34 | COPYDATASTRUCT cpd; 35 | cpd.dwData = 0; 36 | cpd.cbData = file.toUtf8().size() + 1;// + 1 是为了在末尾创建一个00(字符串终止) 37 | cpd.lpData = file.toUtf8().data(); 38 | HWND hWnd = FindWindowW(L"Qt5QWindowIcon", L"ShadowPlayer"); 39 | SendMessageW(hWnd, WM_COPYDATA, NULL, (LPARAM)&cpd); 40 | return -1;//退出 41 | } 42 | 43 | ShadowPlayer w; 44 | w.show(); 45 | //直接使用此应用程序打开文件 46 | if(argc > 1) 47 | { 48 | QStringList fileList; 49 | for (int i = 1; i < argc; i++) 50 | fileList.append(QString::fromLocal8Bit(argv[i])); 51 | w.addToListAndPlay(fileList); 52 | } 53 | 54 | //首次运行 55 | QFile file(QCoreApplication::applicationDirPath() + "/FirstRun"); 56 | if (file.exists()) 57 | { 58 | file.remove(); 59 | w.on_showDskLrcButton_clicked(); 60 | w.addToListAndPlay(QCoreApplication::applicationDirPath() + "/DEMO/CONNECT~心的连接~.mp3"); 61 | QMessageBox::information(0, "欢迎~", "您是第一次运行本程序\n点击右上角的箭头探索更多功能\n祝您玩得愉快", "好的"); 62 | } 63 | 64 | return a.exec(); 65 | } 66 | -------------------------------------------------------------------------------- /Sources/osd.cpp: -------------------------------------------------------------------------------- 1 | #include "osd.h" 2 | #include "ui_osd.h" 3 | 4 | OSD::OSD(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::OSD) 7 | { 8 | ui->setupUi(this); 9 | timer = new QTimer(this); 10 | connect(timer,SIGNAL(timeout()),this,SLOT(timeRoll())); 11 | backGround = QPixmap(":/image/image/OSD.png"); 12 | 13 | this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool); 14 | this->setAttribute(Qt::WA_TranslucentBackground); 15 | 16 | this->setGeometry(QApplication::desktop()->screenGeometry().width() - this->width(), 80, this->width(), this->height()); 17 | this->setFixedSize(this->width(), this->height()); 18 | 19 | hideAnimation = new QPropertyAnimation(this, "windowOpacity"); 20 | hideAnimation->setDuration(600); 21 | hideAnimation->setStartValue(1); 22 | hideAnimation->setEndValue(0); 23 | connect(hideAnimation, SIGNAL(finished()), this, SLOT(hide()));//动画效果结束后隐藏 24 | 25 | titleAnimation = new QPropertyAnimation(ui->titleLabel, "geometry"); 26 | titleAnimation->setEasingCurve(QEasingCurve::OutCirc); 27 | titleAnimation->setDuration(1200); 28 | titleAnimation->setStartValue(QRect(30, 30, 0, 61)); 29 | titleAnimation->setEndValue(QRect(40, 30, 281, 61)); 30 | 31 | timeAnimation = new QPropertyAnimation(ui->timeLabel, "geometry"); 32 | timeAnimation->setEasingCurve(QEasingCurve::OutCirc); 33 | timeAnimation->setDuration(1200); 34 | timeAnimation->setStartValue(QRect(331, 80, 0, 41)); 35 | timeAnimation->setEndValue(QRect(40, 80, 281, 41)); 36 | } 37 | 38 | OSD::~OSD() 39 | { 40 | delete ui; 41 | delete timer; 42 | delete hideAnimation; 43 | delete titleAnimation; 44 | delete timeAnimation; 45 | } 46 | 47 | void OSD::paintEvent(QPaintEvent *) 48 | { 49 | QPainter painter(this); 50 | painter.drawPixmap(0, 0, backGround); 51 | } 52 | 53 | //倒计时隐藏 54 | void OSD::timeRoll() 55 | { 56 | timeleft--; 57 | if (timeleft <= 0) 58 | { 59 | 60 | hideAnimation->start(); 61 | //this->setVisible(false); 62 | timer->stop(); 63 | } 64 | } 65 | 66 | //显示此OSD 67 | void OSD::showOSD(QString tags, QString totalTime) 68 | { 69 | timeleft = 4; 70 | hideAnimation->stop();//如果正在淡出窗口,中止淡出动画 71 | titleAnimation->stop(); 72 | titleAnimation->start(); 73 | timeAnimation->stop(); 74 | timeAnimation->start(); 75 | this->setWindowOpacity(1); 76 | 77 | QFontMetrics titleFontMetrics(ui->titleLabel->font()); 78 | if (titleFontMetrics.width(tags) > 281) 79 | { 80 | ui->titleLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft); 81 | ui->titleLabel->setWordWrap(true); 82 | } else { 83 | ui->titleLabel->setAlignment(Qt::AlignCenter); 84 | ui->titleLabel->setWordWrap(false); 85 | } 86 | 87 | ui->titleLabel->setText(tags); 88 | ui->timeLabel->setText(totalTime); 89 | timer->start(1000); 90 | this->show(); 91 | this->update(); 92 | } 93 | 94 | //点击后立即隐藏 95 | void OSD::mousePressEvent(QMouseEvent *event) 96 | { 97 | if (event->button() == Qt::LeftButton) 98 | { 99 | timer->stop(); 100 | this->hide(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Sources/osd.h: -------------------------------------------------------------------------------- 1 | #ifndef OSD_H 2 | #define OSD_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace Ui { 10 | class OSD; 11 | } 12 | 13 | class OSD : public QWidget 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit OSD(QWidget *parent = 0); 19 | ~OSD(); 20 | void showOSD(QString tags, QString totalTime); 21 | 22 | private: 23 | Ui::OSD *ui; 24 | QPixmap backGround; 25 | QTimer *timer; 26 | int timeleft; 27 | QPropertyAnimation *hideAnimation; 28 | QPropertyAnimation *titleAnimation; 29 | QPropertyAnimation *timeAnimation; 30 | 31 | private slots: 32 | void timeRoll(); 33 | 34 | protected: 35 | void paintEvent(QPaintEvent *); 36 | void mousePressEvent(QMouseEvent *event); 37 | }; 38 | 39 | #endif // OSD_H 40 | -------------------------------------------------------------------------------- /Sources/osd.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | OSD 4 | 5 | 6 | 7 | 0 8 | 0 9 | 360 10 | 160 11 | 12 | 13 | 14 | SPOSD 15 | 16 | 17 | 18 | 19 | 40 20 | 30 21 | 281 22 | 61 23 | 24 | 25 | 26 | 27 | 微软雅黑 28 | 11 29 | 75 30 | true 31 | 32 | 33 | 34 | color: white; 35 | 36 | 37 | 标题信息 38 | 39 | 40 | Qt::AlignCenter 41 | 42 | 43 | 44 | 45 | 46 | 40 47 | 80 48 | 281 49 | 41 50 | 51 | 52 | 53 | 54 | 微软雅黑 55 | 26 56 | 75 57 | true 58 | 59 | 60 | 61 | color: white; 62 | 63 | 64 | 0:00 65 | 66 | 67 | Qt::AlignCenter 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Sources/player.cpp: -------------------------------------------------------------------------------- 1 | #include "player.h" 2 | #include 3 | Player::Player() 4 | { 5 | playNextEnable = true; 6 | //加载解码插件 7 | BASS_PluginLoad("bass_aac.dll", 0); 8 | BASS_PluginLoad("bass_alac.dll", 0); 9 | BASS_PluginLoad("bass_ape.dll", 0); 10 | BASS_PluginLoad("bass_tta.dll", 0); 11 | BASS_PluginLoad("bassflac.dll", 0); 12 | BASS_PluginLoad("basswma.dll", 0); 13 | BASS_PluginLoad("basswv.dll", 0); 14 | } 15 | 16 | Player::~Player() 17 | { 18 | BASS_Free(); 19 | } 20 | 21 | QString Player::openFile(QString fileName) 22 | { 23 | //打开新文件前停止播放 24 | //这里应该用QFileInfo(xx).suffix(); 25 | if(fileName.toLower().endsWith(".mp3")|| 26 | fileName.toLower().endsWith(".mp2")|| 27 | fileName.toLower().endsWith(".mp1")|| 28 | fileName.toLower().endsWith(".wav")|| 29 | fileName.toLower().endsWith(".ogg")|| 30 | fileName.toLower().endsWith(".aiff")|| 31 | fileName.toLower().endsWith(".ape")|| 32 | fileName.toLower().endsWith(".mp4")|| 33 | fileName.toLower().endsWith(".m4a")|| 34 | fileName.toLower().endsWith(".m4v")|| 35 | fileName.toLower().endsWith(".aac")|| 36 | fileName.toLower().endsWith(".alac")|| 37 | fileName.toLower().endsWith(".tta")|| 38 | fileName.toLower().endsWith(".flac")|| 39 | fileName.toLower().endsWith(".wma")|| 40 | fileName.toLower().endsWith(".wv") 41 | ) 42 | { 43 | BASS_ChannelStop(nowPlay); 44 | BASS_StreamFree(nowPlay); 45 | nowPlay = BASS_StreamCreateFile(false,fileName.toStdWString().c_str(),0,0,BASS_UNICODE|BASS_SAMPLE_FLOAT|BASS_SAMPLE_FX|BASS_STREAM_DECODE|BASS_STREAM_PRESCAN); 46 | 47 | if (BASS_ErrorGetCode() != 0) 48 | { 49 | return "err";//打开文件失败 50 | } 51 | 52 | if (nowPlay)//如果流创建成功 53 | { 54 | //创建反向流 55 | nowPlay = BASS_FX_ReverseCreate(nowPlay, 2, BASS_FX_FREESOURCE|BASS_SAMPLE_FLOAT/*|BASS_SAMPLE_FX*/); 56 | //转为正向播放 57 | BASS_ChannelSetAttribute(nowPlay, BASS_ATTRIB_REVERSE_DIR, BASS_FX_RVS_FORWARD); 58 | } 59 | 60 | //创建混响效果 61 | reverbFX = BASS_ChannelSetFX(nowPlay, BASS_FX_DX8_REVERB, 1); 62 | //此时默认开启混响……需要关闭 63 | return "ok"; 64 | } 65 | else 66 | { 67 | return "err"; 68 | } 69 | } 70 | 71 | void Player::eqReady() 72 | { 73 | BASS_BFX_PEAKEQ peakEQ; 74 | 75 | eqFX = BASS_ChannelSetFX(nowPlay, BASS_FX_BFX_PEAKEQ, 2); 76 | 77 | peakEQ.fGain = 0; 78 | peakEQ.fQ = 0; 79 | peakEQ.fBandwidth = 2.5f; 80 | peakEQ.lChannel = BASS_BFX_CHANALL; 81 | 82 | peakEQ.lBand = 0; 83 | peakEQ.fCenter = 31; 84 | BASS_FXSetParameters(eqFX, &peakEQ); 85 | 86 | peakEQ.lBand = 1; 87 | peakEQ.fCenter = 62; 88 | BASS_FXSetParameters(eqFX, &peakEQ); 89 | 90 | peakEQ.lBand = 2; 91 | peakEQ.fCenter = 125; 92 | BASS_FXSetParameters(eqFX, &peakEQ); 93 | 94 | peakEQ.lBand = 3; 95 | peakEQ.fCenter = 250; 96 | BASS_FXSetParameters(eqFX, &peakEQ); 97 | 98 | peakEQ.lBand = 4; 99 | peakEQ.fCenter = 500; 100 | BASS_FXSetParameters(eqFX, &peakEQ); 101 | 102 | peakEQ.lBand = 5; 103 | peakEQ.fCenter = 1000; 104 | BASS_FXSetParameters(eqFX, &peakEQ); 105 | 106 | peakEQ.lBand = 6; 107 | peakEQ.fCenter = 2000; 108 | BASS_FXSetParameters(eqFX, &peakEQ); 109 | 110 | peakEQ.lBand = 7; 111 | peakEQ.fCenter = 4000; 112 | BASS_FXSetParameters(eqFX, &peakEQ); 113 | 114 | peakEQ.lBand = 8; 115 | peakEQ.fCenter = 8000; 116 | BASS_FXSetParameters(eqFX, &peakEQ); 117 | 118 | peakEQ.lBand = 9; 119 | peakEQ.fCenter = 16000; 120 | BASS_FXSetParameters(eqFX, &peakEQ); 121 | } 122 | 123 | void Player::disableEQ() 124 | { 125 | BASS_ChannelRemoveFX(nowPlay, eqFX); 126 | } 127 | 128 | void Player::setEQ(int id, int gain) 129 | { 130 | BASS_BFX_PEAKEQ peakEQ;//均衡器参数结构 131 | //id对应均衡器段编号 132 | peakEQ.lBand = id; 133 | BASS_FXGetParameters(eqFX, &peakEQ); 134 | peakEQ.fGain = gain;//-15~15,EQ参数 135 | BASS_FXSetParameters(eqFX, &peakEQ);//变更参数 136 | } 137 | 138 | void Player::setVol(int vol) 139 | { 140 | //设置音量,0最小,100最大 141 | float v = (float)vol/100; 142 | BASS_ChannelSetAttribute(nowPlay, BASS_ATTRIB_VOL, v); 143 | } 144 | 145 | int Player::getVol() 146 | { 147 | //取得音量,0最小,100最大 148 | float vol; 149 | BASS_ChannelGetAttribute(nowPlay, BASS_ATTRIB_VOL, &vol); 150 | return (int)(vol*100); 151 | } 152 | 153 | bool Player::isPlaying() 154 | { 155 | if (BASS_ChannelIsActive(nowPlay) == BASS_ACTIVE_PLAYING) 156 | return true; 157 | else 158 | return false; 159 | } 160 | 161 | void Player::getFFT(float *array) 162 | { 163 | if (BASS_ChannelIsActive(nowPlay) == BASS_ACTIVE_PLAYING) 164 | BASS_ChannelGetData(nowPlay, array, BASS_DATA_FFT4096); 165 | } 166 | 167 | void Player::play() 168 | { 169 | BASS_ChannelPlay(nowPlay, false); 170 | } 171 | 172 | void Player::stop() 173 | { 174 | BASS_ChannelStop(nowPlay); 175 | BASS_ChannelSetPosition(nowPlay,0,BASS_POS_BYTE); 176 | } 177 | 178 | void Player::pause() 179 | { 180 | BASS_ChannelPause(nowPlay); 181 | } 182 | 183 | //初始化音频设备 184 | bool Player::devInit() 185 | { 186 | return BASS_Init(-1, 48000, 0, 0, NULL); 187 | } 188 | 189 | QString Player::getTags() 190 | { 191 | //QString tags = TAGS_Read(nowPlay, "%IFV2(%ARTI,%UTF8(%ARTI),未知艺术家) - %IFV2(%TITL,%UTF8(%TITL),无标题)"); 192 | 193 | //有一些音频把艺术家写到了标题里 194 | //很少见到只有艺术家没有标题的音频 195 | //故修改为下列表达式,若只有艺术家没有标题会是“艺术家 - ”的形式……喵 196 | //(末尾为" - "应该删去3个字符?) 197 | QString tags = TAGS_Read(nowPlay, "%IFV2(%ARTI,%UTF8(%ARTI) - ,)%IFV2(%TITL,%UTF8(%TITL),)"); 198 | if (tags.trimmed().isEmpty()) 199 | return "Show_File_Name";//如果标签是空字符,直接显示文件名 200 | else 201 | return tags;//返回标签 202 | } 203 | 204 | int Player::getPos() 205 | { 206 | //返回当前播放位置,取值范围0~1000 207 | return (int)(BASS_ChannelGetPosition(nowPlay, BASS_POS_BYTE)*1000/BASS_ChannelGetLength(nowPlay, BASS_POS_BYTE)); 208 | } 209 | 210 | void Player::setPos(int pos) 211 | { 212 | //跳转进度到指定位置,0~1000 213 | BASS_ChannelSetPosition(nowPlay, pos*BASS_ChannelGetLength(nowPlay, BASS_POS_BYTE)/1000, BASS_POS_BYTE); 214 | } 215 | 216 | //取得音频比特率 217 | int Player::getBitRate() 218 | { 219 | float time=BASS_ChannelBytes2Seconds(nowPlay, BASS_ChannelGetLength(nowPlay, BASS_POS_BYTE)); // 播放时间 220 | DWORD len=BASS_StreamGetFilePosition(nowPlay, BASS_FILEPOS_END); // 文件长度 221 | int bitrate=(int)(len/(125*time)+0.5); // 比特率/编码率 (Kbps) 222 | return bitrate; 223 | } 224 | 225 | //取得音频采样率 226 | int Player::getFreq() 227 | { 228 | BASS_CHANNELINFO cInfo; 229 | BASS_ChannelGetInfo(nowPlay, &cInfo); 230 | return cInfo.freq; 231 | } 232 | 233 | //设置音频采样率 234 | void Player::setFreq(float freq) 235 | { 236 | BASS_ChannelSetAttribute(nowPlay, BASS_ATTRIB_FREQ, freq); 237 | } 238 | 239 | QString Player::getNowPlayInfo() 240 | { 241 | QString mono = QString::fromUtf8("单声道"); 242 | QString stereo = QString::fromUtf8("立体声"); 243 | QString fmt = QString(""); 244 | BASS_CHANNELINFO cInfo; 245 | BASS_CHANNELINFO *info = &cInfo; 246 | BASS_ChannelGetInfo(nowPlay, info); 247 | 248 | if (info->ctype == BASS_CTYPE_STREAM_AIFF) 249 | fmt = " AIFF"; 250 | else if (info->ctype == BASS_CTYPE_STREAM_MP3) 251 | fmt = " MP3"; 252 | else if (info->ctype == BASS_CTYPE_STREAM_MP2) 253 | fmt = " MP2"; 254 | else if (info->ctype == BASS_CTYPE_STREAM_MP1) 255 | fmt = " MP1"; 256 | else if (info->ctype == BASS_CTYPE_STREAM_OGG) 257 | fmt = " OGG"; 258 | else if (info->ctype == BASS_CTYPE_STREAM_WAV_PCM) 259 | fmt = " Wave PCM"; 260 | else if (info->ctype == BASS_CTYPE_STREAM_WAV_FLOAT) 261 | fmt = QString::fromUtf8(" Wave 浮点"); 262 | else if (info->ctype == BASS_CTYPE_STREAM_APE) 263 | fmt = QString::fromUtf8(" APE"); 264 | else if (info->ctype == BASS_CTYPE_STREAM_MP4) 265 | fmt = QString::fromUtf8(" MP4"); 266 | else if (info->ctype == BASS_CTYPE_STREAM_AAC) 267 | fmt = QString::fromUtf8(" AAC"); 268 | else if (info->ctype == BASS_CTYPE_STREAM_ALAC) 269 | fmt = QString::fromUtf8(" ALAC"); 270 | else if (info->ctype == BASS_CTYPE_STREAM_TTA) 271 | fmt = QString::fromUtf8(" TTA"); 272 | else if (info->ctype == BASS_CTYPE_STREAM_FLAC) 273 | fmt = QString::fromUtf8(" FLAC"); 274 | else if (info->ctype == BASS_CTYPE_STREAM_WMA) 275 | fmt = QString::fromUtf8(" WMA"); 276 | else if (info->ctype == BASS_CTYPE_STREAM_WMA_MP3) 277 | fmt = QString::fromUtf8(" WMA"); 278 | else if (info->ctype == BASS_CTYPE_STREAM_WV) 279 | fmt = QString::fromUtf8(" WV"); 280 | 281 | 282 | if (info->chans == 1) 283 | return QString::number(info->freq) + "Hz " + QString::number(this->getBitRate()) + "Kbps " + mono + fmt; 284 | else 285 | return QString::number(info->freq) + "Hz " + QString::number(this->getBitRate()) + "Kbps " + stereo + fmt; 286 | } 287 | 288 | QString Player::getCurTime() 289 | { 290 | int totalSec = (int)BASS_ChannelBytes2Seconds(nowPlay,BASS_ChannelGetPosition(nowPlay, BASS_POS_BYTE)); 291 | int minute = totalSec/60; 292 | int second = totalSec%60; 293 | if (second != -1) 294 | { 295 | if(second < 10) 296 | return QString::number(minute) + ":0" + QString::number(second); 297 | else 298 | return QString::number(minute) + ":" + QString::number(second); 299 | } else { 300 | return "0:00"; 301 | } 302 | } 303 | 304 | QString Player::getTotalTime() 305 | { 306 | int totalSec = (int)BASS_ChannelBytes2Seconds(nowPlay,BASS_ChannelGetLength(nowPlay, BASS_POS_BYTE)); 307 | int minute = totalSec/60; 308 | int second = totalSec%60; 309 | if (second != -1) 310 | { 311 | if(second < 10) 312 | return QString::number(minute) + ":0" + QString::number(second); 313 | else 314 | return QString::number(minute) + ":" + QString::number(second); 315 | } else { 316 | return "0:00"; 317 | } 318 | } 319 | 320 | int Player::getCurTimeMS() 321 | { 322 | return (int)(BASS_ChannelBytes2Seconds(nowPlay,BASS_ChannelGetPosition(nowPlay, BASS_POS_BYTE))*1000); 323 | } 324 | 325 | int Player::getTotalTimeMS() 326 | { 327 | return (int)(BASS_ChannelBytes2Seconds(nowPlay,BASS_ChannelGetLength(nowPlay, BASS_POS_BYTE))*1000); 328 | } 329 | 330 | double Player::getCurTimeSec() 331 | { 332 | return BASS_ChannelBytes2Seconds(nowPlay,BASS_ChannelGetPosition(nowPlay, BASS_POS_BYTE)); 333 | } 334 | 335 | double Player::getTotalTimeSec() 336 | { 337 | return BASS_ChannelBytes2Seconds(nowPlay,BASS_ChannelGetLength(nowPlay, BASS_POS_BYTE)); 338 | } 339 | 340 | DWORD Player::getLevel() 341 | { 342 | //返回声道电平,低16位左声道,高16位右声道 343 | DWORD level; 344 | level = BASS_ChannelGetLevel(nowPlay); 345 | if (level != -1) { 346 | return level; 347 | } 348 | else 349 | { 350 | return 0; 351 | } 352 | 353 | } 354 | 355 | QString Player::getFileTotalTime(QString fileName) 356 | { 357 | HSTREAM fileStream = BASS_StreamCreateFile(false,fileName.toStdWString().c_str(),0,0,BASS_UNICODE); 358 | int totalSec = (int)BASS_ChannelBytes2Seconds(fileStream, BASS_ChannelGetLength(fileStream, BASS_POS_BYTE)); 359 | BASS_StreamFree(fileStream); 360 | int minute = totalSec/60; 361 | int second = totalSec%60; 362 | if (second != -1) 363 | { 364 | if(second < 10) 365 | return QString::number(minute) + ":0" + QString::number(second); 366 | else 367 | return QString::number(minute) + ":" + QString::number(second); 368 | } else { 369 | return "0:00"; 370 | } 371 | } 372 | 373 | double Player::getFileSecond(QString fileName) 374 | { 375 | HSTREAM fileStream = BASS_StreamCreateFile(false,fileName.toStdWString().c_str(),0,0,BASS_UNICODE); 376 | double totalSec = BASS_ChannelBytes2Seconds(fileStream, BASS_ChannelGetLength(fileStream, BASS_POS_BYTE)); 377 | BASS_StreamFree(fileStream); 378 | return totalSec; 379 | } 380 | 381 | //更改播放方向(false正、true反) 382 | void Player::setReverse(bool isEnable) 383 | { 384 | if (isEnable) 385 | BASS_ChannelSetAttribute(nowPlay, BASS_ATTRIB_REVERSE_DIR, BASS_FX_RVS_REVERSE); 386 | else 387 | BASS_ChannelSetAttribute(nowPlay, BASS_ATTRIB_REVERSE_DIR, BASS_FX_RVS_FORWARD); 388 | } 389 | 390 | //更新混响效果,参数取值范围:-20~0 391 | void Player::updateReverb(int value) 392 | { 393 | BASS_DX8_REVERB p; 394 | BASS_FXGetParameters(reverbFX, &p); 395 | p.fReverbMix = 0.012f * (value * value * value);//参数取值范围:-96~0 396 | BASS_FXSetParameters(reverbFX, &p); 397 | } 398 | -------------------------------------------------------------------------------- /Sources/player.h: -------------------------------------------------------------------------------- 1 | #ifndef PLAYER_H 2 | #define PLAYER_H 3 | #include "bass.h" 4 | #include "bass_ape.h" 5 | #include "bass_aac.h" 6 | #include "bass_alac.h" 7 | #include "bass_tta.h" 8 | #include "bassflac.h" 9 | #include "basswma.h" 10 | #include "basswv.h" 11 | #include "tags.h" 12 | #include "bass_fx.h" 13 | #include 14 | #include 15 | 16 | class Player 17 | { 18 | public: 19 | Player(); 20 | ~Player(); 21 | bool devInit(); 22 | QString getTags(); 23 | void setVol(int vol); 24 | int getVol(); 25 | QString openFile(QString fileName); 26 | void play();//播放 27 | void pause();//暂停 28 | void stop();//停止并跳回头部 29 | int getPos();//取得播放位置 30 | void setPos(int pos);//改变播放位置 31 | int getBitRate();//计算比特率 32 | void getFFT(float *array); 33 | bool isPlaying(); 34 | int getFreq(); 35 | void setFreq(float freq); 36 | void eqReady(); 37 | void disableEQ(); 38 | void setEQ(int id, int gain); 39 | QString getNowPlayInfo();//取得媒体参数信息描述 40 | QString getTotalTime();//取得用于显示的总时间 41 | QString getCurTime();//取得用于显示的当前时间 42 | int getCurTimeMS();//取得当前播放时间的毫秒数(整数) 43 | int getTotalTimeMS();//取得总播放时间的毫秒数(整数) 44 | double getCurTimeSec(); 45 | double getTotalTimeSec(); 46 | DWORD getLevel(); 47 | QString getFileTotalTime(QString fileName);//计算文件时间 48 | double getFileSecond(QString fileName); 49 | void setReverse(bool isEnable); 50 | void updateReverb(int value);//更新混响效果,参数取值范围:0~20 51 | void setJumpPoint(double timeFrom, double timeTo); 52 | void removeJumpPoint(); 53 | 54 | private: 55 | HSTREAM nowPlay;//播放流句柄 56 | HFX eqFX;//10段均衡器效果 57 | HFX reverbFX;//混响效果 58 | bool playNextEnable;//暂时无用 59 | HSYNC jumping; 60 | }; 61 | #endif // PLAYER_H 62 | -------------------------------------------------------------------------------- /Sources/playlist.cpp: -------------------------------------------------------------------------------- 1 | #include "playlist.h" 2 | #include "ui_playlist.h" 3 | 4 | PlayList::PlayList(Player *player, QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::PlayList) 7 | { 8 | ui->setupUi(this); 9 | curIndex = 0; 10 | lengthFilter = 0; 11 | this->player = player; 12 | ui->playListTable->horizontalHeader()->setStretchLastSection(true);//自动设置最后一列宽度 13 | this->setWindowFlags(Qt::WindowTitleHint | Qt::CustomizeWindowHint); 14 | this->setFixedSize(this->width(), this->height()); 15 | 16 | //“查找”文本框,绑定回车键到“查找”按钮 17 | connect(ui->searchEdit, SIGNAL(returnPressed()), this, SLOT(on_searchButton_clicked())); 18 | 19 | readFromFile(QCoreApplication::applicationDirPath() + "/PlayList.sdpl"); 20 | } 21 | 22 | PlayList::~PlayList() 23 | { 24 | saveToFile(QCoreApplication::applicationDirPath() + "/PlayList.sdpl"); 25 | delete ui; 26 | } 27 | 28 | bool PlayList::fixSuffix(QString fileName) 29 | { 30 | if(fileName.toLower().endsWith(".mp3")|| 31 | fileName.toLower().endsWith(".mp2")|| 32 | fileName.toLower().endsWith(".mp1")|| 33 | fileName.toLower().endsWith(".wav")|| 34 | fileName.toLower().endsWith(".ogg")|| 35 | fileName.toLower().endsWith(".aiff")|| 36 | fileName.toLower().endsWith(".ape")|| 37 | fileName.toLower().endsWith(".mp4")|| 38 | fileName.toLower().endsWith(".m4a")|| 39 | fileName.toLower().endsWith(".m4v")|| 40 | fileName.toLower().endsWith(".aac")|| 41 | fileName.toLower().endsWith(".alac")|| 42 | fileName.toLower().endsWith(".tta")|| 43 | fileName.toLower().endsWith(".flac")|| 44 | fileName.toLower().endsWith(".wma")|| 45 | fileName.toLower().endsWith(".wv") 46 | ) 47 | { 48 | return true; 49 | } else { 50 | return false; 51 | } 52 | } 53 | 54 | bool PlayList::isEmpty() 55 | { 56 | if (fileList.isEmpty()) 57 | return true; 58 | else 59 | return false; 60 | } 61 | 62 | //核心函数,添加歌曲 63 | void PlayList::add(QString fileName) 64 | { 65 | if (fixSuffix(fileName)) 66 | { 67 | if ((int)(player->getFileSecond(fileName)) >= lengthFilter) 68 | { 69 | fileList.append(fileName); 70 | timeList.append(player->getFileTotalTime(fileName)); 71 | } 72 | } 73 | tableUpdate(); 74 | } 75 | 76 | //核心函数 77 | void PlayList::insert(int index, QString fileName) 78 | { 79 | if (fixSuffix(fileName)) 80 | { 81 | if ((int)(player->getFileSecond(fileName)) >= lengthFilter) 82 | { 83 | if (index < curIndex) 84 | ++curIndex;//如果在前端插入,后移播放索引 85 | fileList.insert(index, fileName); 86 | timeList.insert(index, player->getFileTotalTime(fileName)); 87 | } 88 | } 89 | tableUpdate(); 90 | } 91 | 92 | void PlayList::remove(int index) 93 | { 94 | if (index <= curIndex && index > -1)//大于-1用于判断是否未选任何项 95 | --curIndex;//删除前方项,上移当前项索引 96 | fileList.removeAt(index); 97 | timeList.removeAt(index); 98 | tableUpdate(); 99 | } 100 | 101 | void PlayList::clearAll() 102 | { 103 | fileList.clear(); 104 | timeList.clear(); 105 | curIndex = 0; 106 | tableUpdate(); 107 | } 108 | 109 | int PlayList::getLength() 110 | { 111 | return fileList.length(); 112 | } 113 | 114 | int PlayList::getIndex() 115 | { 116 | if (!fileList.isEmpty()) 117 | { 118 | return curIndex; 119 | } 120 | else 121 | { 122 | return -1; 123 | } 124 | } 125 | 126 | //下一曲 参数:是否循环 127 | QString PlayList::next(bool isLoop) 128 | { 129 | if (!fileList.isEmpty()) 130 | { 131 | if (isLoop) 132 | { 133 | if (curIndex < fileList.length() - 1) 134 | { 135 | ++curIndex; 136 | } else { 137 | curIndex = 0; 138 | } 139 | ui->playListTable->selectRow(curIndex);//让视图跟随当前播放歌曲,下一句使该行不选中 140 | tableUpdate(); 141 | return fileList[curIndex]; 142 | } else { 143 | if (curIndex < fileList.length() - 1) 144 | { 145 | ++curIndex; 146 | ui->playListTable->selectRow(curIndex); 147 | tableUpdate(); 148 | return fileList[curIndex]; 149 | } else { 150 | return "stop";//后面没有了。此信息将不处理 151 | } 152 | } 153 | } 154 | return "";//空列表 155 | } 156 | 157 | //上一曲 158 | QString PlayList::previous(bool isLoop) 159 | { 160 | if (!fileList.isEmpty()) 161 | { 162 | if (isLoop) 163 | { 164 | if (curIndex == 0) 165 | { 166 | curIndex = fileList.length() - 1;//循环读取 167 | } else { 168 | --curIndex; 169 | } 170 | ui->playListTable->selectRow(curIndex); 171 | tableUpdate(); 172 | return fileList[curIndex]; 173 | } else { 174 | if (curIndex > 0) 175 | { 176 | --curIndex; 177 | ui->playListTable->selectRow(curIndex); 178 | tableUpdate(); 179 | return fileList[curIndex]; 180 | } else { 181 | return "stop";//前面没有了。 182 | } 183 | } 184 | } 185 | return "";//空列表 186 | } 187 | 188 | //index从0开始计 189 | QString PlayList::playIndex(int index) 190 | { 191 | curIndex = index; 192 | ui->playListTable->selectRow(curIndex); 193 | tableUpdate(); 194 | return fileList[curIndex]; 195 | } 196 | 197 | //返回指定索引的文件名 198 | QString PlayList::getFileNameForIndex(int index) 199 | { 200 | return fileList[index]; 201 | } 202 | 203 | //返回当前文件名 204 | QString PlayList::getCurFile() 205 | { 206 | return fileList[curIndex]; 207 | } 208 | 209 | //返回最后一个文件名,并设置索引 210 | QString PlayList::playLast() 211 | { 212 | if (!fileList.isEmpty()) 213 | { 214 | curIndex = fileList.length() - 1; 215 | ui->playListTable->selectRow(curIndex); 216 | tableUpdate(); 217 | return fileList[curIndex]; 218 | } else { 219 | return ""; 220 | } 221 | } 222 | 223 | //刷新表格 224 | void PlayList::tableUpdate() 225 | { 226 | //这里不能调用此类中任何一个操作元素的函数 227 | //否则将造成循环递归 228 | ui->playListTable->clear(); 229 | ui->playListTable->setRowCount(getLength());//删除项目后,更改表格总行数,防止出现空白行。 230 | int count = fileList.size();//循环效率优化 231 | //重新生成表格项目 232 | for (int i = 0; i < count; i++) 233 | { 234 | QString fileName = fileList[i]; 235 | QFileInfo fileInfo(fileName); 236 | 237 | QTableWidgetItem *item = new QTableWidgetItem(fileInfo.fileName()); 238 | QTableWidgetItem *timeItem = new QTableWidgetItem(timeList[i]); 239 | 240 | if (i == curIndex) 241 | { 242 | item->setBackgroundColor(QColor(128, 255, 0, 128)); 243 | timeItem->setBackgroundColor(QColor(128, 255, 0, 128)); 244 | } 245 | 246 | ui->playListTable->setItem(i, 0, item); 247 | ui->playListTable->setItem(i, 1, timeItem); 248 | } 249 | } 250 | 251 | void PlayList::on_deleteButton_clicked() 252 | { 253 | /* 254 | * 这里做了好久,若直接删除对应行号,上次删除操作会使行号发生变动,误删 255 | * 试过遍历列表得到选中的项目,倒序访问,结果发现排列方式可能不是倒序(访问越界) 256 | * 试过顺序+偏移量的方式,后几项误删 257 | * 以下方法仍为倒序删除。 258 | * 测试正常 259 | * 此方法来自:http://hi.baidu.com/speedylvshirly/item/27c37571f56deb19d1dcb3ee 260 | */ 261 | 262 | //获得列表模型 263 | QItemSelectionModel *selectionModel = ui->playListTable->selectionModel(); 264 | //获得选择项的列表 265 | QModelIndexList selected = selectionModel->selectedIndexes(); 266 | QMap rowMap;//利用QMap的自动排序功能来排列顺序以便删除 267 | foreach (QModelIndex index, selected) 268 | { 269 | rowMap.insert(index.row(), 0);//遍历元素,取得要删除的行数Map 270 | } 271 | 272 | int row;//要删除的行 273 | //创建一个迭代器 274 | QMapIterator rowMapIterator(rowMap); 275 | rowMapIterator.toBack(); 276 | //循环倒序删除 277 | while (rowMapIterator.hasPrevious()) 278 | { 279 | rowMapIterator.previous(); 280 | row = rowMapIterator.key(); 281 | remove(row); 282 | } 283 | } 284 | 285 | void PlayList::dragEnterEvent(QDragEnterEvent *event) 286 | { 287 | event->acceptProposedAction(); 288 | } 289 | 290 | void PlayList::dropEvent(QDropEvent *event) 291 | { 292 | /* 293 | * 不同于主窗口 294 | * 允许多文件拖放 295 | */ 296 | QList urls = event->mimeData()->urls(); 297 | if (urls.isEmpty()) 298 | return; 299 | 300 | int urlCount = urls.size(); 301 | QString fileName; 302 | 303 | for (int i = 0; i < urlCount; i++) 304 | { 305 | fileName = urls[i].toLocalFile(); 306 | if (fixSuffix(fileName)) 307 | { 308 | add(fileName); 309 | } 310 | } 311 | } 312 | 313 | void PlayList::on_playListTable_cellDoubleClicked(int row, int ) 314 | { 315 | curIndex = row; 316 | emit callPlayer();//发送信号给播放器 317 | tableUpdate(); 318 | } 319 | 320 | void PlayList::on_clearButton_clicked() 321 | { 322 | clearAll(); 323 | } 324 | 325 | void PlayList::on_insertButton_clicked() 326 | { 327 | int index = ui->playListTable->currentRow();//记录当前选中的列 328 | if (index < 0) 329 | index = 0;//如果没有选中任何项,在开头插入 330 | QStringList fileNames = QFileDialog::getOpenFileNames(this, QString::fromUtf8("在选择项前插入"), 0, QString::fromUtf8("音频文件 (*.mp3 *.mp2 *.mp1 *.wav *.aiff *.ogg *.ape *.mp4 *.m4a *.m4v *.aac *.alac *.tta *.flac *.wma *.wv)")); 331 | int count = fileNames.size(); 332 | for (int i = 0; i < count; i++) 333 | { 334 | QString fileName = fileNames[i]; 335 | insert(index + i, fileName); 336 | } 337 | } 338 | 339 | void PlayList::on_addButton_clicked() 340 | { 341 | //QFileDialog存在莫名其妙的内存泄漏问题 342 | //选中文件会占用内存空间 343 | //取消选中不会释放 344 | //无解…… 345 | QStringList fileNames = QFileDialog::getOpenFileNames(this, QString::fromUtf8("添加音频"), 0, QString::fromUtf8("音频文件 (*.mp3 *.mp2 *.mp1 *.wav *.aiff *.ogg *.ape *.mp4 *.m4a *.m4v *.aac *.alac *.tta *.flac *.wma *.wv)")); 346 | int count = fileNames.size(); 347 | for (int i = 0; i < count; i++) 348 | { 349 | QString fileName = fileNames[i]; 350 | add(fileName); 351 | } 352 | } 353 | 354 | //查找项目 355 | void PlayList::on_searchButton_clicked() 356 | { 357 | if (!fileList.isEmpty() && !ui->searchEdit->text().isEmpty()) 358 | { 359 | int resultIndex = -1; 360 | int count = fileList.size(); 361 | //在列表中查找字符串 362 | for (int i = 0; i < count; i++) 363 | { 364 | QString fileName = fileList[i]; 365 | QFileInfo fileInfo(fileName); 366 | 367 | //判断“区分大小写”复选框 368 | if (ui->isCaseSensitive->isChecked()) 369 | { 370 | if (fileInfo.fileName().indexOf(ui->searchEdit->text()) > -1)//区分大小写 371 | { 372 | //得到结果,记录 373 | resultIndex = i; 374 | break; 375 | } 376 | } else { 377 | if (fileInfo.fileName().toLower().indexOf(ui->searchEdit->text().toLower()) > -1)//不区分大小写 378 | { 379 | resultIndex = i; 380 | break; 381 | } 382 | } 383 | } 384 | 385 | //如果查找到结果 386 | if (resultIndex != -1) 387 | { 388 | ui->playListTable->selectRow(resultIndex); 389 | } else { 390 | QMessageBox::information(0, "很抱歉", "找不到您要查找的内容", "谢谢"); 391 | } 392 | } else if (ui->searchEdit->text().isEmpty()) { 393 | QMessageBox::information(0, "您好", "请问您要查找什么?", "我忘记了"); 394 | } else { 395 | QMessageBox::information(0, "这是什么情况", "明明什么都没有,为什么我还要在里面找东西呢?。。", "~(>_<。)\"); 396 | } 397 | } 398 | 399 | //查找下一个 400 | void PlayList::on_searchNextButton_clicked() 401 | { 402 | if (!fileList.isEmpty() && !ui->searchEdit->text().isEmpty()) 403 | { 404 | int resultIndex = -1; 405 | int start = ui->playListTable->currentRow() + 1; 406 | int count = fileList.size(); 407 | 408 | if (start < count) //检测是否越界 409 | for (int i = start; i < count; i++) 410 | { 411 | QString fileName = fileList[i]; 412 | QFileInfo fileInfo(fileName); 413 | 414 | if (ui->isCaseSensitive->isChecked()) 415 | { 416 | if (fileInfo.fileName().indexOf(ui->searchEdit->text()) > -1) 417 | { 418 | 419 | resultIndex = i; 420 | break; 421 | } 422 | } else { 423 | if (fileInfo.fileName().toLower().indexOf(ui->searchEdit->text().toLower()) > -1) 424 | { 425 | resultIndex = i; 426 | break; 427 | } 428 | } 429 | } 430 | 431 | if (resultIndex != -1) 432 | { 433 | ui->playListTable->selectRow(resultIndex); 434 | } else { 435 | QMessageBox::information(0, "已完成查找", "所有的内容都查找完毕啦", "辛苦了"); 436 | } 437 | } else if (ui->searchEdit->text().isEmpty()) { 438 | QMessageBox::information(0, "您好", "请问您要查找什么呢?", "我忘记了"); 439 | } else { 440 | QMessageBox::information(0, "这是什么情况", "明明什么都没有,为什么我还要在里面找东西呢?。。", "~(>_<。)\"); 441 | } 442 | } 443 | 444 | void PlayList::on_setLenFilButton_clicked() 445 | { 446 | bool ok; 447 | int set = QInputDialog::getInt(0, "最小播放长度", "小于该长度的音频文件将不被接受\n单位:秒" ,lengthFilter, 0, 2147483647, 1, &ok); 448 | if (ok) 449 | lengthFilter = set; 450 | } 451 | 452 | //保存播放列表,参数:文件路径 453 | void PlayList::saveToFile(QString fileName) 454 | { 455 | QFile file(fileName); 456 | file.open(QIODevice::WriteOnly); 457 | QDataStream stream(&file); 458 | stream << (quint32)0x61727487 << fileList << timeList << curIndex; 459 | file.close(); 460 | } 461 | 462 | //载入播放列表,参数:文件路径 463 | void PlayList::readFromFile(QString fileName) 464 | { 465 | QFile file(fileName); 466 | file.open(QIODevice::ReadOnly); 467 | QDataStream stream(&file); 468 | quint32 magic; 469 | stream >> magic; 470 | if (magic == 0x61727487) 471 | { 472 | stream >> fileList; 473 | stream >> timeList; 474 | stream >> curIndex; 475 | } 476 | file.close(); 477 | tableUpdate(); 478 | } 479 | -------------------------------------------------------------------------------- /Sources/playlist.h: -------------------------------------------------------------------------------- 1 | #ifndef PLAYLIST_H 2 | #define PLAYLIST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "player.h" 9 | 10 | namespace Ui { 11 | class PlayList; 12 | } 13 | 14 | class PlayList : public QWidget 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | explicit PlayList(Player *player, QWidget *parent = 0); 20 | ~PlayList(); 21 | bool fixSuffix(QString fileName); 22 | bool isEmpty(); 23 | void add(QString fileName);//添加文件 24 | void insert(int index, QString fileName);//插入文件 25 | void remove(int index); 26 | void clearAll(); 27 | int getLength(); 28 | int getIndex();//取得当前播放索引 29 | QString next(bool isLoop = false);//得到下一曲路径,索引+1 参数:是否循环 30 | QString previous(bool isLoop = false);//得到上一曲地址路径 31 | QString playIndex(int index);//播放指定索引 32 | QString getFileNameForIndex(int index); 33 | QString getCurFile(); 34 | QString playLast();//播放列表末尾文件 35 | void tableUpdate();//更新显示内容 36 | void saveToFile(QString fileName); 37 | void readFromFile(QString fileName); 38 | 39 | private slots: 40 | void on_deleteButton_clicked(); 41 | void on_playListTable_cellDoubleClicked(int row, int); 42 | void on_clearButton_clicked(); 43 | void on_insertButton_clicked(); 44 | void on_addButton_clicked(); 45 | void on_searchButton_clicked(); 46 | void on_searchNextButton_clicked(); 47 | void on_setLenFilButton_clicked(); 48 | 49 | signals: 50 | void callPlayer();//请求主窗口播放文件 51 | 52 | private: 53 | Ui::PlayList *ui; 54 | QList fileList; 55 | QList timeList; 56 | int curIndex;//正在播放的文件索引 57 | Player *player; 58 | int lengthFilter;//播放长度过滤 59 | 60 | protected: 61 | void dragEnterEvent(QDragEnterEvent *event);//拖放相关 62 | void dropEvent(QDropEvent *event); 63 | }; 64 | 65 | #endif // PLAYLIST_H 66 | -------------------------------------------------------------------------------- /Sources/playlist.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | PlayList 4 | 5 | 6 | 7 | 0 8 | 0 9 | 331 10 | 361 11 | 12 | 13 | 14 | true 15 | 16 | 17 | 播放列表(拖入文件添至末尾,双击启动播放) 18 | 19 | 20 | QScrollBar:vertical { 21 | /*border: 1px solid white;*/ 22 | /*background: rgba(255, 255, 255, 80);*/ 23 | background: transparent; 24 | width: 18px; 25 | margin: 18px 0 18px 0; 26 | } 27 | 28 | QScrollBar::handle:vertical { 29 | background: rgba(0, 0, 0, 128); 30 | min-height: 20px; 31 | } 32 | 33 | QScrollBar::handle:vertical:hover 34 | { 35 | background: rgba(0, 255, 0, 128); 36 | } 37 | 38 | QScrollBar::add-line:vertical { 39 | border: 0px solid grey; 40 | background: rgba(255, 255, 255, 128); 41 | height: 18px; 42 | subcontrol-position: bottom; 43 | subcontrol-origin: margin; 44 | } 45 | 46 | QScrollBar::sub-line:vertical { 47 | border: 0px solid grey; 48 | background: rgba(255, 255, 255, 128); 49 | height: 18px; 50 | subcontrol-position: top; 51 | subcontrol-origin: margin; 52 | } 53 | QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { 54 | border: 1px solid grey; 55 | border-radius: 2px; 56 | width: 3px; 57 | height: 3px; 58 | background: grey; 59 | } 60 | 61 | QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical 62 | { 63 | background:rgba(255, 255, 255, 128); 64 | } 65 | 66 | 67 | 68 | 69 | 0 70 | 0 71 | 331 72 | 281 73 | 74 | 75 | 76 | * { 77 | gridline-color: rgba(255, 255, 255, 200); 78 | } 79 | QTableWidget{ 80 | border: none; 81 | background: rgba(255, 255, 255, 100); 82 | } 83 | QTableWidget::item:selected{ 84 | color: black; 85 | background: rgba(255, 255, 255, 128); 86 | } 87 | QHeaderView { 88 | color: white; 89 | font: bold 10pt; 90 | background-color: rgba(255, 255, 255, 80); 91 | border: 0px solid rgb(144, 144, 144); 92 | border:0px solid rgb(191,191,191); 93 | border-left-color: rgba(255, 255, 255, 0); 94 | border-top-color: rgba(255, 255, 255, 0); 95 | border-radius:0px; 96 | min-height:29px; 97 | } 98 | 99 | QHeaderView::section { 100 | color: black; 101 | background-color: rgba(255, 255, 255, 100); 102 | border: 3px solid #000000; 103 | border-radius:0px; 104 | border-color: rgba(255, 255, 255, 0); 105 | } 106 | 107 | 108 | Qt::ScrollBarAlwaysOff 109 | 110 | 111 | QAbstractItemView::NoEditTriggers 112 | 113 | 114 | QAbstractItemView::SelectRows 115 | 116 | 117 | QAbstractItemView::ScrollPerPixel 118 | 119 | 120 | Qt::SolidLine 121 | 122 | 123 | 0 124 | 125 | 126 | 2 127 | 128 | 129 | false 130 | 131 | 132 | 235 133 | 134 | 135 | 18 136 | 137 | 138 | 18 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 10 147 | 290 148 | 41 149 | 31 150 | 151 | 152 | 153 | 删除当前选中的项 154 | 155 | 156 | 删除 157 | 158 | 159 | 160 | 161 | 162 | 160 163 | 290 164 | 41 165 | 31 166 | 167 | 168 | 169 | 将文件添加到播放列表末尾 170 | 171 | 172 | 添加 173 | 174 | 175 | 176 | 177 | 178 | 110 179 | 290 180 | 41 181 | 31 182 | 183 | 184 | 185 | 在当前选中的项(单项)前插入文件(无选择=第一项) 186 | 187 | 188 | 插入 189 | 190 | 191 | 192 | 193 | 194 | 60 195 | 290 196 | 41 197 | 31 198 | 199 | 200 | 201 | 清空播放列表 202 | 203 | 204 | 清空 205 | 206 | 207 | 208 | 209 | 210 | 10 211 | 330 212 | 121 213 | 21 214 | 215 | 216 | 217 | QLineEdit { 218 | border: 1px solid rgb(0, 170, 255); 219 | border-radius: 2px; 220 | background: rgba(255, 255, 255, 255); 221 | } 222 | 223 | QLineEdit:focus { 224 | border: 1px solid rgb(0, 170, 255); 225 | border-radius: 2px; 226 | background: rgb(230, 239, 255); 227 | } 228 | 229 | 230 | 231 | 232 | 233 | 230 234 | 330 235 | 41 236 | 21 237 | 238 | 239 | 240 | 查找 241 | 242 | 243 | 244 | 245 | 246 | 270 247 | 330 248 | 51 249 | 21 250 | 251 | 252 | 253 | 下一个 254 | 255 | 256 | 257 | 258 | 259 | 230 260 | 290 261 | 91 262 | 31 263 | 264 | 265 | 266 | 最短长度过滤 267 | 268 | 269 | 270 | 271 | 272 | 140 273 | 330 274 | 81 275 | 21 276 | 277 | 278 | 279 | QCheckBox { 280 | spacing: 3px; 281 | } 282 | 283 | QCheckBox::indicator { 284 | width: 13px; 285 | height: 13px; 286 | border: 1px solid rgb(0, 170, 255); 287 | border-radius: 4px; 288 | } 289 | 290 | QCheckBox::indicator:unchecked { 291 | background-color: white; 292 | } 293 | 294 | QCheckBox::indicator:checked { 295 | background-color: rgb(178, 203, 255); 296 | } 297 | 298 | 299 | 区分大小写 300 | 301 | 302 | 303 | 304 | playListTable 305 | deleteButton 306 | insertButton 307 | addButton 308 | 309 | 310 | 311 | 312 | -------------------------------------------------------------------------------- /Sources/res.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | ICO/AllRepeat.png 4 | ICO/Close.png 5 | ICO/Mini.png 6 | ICO/Mute.png 7 | ICO/Next.png 8 | ICO/Open.png 9 | ICO/Order.png 10 | ICO/Pause.png 11 | ICO/Play.png 12 | ICO/PlayList.png 13 | ICO/Pre.png 14 | ICO/Repeat.png 15 | ICO/ShadowPlayer.ico 16 | ICO/Shuffle.png 17 | ICO/Single.png 18 | ICO/Stop.png 19 | ICO/Vol.png 20 | ICO/CSkin.png 21 | 22 | 23 | image/ShadowPlayer.png 24 | image/Skin1.jpg 25 | image/OSD.png 26 | 27 | 28 | -------------------------------------------------------------------------------- /Sources/shadowlabel.cpp: -------------------------------------------------------------------------------- 1 | #include "shadowlabel.h" 2 | 3 | ShadowLabel::ShadowLabel(QWidget *parent) : 4 | QLabel(parent) 5 | { 6 | shadowColor = QColor(255, 255, 255, 128); 7 | shadowMode = 0; 8 | } 9 | 10 | void ShadowLabel::paintEvent(QPaintEvent *event) 11 | { 12 | QPainter painter(this); 13 | painter.setRenderHint(QPainter::Antialiasing, true);//绘图抗锯齿 14 | painter.setFont(this->font()); 15 | painter.setPen(shadowColor);//取得阴影颜色 16 | //绘制阴影 17 | switch (shadowMode) { 18 | case 0: 19 | painter.drawText(2, 2, this->width() - 1, this->height() - 1, this->alignment(), this->text()); 20 | break; 21 | case 1: 22 | painter.drawText(0, 0, this->width() - 1, this->height() - 1, this->alignment(), this->text());//左上 23 | painter.drawText(0, 1, this->width() - 1, this->height() - 1, this->alignment(), this->text());//左 24 | painter.drawText(0, 2, this->width() - 1, this->height() - 1, this->alignment(), this->text());//左下 25 | painter.drawText(1, 0, this->width() - 1, this->height() - 1, this->alignment(), this->text());//上 26 | painter.drawText(1, 2, this->width() - 1, this->height() - 1, this->alignment(), this->text());//下 27 | painter.drawText(2, 0, this->width() - 1, this->height() - 1, this->alignment(), this->text());//右上 28 | painter.drawText(2, 1, this->width() - 1, this->height() - 1, this->alignment(), this->text());//右 29 | painter.drawText(2, 2, this->width() - 1, this->height() - 1, this->alignment(), this->text());//右下 30 | break; 31 | default: 32 | painter.drawText(1, 1, this->width(), this->height(), this->alignment(), this->text()); 33 | break; 34 | } 35 | painter.setPen(this->palette().color(QPalette::WindowText));//取得文本颜色 36 | painter.drawText(1, 1, this->width() - 1, this->height() - 1, this->alignment(), this->text());//绘制文本 37 | } 38 | 39 | void ShadowLabel::setShadowColor(QColor color) 40 | { 41 | shadowColor = color; 42 | } 43 | 44 | void ShadowLabel::setShadowMode(int mode) 45 | { 46 | shadowMode = mode; 47 | } 48 | -------------------------------------------------------------------------------- /Sources/shadowlabel.h: -------------------------------------------------------------------------------- 1 | #ifndef SHADOWLABEL_H 2 | #define SHADOWLABEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class ShadowLabel : public QLabel 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit ShadowLabel(QWidget *parent = 0); 14 | void setShadowColor(QColor color); 15 | void setShadowMode(int mode); 16 | 17 | signals: 18 | 19 | public slots: 20 | 21 | private: 22 | QColor shadowColor; 23 | int shadowMode; 24 | 25 | protected: 26 | void paintEvent(QPaintEvent *event); 27 | 28 | }; 29 | 30 | #endif // SHADOWLABEL_H 31 | -------------------------------------------------------------------------------- /Sources/shadowplayer.h: -------------------------------------------------------------------------------- 1 | #ifndef SHADOWPLAYER_H 2 | #define SHADOWPLAYER_H 3 | #include 4 | #include "player.h" 5 | #include "lyrics.h" 6 | #include "lrcbar.h" 7 | #include "playlist.h" 8 | #include "osd.h" 9 | #include "bass.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace Ui { 20 | class ShadowPlayer; 21 | } 22 | 23 | class ShadowPlayer : public QMainWindow 24 | { 25 | Q_OBJECT 26 | 27 | public: 28 | explicit ShadowPlayer(QWidget *parent = 0); 29 | ~ShadowPlayer(); 30 | void loadFile(QString file); 31 | void loadSkin(QString image, bool save = true); 32 | int cutInt(int i); 33 | void addToListAndPlay(QList files); 34 | void addToListAndPlay(QStringList files); 35 | void addToListAndPlay(QString file); 36 | 37 | private slots: 38 | void UpdateTime(); 39 | void UpdateLrc(); 40 | void callFromPlayList();//接受播放列表的请求,启动播放 41 | void on_openButton_clicked(); 42 | void on_playButton_clicked(); 43 | void on_stopButton_clicked(); 44 | void on_volSlider_valueChanged(int value); 45 | void on_muteButton_clicked(); 46 | void on_playSlider_sliderPressed(); 47 | void on_playSlider_sliderReleased(); 48 | void on_resetFreqButton_clicked(); 49 | void applyEQ();//应用均衡器效果 50 | void on_extraButton_clicked(); 51 | void on_closeButton_clicked(); 52 | void on_setSkinButton_clicked(); 53 | void loadDefaultSkin(); 54 | void fixSkinSizeLeft(); 55 | void fixSkinSizeFull(); 56 | void originalSkinSize(); 57 | void autoSkinSize(); 58 | void dynamicSkinSize(); 59 | void skinOnTop(); 60 | void skinOnCenter(); 61 | void skinOnButtom(); 62 | void skinDisable(); 63 | void physicsSetting(); 64 | void enableFFTPhysics(); 65 | void disableFFTPhysics(); 66 | void on_miniSizeButton_clicked(); 67 | void on_playModeButton_clicked(); 68 | void on_loadLrcButton_clicked(); 69 | void on_playSlider_valueChanged(int value); 70 | void on_freqSlider_valueChanged(int value); 71 | void on_eqComboBox_currentIndexChanged(int index); 72 | void on_playPreButton_clicked(); 73 | void on_playNextButton_clicked(); 74 | void on_playListButton_clicked(); 75 | void on_reverseButton_clicked(); 76 | void showDeveloperInfo(); 77 | void on_reverbDial_valueChanged(int value); 78 | void setTaskbarButtonWindow(); 79 | 80 | void on_eqEnableCheckBox_clicked(bool checked); 81 | 82 | public slots: 83 | void on_showDskLrcButton_clicked(); 84 | 85 | private: 86 | Ui::ShadowPlayer *ui; 87 | 88 | float arraySUM(int start, int end, float *array);//求数组平均数 89 | void UpdateFFT(); 90 | void showCoverPic(QString filePath); 91 | void infoLabelAnimation(); 92 | void drawFFTBar(QWidget *parent, int x, int y, int width, int height, double percent); 93 | void drawFFTBarPeak(QWidget *parent, int x, int y, int width, int height, double percent); 94 | void fullZero(int length, float *array);//数组填0 95 | void saveConfig(); 96 | void loadConfig(); 97 | void saveSkinData(); 98 | void loadSkinData(); 99 | 100 | Player *player; 101 | PlayList *playList; 102 | Lyrics *lyrics; 103 | OSD *osd; 104 | QTimer *timer; 105 | QTimer *lrcTimer; 106 | LrcBar *lb;//歌词窗口 107 | bool isPlaySliderPress; 108 | bool isMute;//是否静音 109 | int lastVol;//静音前的音量值 110 | float fftData[2048];//fft数据 111 | double fftBarValue[29];//存放频谱分析条的值 112 | double fftBarPeakValue[29];//存放频谱分析顶峰的值 113 | int oriFreq;//存放歌曲初始采样率 114 | bool playing;//播放?(防止歌曲无法停止,Timer判断,用于循环播放,下一曲等,false不会启动播放) 115 | 116 | QPoint pos;//用于窗口拖动,存储鼠标坐标 117 | bool clickOnFrame;//是否点击到了窗口上,用于解决瞬移BUG 118 | bool clickOnLeft;//用于调节背景图位置 119 | 120 | QPixmap skin;//用作皮肤的背景图片 121 | QPixmap skinLeft; 122 | QPixmap skinFull; 123 | double aspectRatio;//图片宽高比,用于动态缩放 124 | int skinMode;//皮肤模式 0.原始 1.左侧 2.全屏 3.自动 4.动态缩放 125 | int playMode;//播放模式 0.单曲播放 1.单曲循环 2.顺序播放 3.列表循环 4.随机播放 126 | int skinPos;//预设背景图片位置 0.显示顶端 1.显示中间 2.显示底部 127 | double skinDrawPos;//绘制背景图片时,使用的百分比位置 0 = 顶部 1 = 底部 128 | bool isReverse;//是否倒放 129 | 130 | //Windows NT 6.x 相关 131 | QWinTaskbarButton *taskbarButton; 132 | QWinTaskbarProgress *taskbarProgress; 133 | 134 | QWinThumbnailToolBar *thumbnailToolBar; 135 | QWinThumbnailToolButton *playToolButton; 136 | QWinThumbnailToolButton *stopToolButton; 137 | QWinThumbnailToolButton *backwardToolButton; 138 | QWinThumbnailToolButton *forwardToolButton; 139 | 140 | //各种动画 141 | QPropertyAnimation *sizeSlideAnimation; 142 | QPropertyAnimation *fadeInAnimation; 143 | QPropertyAnimation *tagAnimation; 144 | QPropertyAnimation *mediaInfoAnimation; 145 | QPropertyAnimation *coverAnimation; 146 | QPropertyAnimation *fadeOutAnimation; 147 | 148 | QPropertyAnimation *eqHideAnimation; 149 | QPropertyAnimation *eqShowAnimation; 150 | QPropertyAnimation *lyricsHideAnimation; 151 | QPropertyAnimation *lyricsShowAnimation; 152 | QPropertyAnimation *playListHideAnimation; 153 | QPropertyAnimation *playListShowAnimation; 154 | 155 | //渐变背景 156 | QLinearGradient bgLinearGradient; 157 | 158 | protected: 159 | void dragEnterEvent(QDragEnterEvent *event);//拖放相关 160 | void dropEvent(QDropEvent *event); 161 | 162 | void paintEvent(QPaintEvent *);//界面绘图 163 | 164 | void mousePressEvent(QMouseEvent *event);//窗体拖动相关 165 | void mouseMoveEvent(QMouseEvent *event); 166 | void mouseReleaseEvent(QMouseEvent *event); 167 | 168 | void contextMenuEvent(QContextMenuEvent *);//右键菜单 169 | void closeEvent(QCloseEvent *); 170 | void resizeEvent(QResizeEvent *); 171 | bool nativeEvent(const QByteArray &eventType, void *message, long *result); 172 | }; 173 | 174 | #endif // SHADOWPLAYER_H 175 | -------------------------------------------------------------------------------- /Sources/spslider.cpp: -------------------------------------------------------------------------------- 1 | #include "spslider.h" 2 | 3 | SPSlider::SPSlider(QWidget *parent) : 4 | QSlider(parent) 5 | { 6 | //关闭分段移动 7 | setSingleStep(0); 8 | setPageStep(0); 9 | } 10 | 11 | //点击Slider即可调节Value 12 | //只写了横向模式的Slider…… 13 | void SPSlider::mousePressEvent(QMouseEvent *event) { 14 | if (event->buttons() & Qt::LeftButton) 15 | { 16 | QSlider::mousePressEvent(event); 17 | double pos = event->pos().x() / (double)width(); 18 | setValue(pos * (maximum() - minimum()) + minimum()); 19 | } 20 | } 21 | 22 | void SPSlider::mouseMoveEvent(QMouseEvent *event) { 23 | if (event->buttons() & Qt::LeftButton) 24 | { 25 | QSlider::mousePressEvent(event); 26 | double pos = event->pos().x() / (double)width(); 27 | setValue(pos * (maximum() - minimum()) + minimum()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/spslider.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 重写的播放进度条,点击后立即跳转到指定位置 3 | */ 4 | #ifndef SPSLIDER_H 5 | #define SPSLIDER_H 6 | 7 | #include 8 | #include 9 | 10 | class SPSlider : public QSlider 11 | { 12 | Q_OBJECT 13 | public: 14 | explicit SPSlider(QWidget *parent = 0); 15 | 16 | signals: 17 | 18 | public slots: 19 | 20 | protected: 21 | void mousePressEvent(QMouseEvent *event); 22 | void mouseMoveEvent(QMouseEvent *event); 23 | }; 24 | 25 | #endif // SPSLIDER_H 26 | -------------------------------------------------------------------------------- /Sources/tags.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // 3 | // tags.h - TAGS: Yet Another Tag Reading Library for BASS 2.3+ 4 | // 5 | // Author: Wraith, 2k5-2k6 6 | // Public domain. No warranty. 7 | // 8 | // (public) 9 | // 10 | // Abstract: reads tags from given BASS handle, formats them according 11 | // to given format string and returns the resulting string. 12 | // 13 | // read tags-readme.txt for details 14 | // 15 | 16 | #ifndef _YATRL_H_W2348_H4232 17 | #define _YATRL_H_W2348_H4232 18 | 19 | // c guards (hmm... just in case) 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | // Current version. Just increments each release. 25 | #define TAGS_VERSION 17 26 | 27 | // returns description of the last error. 28 | const char* _stdcall TAGS_GetLastErrorDesc(); 29 | 30 | // main purpose of this library 31 | const char* _stdcall TAGS_Read( DWORD dwHandle, const char* fmt ); 32 | 33 | // retrieves the current version 34 | DWORD _stdcall TAGS_GetVersion(); 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /Sources/tags.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShadowPower/ShadowPlayer/d7fd0275a450609b54ca3cd211675d937c41d756/Sources/tags.lib --------------------------------------------------------------------------------