SID Player
All Classes Functions Pages
SIDStream.h
1 
8 #pragma once
9 #include <stdint.h>
10 #include "sid-api/libcsid.h"
11 #include "AudioTools.h"
12 
13 namespace audio_tools {
14 
20 struct SIDStreamConfig : public AudioInfo {
21  SIDStreamConfig() {
22  sample_rate = 22050;
23  channels = 2;
24  bits_per_sample = 16;
25  }
26  int sid_model = 6581;
27  const unsigned char *tune_data = nullptr;
28  int tune_data_length = 0;
29  int subtune = 0;
30 };
31 
38 struct SIDMetadata {
39  char title[32] = {0};
40  char author[32] = {0};
41  char sid_info[32] = {0};
42  uint8_t total_tunes;
43  uint8_t default_tune;
44 
45  void logInfo() {
46  LOGI("SID Title: %s", title);
47  LOGI("SID Author: %s", author);
48  LOGI("SID Info: %s", sid_info);
49  LOGI("SID Number of tunes: %d", total_tunes);
50  LOGI("SID Default tune: %d", default_tune);
51  }
52 };
53 
59 class SIDStream : public AudioStream {
60 
61 public:
66  SIDStream() = default;
74  SIDStream(const unsigned char *tunedata, int tunedatalen, int subtune = 0) {
75  cfg.tune_data = tunedata;
76  cfg.tune_data_length = tunedatalen;
77  cfg.subtune = subtune;
78  }
79 
83  return c;
84  }
85 
86  bool begin(SIDStreamConfig config) {
87  TRACEI();
88  if (config.bits_per_sample!=16){
89  LOGE("bits_per_sample %d: must be 16", config.bits_per_sample);
90  return false;
91  }
92  // save tune_data from constructor
93  if (config.tune_data == nullptr && cfg.tune_data != nullptr) {
94  config.tune_data = cfg.tune_data;
95  config.tune_data_length = cfg.tune_data_length;
96  }
97  // Use subtune from constructor if not reqeusted by begin
98  if (config.subtune==0 && cfg.subtune!=0){
99  config.subtune = cfg.subtune;
100  }
101  this->cfg = config;
102  this->frame_size = sizeof(int16_t) * cfg.channels;
103 
104  // allocate memory and setup processing
105  libcsid_init(cfg.sample_rate, cfg.sid_model);
106 
107  // start to play default song
108  if (cfg.tune_data != nullptr) {
109  setSID(cfg.tune_data, cfg.tune_data_length, cfg.subtune);
110  } else {
111  LOGI("call setSID()");
112  }
113 
114  return true;
115  }
116 
118  void end() override {
119  TRACEI();
120  active = false;
121  libcsid_free();
122  }
123 
128  void setSID(const unsigned char *tunedata, int tunedatalen, int subtune = 0) {
129  LOGI("setSID len %d, subtune: %d", tunedatalen, subtune);
130  active = true;
131  // update tune in cfg
132  cfg.tune_data = tunedata;
133  cfg.tune_data_length = tunedatalen;
134 
135  // load song
136  libcsid_load((unsigned char *)tunedata, tunedatalen);
137 
138  // save metadata
139  memcpy(meta.author, libcsid_getauthor(), sizeof(meta.author));
140  memcpy(meta.title, libcsid_gettitle(), sizeof(meta.author));
141  memcpy(meta.sid_info, libcsid_getinfo(), sizeof(meta.sid_info));
142  meta.total_tunes = libcsid_get_total_tunes_number();
143  meta.default_tune = libcsid_get_default_tune_number();
144  setTune(subtune);
145  }
146 
147  void setTune(int subtune = 0) {
148  if (!active)
149  return;
150  LOGI("setTune: %d", subtune);
151  cfg.subtune = subtune;
152  meta.logInfo();
153  libcsid_play(cfg.subtune);
154  }
155 
157  size_t readBytes(uint8_t *buffer, size_t bytes) override {
158  // return when not active
159  if (!active)
160  return 0;
161 
162  // check for acceptable size
163  if (bytes<frame_size){
164  LOGE("readBytes: %d - too small", bytes);
165  return 0;
166  }
167 
168  // request is valid
169  LOGD("readBytes %d", bytes);
170  size_t result = 0;
171  int16_t *ptr = (int16_t *)buffer;
172  int frames = bytes / frame_size;
173  for (int j = 0; j < frames; j++) {
174  int16_t sample = readSample();
175  for (int i = 0; i < cfg.channels; i++) {
176  *ptr++ = sample;
177  result += 2;
178  }
179  }
180 
181  updateTimeOfLastSound((int16_t*)buffer, bytes/2);
182  return result;
183  }
184 
186  SIDMetadata getMetadata() { return meta; }
187  SIDStreamConfig getStreamConfigdata() { return cfg; }
188 
192  bool isActive(int timeoutMs=2000) {
193  return active && (time_of_last_sound > millis() - timeoutMs);
194  }
195 
196 protected:
197  SIDStreamConfig cfg;
198  SIDMetadata meta;
199  bool active = false;
200  uint8_t frame_size;
201  uint64_t time_of_last_sound = 0;
202 
204  int16_t readSample() {
205  unsigned short result;
206 
207  libcsid_render(&result, 1);
208 
209  return ((int16_t)result);
210  }
211 
212  void updateTimeOfLastSound(int16_t *data, int len){
213  for (int j=0;j<len;j++){
214  if (data[j]!=0){
215  time_of_last_sound = millis();
216  break;
217  }
218  }
219  }
220 
221 };
222 
223 } // namespace audio_tools
Provides SID audio data.
Definition: SIDStream.h:59
void setSID(const unsigned char *tunedata, int tunedatalen, int subtune=0)
Loads the tune to be played and starts generating audio.
Definition: SIDStream.h:128
size_t readBytes(uint8_t *buffer, size_t bytes) override
fill the data with 2 channels
Definition: SIDStream.h:157
SIDMetadata getMetadata()
Provide the metadata for the sid.
Definition: SIDStream.h:186
void end() override
Stops processing and releases the memory.
Definition: SIDStream.h:118
bool isActive(int timeoutMs=2000)
Definition: SIDStream.h:192
int16_t readSample()
Provides a single sample.
Definition: SIDStream.h:204
SIDStream()=default
Construct a new SIDStream object To play a song call begin() and then setSID()
SIDStream(const unsigned char *tunedata, int tunedatalen, int subtune=0)
Construct a new SIDStream object To play a song just call begin()
Definition: SIDStream.h:74
SIDStreamConfig defaultConfig()
Provides the default configuration.
Definition: SIDStream.h:81
Title and Author from the SID.
Definition: SIDStream.h:38
Configuration data for a SIDStream.
Definition: SIDStream.h:20