/** * Furnace Tracker - multi-system chiptune tracker * Copyright (C) 2021-2025 tildearrow and contributors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "filePlayer.h" #include "../ta-log.h" #include #define DIV_FPCACHE_BLOCK_SHIFT 16 #define DIV_FPCACHE_BLOCK_SIZE (1U<>DIV_FPCACHE_BLOCK_SHIFT; size_t lastBlock=firstBlock+DIV_FPCACHE_BLOCKS_FROM_FILL; if (lastBlock>=numBlocks) lastBlock=numBlocks-1; // don't read if we're after end of file if (firstBlock>lastBlock) return; bool needToFill=false; for (size_t i=firstBlock; i<=lastBlock; i++) { if (!blocks[i]) { needToFill=true; firstBlock=i; break; } } if (!needToFill) return; // check whether we need to seek sf_count_t curSeek=sf_seek(sf,0,SEEK_CUR); if (curSeek==-1) { // I/O error fileError=true; return; } if ((curSeek&DIV_FPCACHE_BLOCK_MASK)!=0 || (((size_t)curSeek)>>DIV_FPCACHE_BLOCK_SHIFT)!=firstBlock) { // we need to seek logV("- seeking"); // we seek to a previous position in order to compensate for possible decoding differences when seeking // (usually in lossy codecs) sf_count_t seekWhere=firstBlock<>DIV_FPCACHE_BLOCK_SHIFT; if (blockIndex!=lastBlock) { fillBlocksNear(playPos); lastBlock=blockIndex; } if (blockIndex>=numBlocks) { // stop here for (int j=0; j=si.channels) { buf[j][i]=0.0f; } else { buf[j][i]=block[posInBlock++]*volume; } } } // advance rateAccum+=si.samplerate; while (rateAccum>=outRate) { rateAccum-=outRate; playPos++; if (playPos>=(size_t)si.frames) { playPos=0; } } } else { for (int j=0; j>DIV_FPCACHE_BLOCK_SHIFT]!=NULL); } bool DivFilePlayer::isLoaded() { return (sf!=NULL); } bool DivFilePlayer::isPlaying() { return playing; } void DivFilePlayer::play(unsigned int offset) { logV("DivFilePlayer: playing"); playing=true; } void DivFilePlayer::stop(unsigned int offset) { logV("DivFilePlayer: stopping"); playing=false; } bool DivFilePlayer::closeFile() { if (sf==NULL) return false; sfw.doClose(); sf=NULL; playing=false; for (size_t i=0; i>DIV_FPCACHE_BLOCK_SHIFT; blocks=new float*[numBlocks]; memset(blocks,0,numBlocks*sizeof(void*)); playPos=0; lastBlock=SIZE_MAX; rateAccum=0; fileError=false; // read the entire file if not seekable if (!si.seekable) { logV("file not seekable - reading..."); for (size_t i=0; i