-
Notifications
You must be signed in to change notification settings - Fork 0
/
playback.h
137 lines (114 loc) · 3.32 KB
/
playback.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//
// Created by jason on 2020/8/9.
//
#ifndef JMP123_PLAYBACK_H
#define JMP123_PLAYBACK_H
#include <decoder/audio_interface.h>
#include <filesystem>
#include <fstream>
#include "decoder/header.h"
#include "decoder/layer123.h"
#include "decoder/layer_1.h"
#include "decoder/layer_2.h"
#include "decoder/layer_3.h"
namespace jmp123 {
class Playback {
constexpr static int BUFLEN = 8192;
std::vector<uint8_t> buf{};
bool eof{false}, paused{false};
// RandomRead instream;
std::ifstream instream;
// ID3Tag id3tag;
int off{}, maxOff{};
decoder::Header header;
std::unique_ptr<decoder::IAudio> audio;
float currentVolume = 0.0f;
decoder::LayerI_II_III* layer{};
public:
Playback(std::unique_ptr<decoder::IAudio> audio)
: audio(std::move(audio)), header(), buf(BUFLEN) {
// id3tag = new ID3Tag();
}
~Playback() { delete layer; }
bool Open(std::string name, std::string title) {
maxOff = 8192;
off = 0;
paused = eof = false;
instream = std::ifstream(name, std::ifstream::binary);
auto size = std::filesystem::file_size(name);
header.Initialize(size, 0);
NextHeader();
audio->Open(header, nullptr);
if (eof) return false;
return true;
}
bool Start(bool verbose) {
using namespace decoder;
layer = nullptr;
int frames = 0;
paused = false;
audio.get()->Start(true);
switch (header.GetLayer()) {
case 1:
layer = new LayerI(std::move(header), std::move(audio));
break;
case 2:
layer = new LayerII(std::move(header), std::move(audio));
break;
case 3:
layer = new LayerIII(std::move(header), std::move(audio));
break;
default:
return false;
}
while (!eof) {
// 1. 解码一帧并输出(播放)
off = layer->DecodeFrame(buf, off);
// auto a = layer->DecodeFrame(buf, off);
if (verbose && (++frames & 0x7) == 0) {
try {
header.PrintProgress();
}catch (std::exception e) {
std::cout << e.what() << "\n";
}
}
// 2. 定位到下一帧并解码帧头
NextHeader();
// 3. 检测并处理暂停
if (paused) {
while (paused && !eof)
;
}
}
if (verbose) {
try {
header.PrintProgress();
} catch (std::exception e) {
std::cout << e.what() << "\n";
}
std::cout << std::endl;
}
return true;
}
//====================================================================
void NextHeader() {
int len = 0, chunk = 0;
while (!eof && !header.SyncFrame(buf, off, maxOff)) {
// buf内帧同步失败或数据不足一帧,刷新缓冲区buf
off = header.Offset();
len = maxOff - off;
// System.arraycopy(buf, off, buf, 0, len);
memmove(buf.data(), buf.data() + off, len);
// instream.read(reinterpret_cast<char*>(buf.data() + len), off);
char* b = static_cast<char*>(alloca(off));
instream.read(b, off);
memcpy(buf.data() + len, b, off);
maxOff = len + instream.gcount();
off = 0;
if (maxOff <= len || (chunk += BUFLEN) > 0x10000) eof = true;
}
off = header.Offset();
}
};
} // namespace jmp123
#endif // JMP123_PLAYBACK_H