lsnes rr2-β24
[lsnes.git] / src / emulation / sky / music.cpp
blob16f230b9fd9fb1273749670076d2b935153b267a
1 #include "music.hpp"
2 #include <cstring>
3 #include <iomanip>
4 #include <cmath>
5 #include "library/hex.hpp"
6 #include "library/minmax.hpp"
7 #include "library/ogg.hpp"
8 #include "library/opus-ogg.hpp"
9 #include "library/string.hpp"
10 #include "core/messages.hpp"
11 #include "state.hpp"
13 namespace sky
15 struct downmix_pair
17 float l;
18 float r;
21 struct song_buffer;
22 const uint64_t past_end = 0xFFFFFFFFFFFFFFFFULL;
24 //These values are taken from libopusfile.
25 const downmix_pair downmix[] = {
26 {16384,16384},
27 {16384,0},{0,16384},
28 {9598,0},{6786,6786},{0,9598},
29 {6924,0},{0,6924}, {5996,3464}, {3464,5996},
30 {10666,0},{7537,7537},{0,10666},{9234,5331},{5331,9234},
31 {8668,0},{6129,6129},{0,8668},{7507,4335},{4335,7507},{6129,6129},
32 {7459,0},{5275,5275},{0,7459},{6460,3731},{3731,6460},{4568,4568},{5275,5275},
33 {6368,0},{4502,4502},{0,6368},{5515,3183},{3183,5515},{5515,3183},{3183,5515},{4502,4502}
36 const size_t downmix_idx[9] = {0, 0, 1, 3, 6, 10, 15, 21, 28};
38 uint32_t pick_subsong(random& rng, const std::set<uint32_t>& candidates)
40 if(candidates.empty())
41 return 0;
42 if(candidates.size() == 1)
43 return *candidates.begin();
44 uint32_t r = rng.pull();
45 r %= candidates.size();
46 for(auto i : candidates)
47 if(!(r--))
48 return i;
49 return 0;
52 void fill_msc_downmix_family0(struct multistream_characteristics& c, unsigned chan)
54 if(chan < 1 || chan > 2)
55 (stringfmt() << "Illegal channel count " << chan << " for map family 0").throwex();
56 for(unsigned i = 0; i < chan; i++) {
57 c.downmix_l[i] = downmix[i + downmix_idx[chan]].l;
58 c.downmix_r[i] = downmix[i + downmix_idx[chan]].r;
62 void fill_msc_downmix_family1(struct multistream_characteristics& c, unsigned chan)
64 if(chan < 1 || chan > 8)
65 (stringfmt() << "Illegal channel count " << chan << " for map family 1").throwex();
66 for(unsigned i = 0; i < chan; i++) {
67 c.downmix_l[i] = downmix[i + downmix_idx[chan]].l;
68 c.downmix_r[i] = downmix[i + downmix_idx[chan]].r;
72 void fill_msc_from_header(struct multistream_characteristics& c, const opus::ogg_header& h)
74 c.channels = h.channels;
75 c.gain = h.gain;
76 c.streams = h.streams;
77 c.coupled = h.coupled;
78 memcpy(c.mapping, h.chanmap, 255);
79 if(h.map_family == 0)
80 fill_msc_downmix_family0(c, c.channels);
81 else if(h.map_family == 1)
82 fill_msc_downmix_family1(c, c.channels);
83 else
84 (stringfmt() << "Unsupported map family " << (int)h.map_family).throwex();
87 multistream_characteristics::multistream_characteristics()
89 channels = 1;
90 gain = 0;
91 streams = 1;
92 coupled = 0;
93 mapping[0] = 0;
94 fill_msc_downmix_family0(*this, 1);
97 subsong_transition::subsong_transition()
99 start_pts = past_end;
100 xfade_pts = past_end;
101 end_pts = past_end;
104 void subsong_transition::fixup(uint64_t pregap, uint64_t datalen, const std::string& ssname)
106 if(start_pts == past_end)
107 start_pts = pregap;
108 if(end_pts == past_end)
109 end_pts = datalen;
110 if(xfade_pts == past_end)
111 xfade_pts = end_pts;
112 if(end_pts < start_pts || end_pts > datalen) {
113 messages << "Warning: [" << ssname << "] Ending PTS out of range, clipped to the end."
114 << std::endl;
115 end_pts = datalen;
117 if(xfade_pts < start_pts || xfade_pts > end_pts) {
118 messages << "Warning: [" << ssname << "] Fade PTS out of range, clipped to the end."
119 << std::endl;
120 xfade_pts = datalen;
122 if(start_pts >= end_pts) {
123 messages << "Warning: [" << ssname << "] Start PTS out of range, clipped to the start."
124 << std::endl;
125 xfade_pts = pregap;
129 uint32_t song_buffer::register_lsid(const std::string& ssid)
131 if(ssid_to_lsid.count(ssid))
132 return ssid_to_lsid[ssid];
133 auto dummy = stransitions[next_lsid];
134 ssid_to_lsid[ssid] = next_lsid++;
135 return ssid_to_lsid[ssid];
138 uint32_t song_buffer::register_lsid(const std::string& ssid, uint32_t psid)
140 if(ssid_to_lsid.count(ssid)) {
141 lsid_to_psid[ssid_to_lsid[ssid]] = psid;
142 return ssid_to_lsid[ssid];
144 auto dummy = stransitions[next_lsid];
145 lsid_to_psid[next_lsid] = psid;
146 ssid_to_lsid[ssid] = next_lsid++;
147 return ssid_to_lsid[ssid];
150 void song_buffer::delete_undefined_substreams()
152 bool deleted = false;
153 do {
154 deleted = false;
155 for(auto& i : ssid_to_lsid) {
156 uint32_t lsid = i.second;
157 if(!lsid_to_psid.count(lsid)) {
158 //This needs to be deleted.
159 stransitions.erase(lsid);
160 ssid_to_lsid.erase(i.first);
161 deleted = true;
162 break;
165 } while(deleted);
168 void song_buffer::delete_stream(uint32_t psid)
170 bool deleted = false;
171 do {
172 deleted = false;
173 for(auto& i : ssid_to_lsid) {
174 uint32_t lsid = i.second;
175 if(lsid_to_psid.count(lsid) && lsid_to_psid[lsid] == psid) {
176 //This needs to be deleted.
177 stransitions.erase(lsid);
178 lsid_to_psid.erase(lsid);
179 ssid_to_lsid.erase(i.first);
180 deleted = true;
181 break;
184 } while(deleted);
185 mscharacteristics.erase(psid);
186 auto key1 = std::make_pair(psid, 0ULL);
187 auto key2 = std::make_pair(psid + 1, 0ULL);
188 std::map<std::pair<uint32_t, uint64_t>, std::vector<uint8_t>>::iterator itr1;
189 while((itr1 = packetdata.lower_bound(key1)) != packetdata.lower_bound(key2))
190 packetdata.erase(itr1);
193 std::string song_buffer::reverse_lsid(uint32_t lsid)
195 for(auto& i : ssid_to_lsid)
196 if(i.second == lsid)
197 return i.first;
198 return "";
201 const std::vector<uint8_t>& song_buffer::get_packet(uint32_t subsong, uint64_t pts)
203 if(!lsid_to_psid.count(subsong))
204 return dummy_packet;
205 std::pair<uint32_t, uint64_t> ptsx = std::make_pair(lsid_to_psid[subsong], pts);
206 if(!packetdata.count(ptsx))
207 return dummy_packet;
208 return packetdata[ptsx];
211 uint64_t song_buffer::next_timecode(uint32_t subsong, uint64_t pts)
213 if(!lsid_to_psid.count(subsong))
214 return past_end;
215 std::pair<uint32_t, uint64_t> ptsx = std::make_pair(lsid_to_psid[subsong], pts);
216 if(ptsx.second == past_end || packetdata.empty())
217 return past_end;
218 auto i = packetdata.lower_bound(ptsx);
219 if(i == packetdata.end())
220 return past_end;
221 else {
222 uint32_t psid = i->first.first;
223 if(psid == lsid_to_psid[subsong])
224 return i->first.second;
225 else
226 return past_end;
230 uint64_t song_buffer::prev_timecode(uint32_t subsong, uint64_t pts)
232 if(!lsid_to_psid.count(subsong))
233 return past_end;
234 std::pair<uint32_t, uint64_t> ptsx = std::make_pair(lsid_to_psid[subsong], pts);
235 if(ptsx.second == past_end || packetdata.empty())
236 return past_end;
237 auto i = packetdata.upper_bound(ptsx);
238 if(i == packetdata.end()) {
239 uint32_t psid = packetdata.rbegin()->first.first;
240 if(psid == lsid_to_psid[subsong])
241 return packetdata.rbegin()->first.second;
242 else
243 return past_end;
244 } else {
245 i--;
246 uint32_t psid = i->first.first;
247 if(psid == lsid_to_psid[subsong])
248 return i->first.second;
249 else
250 return past_end;
254 song_buffer::song_buffer(std::istream& stream)
256 next_lsid = 0;
257 ogg::stream_reader_iostreams r(stream);
258 r.set_errors_to(messages);
259 ogg::page p;
260 std::map<uint32_t, subsong_context> psids;
261 uint32_t next_psid = 0;
262 while(r.get_page(p))
263 if(page_starts_new_stream(p)) {
264 uint32_t psid = next_psid++;
265 psids[psid].psid = psid;
266 psids[psid].oggid = p.get_stream();
267 parse_ogg_page(p, psids[psid]);
268 } else
269 for(auto& i : psids)
270 if(parse_ogg_page(p, i.second) && p.get_eos()) {
271 if(i.second.pts <= i.second.pregap) {
272 //Invalid or blank stream.
273 messages << "Warning: " << p.stream_debug_id() << " has "
274 << "length <= 0. Ignoring stream." << std::endl;
275 psids.erase(i.first);
276 //Also erase all associated lsids.
277 delete_stream(i.first);
278 break;
279 } else
280 i.second.eos_seen = true;
282 for(auto& i : psids)
283 if(!i.second.eos_seen)
284 messages << "Warning: No EOS on stream " << hex::to(i.second.oggid, true)
285 << std::endl;
286 delete_undefined_substreams();
287 if(ssid_to_lsid.empty())
288 throw std::runtime_error("No valid Oggopus streams found");
289 for(auto& i : ssid_to_lsid) {
290 uint32_t psid = lsid_to_psid[i.second];
291 uint32_t next_psid = 0;
292 uint32_t default_lsid;
293 //Look up known psids.
294 if(mscharacteristics.upper_bound(psid) != mscharacteristics.end())
295 next_psid = mscharacteristics.upper_bound(psid)->first;
296 else
297 next_psid = mscharacteristics.begin()->first;
298 default_lsid = ssid_to_lsid[(stringfmt() << "PSID" << next_psid).str()];
299 bool deleted = false;
300 do {
301 deleted = false;
302 for(auto& j : stransitions[i.second].next_subsongs)
303 if(!lsid_to_psid.count(j)) {
304 messages << "Warning: Undefined reference from '" << i.first
305 << "' to '" << reverse_lsid(j) << "'" << std::endl;
306 stransitions[i.second].next_subsongs.erase(j);
307 deleted = true;
308 break;
310 } while(deleted);
311 if(stransitions[i.second].next_subsongs.empty())
312 stransitions[i.second].next_subsongs.insert(default_lsid);
313 stransitions[i.second].fixup(psids[psid].pregap, psids[psid].pts, i.first);
315 if(entry.empty()) {
316 for(auto& i : mscharacteristics) {
317 entry.insert(ssid_to_lsid[(stringfmt() << "PSID" << i.first).str()]);
321 for(auto& i : ssid_to_lsid) {
322 std::cerr << "SSID: " << i.first << " (#" << i.second << ") Start: "
323 << stransitions[i.second].start_pts / 48 << "ms Fade:"
324 << stransitions[i.second].xfade_pts / 48 << "ms End:"
325 << stransitions[i.second].end_pts / 48 << "ms"
326 << (entry.count(i.second) ? " ENTRYPOINT" : "") << std::endl;
327 std::cerr << "\tNext up\t";
328 bool f = true;
329 for(auto& j : stransitions[i.second].next_subsongs) {
330 std::cerr << (f ? "" : ",") << reverse_lsid(j);
331 f = false;
333 uint32_t psid = lsid_to_psid[i.second];
334 std::cerr << std::endl << "\tPhysical stream (PSID#" << psid << ", Ogg stream " <<
335 hex::to(psids[psid].oggid) << "):" << std::endl;
336 auto c = mscharacteristics[psid];
337 std::cerr << "\t\t" << (int)c.channels << " channels (" << (int)c.streams << " streams, "
338 << (int)c.coupled << " coupled) @" << (c.gain / 256.0) << "dB" << std::endl;
339 std::cerr << "\t\tPregap " << psids[psid].pregap / 48 << "ms, length " << psids[psid].pts / 48
340 << "ms." << std::endl;
345 song_buffer::subsong_context::subsong_context()
346 : demux(messages)
348 psid = 0xDEADBEEF;
349 last_granule = 0;
350 pts = 0;
351 last_pts = 0;
352 pages = 0;
353 eos_seen = false;
356 void song_buffer::fill_ms_characteristics(uint32_t subsong, struct multistream_characteristics& c)
358 if(!lsid_to_psid.count(subsong)) {
359 c = multistream_characteristics();
360 return;
362 subsong = lsid_to_psid[subsong];
363 if(mscharacteristics.count(subsong))
364 c = mscharacteristics[subsong];
365 else
366 c = multistream_characteristics();
369 const struct subsong_transition& song_buffer::transitions(uint32_t subsong)
371 if(stransitions.count(subsong))
372 return stransitions[subsong];
373 else
374 return dummy_transition;
377 bool song_buffer::page_starts_new_stream(ogg::page& p)
379 if(!p.get_bos() || p.get_packet_count() != 1)
380 return false;
381 auto pkt = p.get_packet(0);
382 if(pkt.second < 8 || memcmp(pkt.first, "OpusHead", 8))
383 return false;
384 return true;
387 bool song_buffer::parse_ogg_page(ogg::page& page, subsong_context& ctx)
389 ogg::packet p;
390 if(!ctx.demux.page_in(page))
391 return false;
392 while(ctx.demux.wants_packet_out()) {
393 ctx.demux.packet_out(p);
394 if(ctx.pages == 0) {
395 parse_ogg_header(p, ctx);
396 ctx.pages = 1;
397 } else if(ctx.pages == 1) {
398 parse_ogg_tags(p, ctx, page);
399 ctx.pages = 2;
400 } else
401 parse_ogg_data(p, ctx, page);
403 if(ctx.pages > 1)
404 ctx.pages++;
405 return true;
408 void song_buffer::parse_ogg_header(ogg::packet& p, subsong_context& ctx)
410 struct opus::ogg_header h;
411 h.parse(p);
412 fill_msc_from_header(mscharacteristics[ctx.psid], h);
413 ctx.pregap = h.preskip;
414 ctx.gain = h.gain;
417 void song_buffer::parse_ogg_tags(ogg::packet& p, subsong_context& ctx, const ogg::page& debug)
419 struct opus::ogg_tags t;
420 t.parse(p);
421 for(auto& i : t.comments) {
422 try {
423 regex_results r = regex("SKY-([^-]+)-([^=]+)=(.*)", i);
424 if(!r)
425 continue;
426 uint32_t lsid = register_lsid(r[2], ctx.psid);
427 if(r[1] == "START")
428 stransitions[lsid].start_pts = parse_value<uint64_t>(r[3]) + ctx.pregap;
429 if(r[1] == "FADE")
430 stransitions[lsid].xfade_pts = parse_value<uint64_t>(r[3]) + ctx.pregap;
431 if(r[1] == "END")
432 stransitions[lsid].end_pts = parse_value<uint64_t>(r[3]) + ctx.pregap;
433 if(r[1] == "NEXT") {
434 std::string next = r[3];
435 for(auto& token : token_iterator<char>::foreach(next, {","})) {
436 uint32_t lsid2 = register_lsid(token);
437 stransitions[lsid].next_subsongs.insert(lsid2);
440 if(r[1] == "ENTRY") {
441 entry.insert(lsid);
443 } catch(std::exception& e) {
444 messages << "Warning: " << debug.stream_debug_id() << " tag '" << i << "': "
445 << e.what() << std::endl;
448 //Make sure substream 0 exits.
449 register_lsid((stringfmt() << "PSID" << ctx.psid).str(), ctx.psid);
452 void song_buffer::parse_ogg_data(ogg::packet& p, subsong_context& ctx, const ogg::page& debug)
454 std::pair<uint32_t, uint64_t> ptsx = std::make_pair(ctx.psid, ctx.pts);
455 packetdata[ptsx] = p.get_vector();
456 uint8_t t = opus::packet_tick_count(&packetdata[ptsx][0], packetdata[ptsx].size());
457 ctx.pts += 120 * t;
458 if(p.get_last_page()) {
459 uint64_t samples = p.get_granulepos() - ctx.last_granule;
460 if(samples > ctx.pts - ctx.last_pts) {
461 //If there is only one data page, it is assumed to have zero base granulepos.
462 //But for multiple pages, the first granulepos is arbitrary.
463 if(ctx.pages > 2 || p.get_on_eos_page())
464 messages << "Warning: " << debug.page_debug_id() << " Granulepos says there "
465 << "are " << samples << " samples, found " << ctx.pts - ctx.last_pts
466 << std::endl;
467 } else if(p.get_on_eos_page())
468 //On EOS page, clip.
469 ctx.pts = ctx.last_pts + samples;
470 else if(samples < ctx.pts - ctx.last_pts)
471 messages << "Warning: " << debug.page_debug_id() << " Granulepos says there are "
472 << samples << " samples, found " << ctx.pts - ctx.last_pts
473 << std::endl;
474 ctx.last_pts = ctx.pts;
475 ctx.last_granule = p.get_granulepos();
479 packet_decoder::packet_decoder()
481 d = NULL;
482 channels = 0;
485 void packet_decoder::set_multistream(const struct multistream_characteristics& c)
487 try {
488 size_t msstate_size = opus::multistream_decoder::size(c.streams, c.coupled);
489 msstate_size += sizeof(opus::multistream_decoder) + alignof(opus::multistream_decoder);
490 size_t dmix_offset = msstate_size;
491 msstate_size += 5760 * c.channels * sizeof(float);
492 if(memory.size() < msstate_size)
493 memory.resize(msstate_size);
494 uint8_t* a = &memory[0];
495 if(reinterpret_cast<uint64_t>(a) % alignof(opus::multistream_decoder))
496 a++;
497 uint8_t* b = a + sizeof(opus::multistream_decoder);
498 d = new(a) opus::multistream_decoder(opus::samplerate::r48k, c.channels, c.streams, c.coupled,
499 c.mapping, reinterpret_cast<char*>(b));
500 dmem = reinterpret_cast<float*>(a + dmix_offset);
501 channels = c.channels;
502 float gain_factor = 2 * pow(10, c.gain / 5120.0);
503 for(unsigned i = 0; i < channels; i++) {
504 downmix_l[i] = gain_factor * c.downmix_l[i];
505 downmix_r[i] = gain_factor * c.downmix_r[i];
507 } catch(opus::not_loaded l) {
508 d = NULL;
509 channels = c.channels;
513 void packet_decoder::decode_packet(const std::vector<uint8_t>& data)
515 size_t s = 120;
516 try {
517 if(d)
518 s = d->decode(&data[0], data.size(), dmem, 5760);
519 else {
520 //Insert silence.
521 uint8_t ticks = opus::packet_tick_count(&data[0], data.size());
522 if(!ticks)
523 ticks = 1; //Try to recover.
524 memset(pcmbuf, 0, 240 * ticks * sizeof(int16_t));
525 pcmpos = 0;
526 pcmlen = 120 * ticks;
527 return;
529 } catch(std::exception& e) {
530 //Try to insert silence.
531 messages << "Failed to decode opus packet: " << e.what() << std::endl;
532 uint8_t ticks = opus::packet_tick_count(&data[0], data.size());
533 if(!ticks)
534 ticks = 1; //Try to recover.
535 memset(pcmbuf, 0, 240 * ticks * sizeof(int16_t));
536 pcmpos = 0;
537 pcmlen = 120 * ticks;
538 return;
540 for(unsigned i = 0; i < s; i++) {
541 float a = 0;
542 float b = 0;
543 for(unsigned j = 0; j < channels; j++) {
544 a += downmix_l[j] * dmem[i * channels + j];
545 b += downmix_r[j] * dmem[i * channels + j];
547 pcmbuf[2 * i + 0] = min(max((int32_t)a, -32768), 32767);
548 pcmbuf[2 * i + 1] = min(max((int32_t)b, -32768), 32767);
550 pcmpos = 0;
551 pcmlen = s;
554 void packet_decoder::reset()
556 try {
557 if(d)
558 d->ctl(opus::reset);
559 } catch(opus::not_loaded e) {
563 music_player::music_player(struct music_player_memory& m, random& _rng)
564 : mem(m), rng(_rng)
566 song = NULL;
569 void music_player::seek_channel(packet_decoder& i, uint64_t& spts, uint32_t subsong, uint64_t pts)
571 if(pts == past_end) {
572 i.pcmpos = i.pcmlen = 0;
573 spts = past_end;
574 return;
576 i.reset();
577 uint64_t ptsr = song->prev_timecode(subsong, (pts >= 3840) ? (pts - 3840) : 0);
578 while(ptsr < pts) {
579 ptsr = song->next_timecode(subsong, ptsr);
580 if(ptsr == past_end)
581 break;
582 i.decode_packet(song->get_packet(subsong, ptsr));
583 if(ptsr + i.pcmlen > pts) {
584 i.pcmpos = pts - ptsr;
585 ptsr = pts;
586 } else
587 ptsr += i.pcmlen;
589 spts = pts;
592 void music_player::song_to_beginning()
594 mem.pcmpos2 = past_end;
595 mem.subsong2 = 0;
596 if(!song) {
597 mem.subsong1 = 0;
598 mem.pcmpos1 = past_end;
599 return;
601 const std::set<uint32_t>& songs = song->entrypoints();
602 mem.subsong1 = pick_subsong(rng, songs);
603 mem.pcmpos1 = song->transitions(mem.subsong1).start_pts;
606 void music_player::do_preroll()
608 multistream_characteristics c1, c2;
609 if(song) {
610 song->fill_ms_characteristics(mem.subsong1, c1);
611 song->fill_ms_characteristics(mem.subsong2, c2);
613 i1.set_multistream(c1);
614 i2.set_multistream(c2);
615 if(!song)
616 return;
617 uint64_t pts1p;
618 uint64_t pts2p;
619 seek_channel(i1, pts1p, mem.subsong1, mem.pcmpos1);
620 seek_channel(i2, pts2p, mem.subsong2, mem.pcmpos2);
623 void music_player::decode(std::pair<int16_t, int16_t>* output, size_t samples)
625 if(!song) {
626 memset(output, 0, samples * sizeof(std::pair<int16_t, int16_t>));
627 return;
629 const subsong_transition* strans1 = &song->transitions(mem.subsong1);
630 const subsong_transition* strans2 = &song->transitions(mem.subsong2);
631 for(; samples > 0; output++, samples--) {
632 if(strans1->xfade_pts == mem.pcmpos1) {
633 mem.subsong2 = pick_subsong(rng, strans1->next_subsongs);
634 const subsong_transition& st = song->transitions(mem.subsong2);
635 seek_channel(i2, mem.pcmpos2, mem.subsong2, st.start_pts);
636 strans2 = &song->transitions(mem.subsong2);
638 if(strans2->xfade_pts == mem.pcmpos2) {
639 mem.subsong1 = pick_subsong(rng, strans2->next_subsongs);
640 const subsong_transition& st = song->transitions(mem.subsong1);
641 seek_channel(i1, mem.pcmpos1, mem.subsong1, st.start_pts);
642 strans1 = &song->transitions(mem.subsong1);
644 if(strans1->end_pts == mem.pcmpos1)
645 seek_channel(i1, mem.pcmpos1, mem.subsong1, past_end);
646 if(strans2->end_pts == mem.pcmpos2)
647 seek_channel(i2, mem.pcmpos2, mem.subsong2, past_end);
648 if(i1.pcmpos == i1.pcmlen && mem.pcmpos1 != past_end) {
649 uint64_t pts = song->next_timecode(mem.subsong1, mem.pcmpos1);
650 if(pts != past_end)
651 i1.decode_packet(song->get_packet(mem.subsong1, mem.pcmpos1));
653 if(i2.pcmpos == i2.pcmlen && mem.pcmpos2 != past_end) {
654 uint64_t pts = song->next_timecode(mem.subsong2, mem.pcmpos2);
655 if(pts != past_end)
656 i2.decode_packet(song->get_packet(mem.subsong2, mem.pcmpos2));
658 int32_t cf = 0, icf = 0;
659 if(mem.pcmpos1 >= strans1->end_pts)
660 icf = 256;
661 else if(mem.pcmpos2 >= strans2->end_pts)
662 cf = 256;
663 else if(strans1->xfade_pts < mem.pcmpos1) {
664 uint64_t cfstart = strans1->xfade_pts;
665 uint64_t cflen = strans1->end_pts - strans1->xfade_pts;
666 cf = 256 - 256 * (mem.pcmpos1 - cfstart) / cflen;
667 icf = 256 - cf;
668 } else if(strans2->xfade_pts < mem.pcmpos2) {
669 uint64_t cfstart = strans2->xfade_pts;
670 uint64_t cflen = strans2->end_pts - strans2->xfade_pts;
671 icf = 256 - 256 * (mem.pcmpos2 - cfstart) / cflen;
672 cf = 256 - icf;
674 int32_t l = (cf * i1.pcmbuf[2 * i1.pcmpos + 0] + icf * i2.pcmbuf[2 * i2.pcmpos + 0]) >> 8;
675 int32_t r = (cf * i1.pcmbuf[2 * i1.pcmpos + 1] + icf * i2.pcmbuf[2 * i2.pcmpos + 1]) >> 8;
676 output->first = max(min(l, 32767), -32768);
677 output->second = max(min(r, 32767), -32768);
678 if(i1.pcmpos < i1.pcmlen)
679 i1.pcmpos++;
680 if(i2.pcmpos < i2.pcmlen)
681 i2.pcmpos++;
682 if(mem.pcmpos1 != past_end)
683 mem.pcmpos1++;
684 if(mem.pcmpos2 != past_end)
685 mem.pcmpos2++;