Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kew for openSUSE:Factory checked in at 2023-12-01 21:26:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kew (Old) and /work/SRC/openSUSE:Factory/.kew.new.25432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kew" Fri Dec 1 21:26:03 2023 rev:4 rq:1130123 version:1.8.1 Changes: -------- --- /work/SRC/openSUSE:Factory/kew/kew.changes 2023-11-27 22:43:58.471161516 +0100 +++ /work/SRC/openSUSE:Factory/.kew.new.25432/kew.changes 2023-12-01 21:26:40.400753946 +0100 @@ -1,0 +2,28 @@ +Wed Nov 29 12:05:29 UTC 2023 - Muhammad Akbar Yanuar Mantari <mantari...@pm.me> + +- Update to version 1.8.1 + * Fixed bug where kew for no reason stopped playing audio but + kept counting elapsed seconds. + * Fixed bugs relating to showing the playlist. + * Fixed bug where trying to seek in ogg files led to strange + behavior. Now seeking in ogg is entirely disabled. + * More colorful visualizer bars when using album cover colors. + +------------------------------------------------------------------- +Tue Nov 28 00:27:10 UTC 2023 - Muhammad Akbar Yanuar Mantari <mantari...@pm.me> + +- Update to version 1.8 + * visualizer bars now grow and decrease smoothly (if your + terminal supports unicode). + * m4a files quit properly. + +------------------------------------------------------------------- +Mon Nov 27 10:18:38 UTC 2023 - Muhammad Akbar Yanuar Mantari <mantari...@pm.me> + +- Update to version 1.7.4 + * kew is now interactive when paused. + * Fixed issue with crashing after a few plays with repeat + enabled. + * Deletes cover images from cache after playing the file. + +------------------------------------------------------------------- Old: ---- kew-1.7.3.tar.gz New: ---- kew-1.8.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kew.spec ++++++ --- /var/tmp/diff_new_pack.hUONxd/_old 2023-12-01 21:26:41.244784945 +0100 +++ /var/tmp/diff_new_pack.hUONxd/_new 2023-12-01 21:26:41.256785386 +0100 @@ -17,7 +17,7 @@ Name: kew -Version: 1.7.3 +Version: 1.8.1 Release: 0 Summary: A command-line music player License: GPL-2.0-only ++++++ kew-1.7.3.tar.gz -> kew-1.8.1.tar.gz ++++++ Binary files old/kew-1.7.3/kew-screenshot.png and new/kew-1.8.1/kew-screenshot.png differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/cache.c new/kew-1.8.1/src/cache.c --- old/kew-1.7.3/src/cache.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/cache.c 2023-11-29 01:42:25.000000000 +0100 @@ -51,4 +51,18 @@ remove(current->filePath); current = current->next; } +} + +bool existsInCache(Cache *cache, char *filePath) +{ + CacheNode *current = cache->head; + while (current != NULL) + { + if (strcmp(filePath, current->filePath) == 0) + { + return true; + } + current = current->next; + } + return false; } \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/cache.h new/kew-1.8.1/src/cache.h --- old/kew-1.7.3/src/cache.h 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/cache.h 2023-11-29 01:42:25.000000000 +0100 @@ -3,6 +3,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <stdbool.h> typedef struct CacheNode { @@ -25,4 +26,6 @@ void deleteCachedFiles(Cache *cache); +bool existsInCache(Cache *cache, char *filePath); + #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/kew.c new/kew-1.8.1/src/kew.c --- old/kew-1.7.3/src/kew.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/kew.c 2023-11-29 01:42:25.000000000 +0100 @@ -413,6 +413,8 @@ void handleGoToSong() { + resetPlaylistDisplay = true; + if (digitsPressedCount == 0) { skipToNumberedSong(chosenSong + 1); @@ -424,7 +426,7 @@ memset(digitsPressed, '\0', sizeof(digitsPressed)); digitsPressedCount = 0; skipToNumberedSong(songNumber); - } + } } void gotoBeginningOfPlaylist() @@ -498,10 +500,12 @@ case EVENT_VOLUME_DOWN: adjustVolumePercent(-5); break; - case EVENT_NEXT: + case EVENT_NEXT: + resetPlaylistDisplay = true; skipToNextSong(); break; case EVENT_PREV: + resetPlaylistDisplay = true; skipToPrevSong(); break; case EVENT_SEEKBACK: @@ -748,6 +752,7 @@ loadingdata.songdataB = NULL; loadingdata.loadA = true; initAudioBuffer(); + initVisuals(); #ifdef DEBUG g_setenv("G_MESSAGES_DEBUG", "all", TRUE); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/player.c new/kew-1.8.1/src/player.c --- old/kew-1.7.3/src/player.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/player.c 2023-11-29 01:42:25.000000000 +0100 @@ -23,9 +23,9 @@ } PixelData; #endif -const char VERSION[] = "1.7.3"; +const char VERSION[] = "1.8.1"; const int LOGO_COLOR = 3; -const int VERSION_COLOR = 6; +const int VERSION_COLOR = 2; const int ABSOLUTE_MIN_WIDTH = 38; volatile bool refresh = true; bool visualizerEnabled = true; @@ -35,12 +35,11 @@ bool timeEnabled = true; bool drewCover = true; bool uiEnabled = true; -bool printInfo = false; +bool printPlaylist = false; bool printKeyBindings = false; bool showList = true; bool resetPlaylistDisplay = true; bool useProfileColors = true; -bool hasPrintedPaused = false; bool fastForwarding = false; bool rewinding = false; int numProgressBars = 15; @@ -362,7 +361,7 @@ } void printMetadata(TagSettings const *metadata) { - if (!metaDataEnabled || printInfo) + if (!metaDataEnabled || printPlaylist) return; c_sleep(100); setColor(); @@ -371,7 +370,7 @@ void printTime(PlayList const *playlist) { - if (!timeEnabled || printInfo) + if (!timeEnabled || printPlaylist) return; setColor(); int term_w, term_h; @@ -621,7 +620,7 @@ void toggleShowPlaylist() { refresh = true; - printInfo = !printInfo; + printPlaylist = !printPlaylist; printKeyBindings = false; } @@ -629,12 +628,12 @@ { refresh = true; printKeyBindings = !printKeyBindings; - printInfo = false; + printPlaylist = false; } void scrollNext() { - if (printInfo) + if (printPlaylist) { chosenRow++; refresh = true; @@ -643,7 +642,7 @@ void scrollPrev() { - if (printInfo) + if (printPlaylist) { chosenRow--; refresh = true; @@ -714,7 +713,7 @@ if (chosenSong < startIter) { - startIter = chosenSong; + startIter = chosenSong; } if (chosenRow >= maxListSize - 1 && chosenRow > startIter + maxListSize - 1) @@ -731,6 +730,7 @@ { startIter = chosenRow = chosenSong = foundAt; } + for (int i = foundAt; i > startIter; i--) { if (i > 0 && node->prev != NULL) @@ -841,7 +841,7 @@ void printVisualizer() { - if (visualizerEnabled && !printInfo) + if (visualizerEnabled && !printPlaylist) { printf("\n"); int term_w, term_h; @@ -891,7 +891,7 @@ int printPlayer(SongData *songdata, double elapsedSeconds, PlayList *playlist) { - if (!uiEnabled || (hasPrintedPaused && isPaused())) + if (!uiEnabled) { return 0; } @@ -908,7 +908,7 @@ if (preferredWidth <= 0 || preferredHeight <= 0) return -1; - if (!printInfo) + if (!printPlaylist) resetPlaylistDisplay = true; if (printKeyBindings) @@ -920,7 +920,7 @@ saveCursorPosition(); } } - else if (printInfo) + else if (printPlaylist) { if (refresh) { @@ -944,7 +944,7 @@ } refresh = false; fflush(stdout); - hasPrintedPaused = true; + return 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/player.h new/kew-1.8.1/src/player.h --- old/kew-1.7.3/src/player.h 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/player.h 2023-11-29 01:42:25.000000000 +0100 @@ -17,7 +17,7 @@ extern bool coverEnabled; extern bool uiEnabled; extern bool coverAnsi; -extern bool printInfo; +extern bool printPlaylist; extern bool printKeyBindings; extern bool visualizerEnabled; extern bool useThemeColors; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/playerops.c new/kew-1.8.1/src/playerops.c --- old/kew-1.7.3/src/playerops.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/playerops.c 2023-11-29 01:42:25.000000000 +0100 @@ -35,8 +35,6 @@ volatile bool songLoading = false; GDBusConnection *connection = NULL; -UserData userData; - void updateLastSongSwitchTime() { clock_gettime(CLOCK_MONOTONIC, &start_time); @@ -159,7 +157,7 @@ { emitStringPropertyChanged("LoopStatus", "None"); } - if (printInfo) + if (printPlaylist) refresh = true; } @@ -192,7 +190,7 @@ } loadedNextSong = false; nextSong = NULL; - if (printInfo) + if (printPlaylist) refresh = true; } @@ -269,6 +267,14 @@ { if (seekAccumulatedSeconds != 0.0) { + if (currentSong != NULL) + { + if (endsWith(currentSong->song.filePath, "ogg")) + { + return; + } + } + setSeekElapsed(getSeekElapsed() + seekAccumulatedSeconds); seekAccumulatedSeconds = 0.0; calcElapsedTime(); @@ -286,6 +292,14 @@ void seekForward() { + if (currentSong != NULL) + { + if (endsWith(currentSong->song.filePath, "ogg")) + { + return; + } + } + if (duration != 0.0) { float step = 100 / numProgressBars; @@ -296,6 +310,14 @@ void seekBack() { + if (currentSong != NULL) + { + if (endsWith(currentSong->song.filePath, "ogg")) + { + return; + } + } + if (duration != 0.0) { float step = 100 / numProgressBars; @@ -328,28 +350,13 @@ void assignLoadedData() { - if (usingSongDataA) - { - if (loadingdata.songdataB != NULL) - { - userData.filenameB = loadingdata.songdataB->pcmFilePath; - userData.songdataB = loadingdata.songdataB; - if (hasBuiltinDecoder(loadingdata.songdataB->filePath)) - prepareNextDecoder(loadingdata.songdataB->filePath); - else if (endsWith(loadingdata.songdataB->filePath, "opus")) - prepareNextOpusDecoder(loadingdata.songdataB->filePath); - else if (endsWith(loadingdata.songdataB->filePath, "ogg")) - prepareNextVorbisDecoder(loadingdata.songdataB->filePath); - } - else - userData.filenameB = NULL; - } - else + if (loadingdata.loadA) { if (loadingdata.songdataA != NULL) { userData.filenameA = loadingdata.songdataA->pcmFilePath; userData.songdataA = loadingdata.songdataA; + if (hasBuiltinDecoder(loadingdata.songdataA->filePath)) prepareNextDecoder(loadingdata.songdataA->filePath); else if (endsWith(loadingdata.songdataA->filePath, "opus")) @@ -360,6 +367,23 @@ else userData.filenameA = NULL; } + else + { + if (loadingdata.songdataB != NULL) + { + userData.filenameB = loadingdata.songdataB->pcmFilePath; + userData.songdataB = loadingdata.songdataB; + + if (hasBuiltinDecoder(loadingdata.songdataB->filePath)) + prepareNextDecoder(loadingdata.songdataB->filePath); + else if (endsWith(loadingdata.songdataB->filePath, "opus")) + prepareNextOpusDecoder(loadingdata.songdataB->filePath); + else if (endsWith(loadingdata.songdataB->filePath, "ogg")) + prepareNextVorbisDecoder(loadingdata.songdataB->filePath); + } + else + userData.filenameB = NULL; + } } void *songDataReaderThread(void *arg) @@ -500,6 +524,7 @@ } updateLastSongSwitchTime(); + skip(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/songloader.c new/kew-1.8.1/src/songloader.c --- old/kew-1.7.3/src/songloader.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/songloader.c 2023-11-29 01:42:25.000000000 +0100 @@ -328,6 +328,11 @@ data->cover = NULL; } + if (existsInCache(tempCache, data->coverArtPath)) + { + deleteFile(data->coverArtPath); + } + free(data->red); free(data->green); free(data->blue); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/soundbuiltin.c new/kew-1.8.1/src/soundbuiltin.c --- old/kew-1.7.3/src/soundbuiltin.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/soundbuiltin.c 2023-11-29 01:42:25.000000000 +0100 @@ -151,6 +151,8 @@ ma_uint64 framesToRead = 0; ma_decoder *firstDecoder = getFirstDecoder(); + pthread_mutex_lock(&dataSourceMutex); + if (decoder == NULL || firstDecoder == NULL) return; @@ -159,6 +161,8 @@ ma_uint64 cursor; result = ma_data_source_get_cursor_in_pcm_frames(decoder, &cursor); + pthread_mutex_unlock(&dataSourceMutex); + if (((pPCMDataSource->totalFrames != 0 && cursor != 0 && cursor >= pPCMDataSource->totalFrames) || framesToRead == 0 || isSkipToNext() || result != MA_SUCCESS) && !isEOFReached()) { activateSwitch(pPCMDataSource); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/soundcommon.c new/kew-1.8.1/src/soundcommon.c --- old/kew-1.7.3/src/soundcommon.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/soundcommon.c 2023-11-29 01:42:25.000000000 +0100 @@ -2,6 +2,14 @@ #define MAX_DECODERS 2 +/* + +soundcommon.c + + Related to common functions for decoders / miniaudio implementations + +*/ + const char BUILTIN_EXTENSIONS[] = "\\.(mp3|flac|wav)$"; bool repeatEnabled = false; @@ -13,6 +21,8 @@ double seekElapsed; _Atomic bool EOFReached = false; _Atomic bool switchReached = false; +_Atomic bool readingFrames = false; +pthread_mutex_t dataSourceMutex = PTHREAD_MUTEX_INITIALIZER; ma_device device = {0}; ma_int32 *audioBuffer = NULL; ma_decoder *firstDecoder; @@ -32,16 +42,6 @@ int vorbisDecoderIndex = -1; bool doQuit = false; -ma_libopus *getOpus() -{ - return &opus; -} - -ma_libvorbis *getVorbis() -{ - return &vorbis; -} - enum AudioImplementation getCurrentImplementationType() { return currentImplementation; @@ -273,6 +273,9 @@ if (firstOpusDecoder != NULL) { + ma_data_source_base * base = (ma_data_source_base *)firstOpusDecoder; + base->pCurrent = NULL; + base->vtable = NULL; ma_libopus_uninit(firstOpusDecoder, NULL); free(firstOpusDecoder); firstOpusDecoder = NULL; @@ -659,7 +662,6 @@ ma_device_stop(&device); paused = true; } - hasPrintedPaused = false; } void cleanupPlaybackDevice() @@ -678,7 +680,6 @@ { ma_device_stop(&device); paused = true; - hasPrintedPaused = false; } else if (paused) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/soundcommon.h new/kew-1.8.1/src/soundcommon.h --- old/kew-1.7.3/src/soundcommon.h 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/soundcommon.h 2023-11-29 01:42:25.000000000 +0100 @@ -108,6 +108,7 @@ }; extern bool doQuit; +extern pthread_mutex_t dataSourceMutex; ma_libopus *getOpus(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/soundgapless.c new/kew-1.8.1/src/soundgapless.c --- old/kew-1.7.3/src/soundgapless.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/soundgapless.c 2023-11-29 01:42:25.000000000 +0100 @@ -13,15 +13,20 @@ */ ma_context context; -UserData *g_userData; + +UserData userData; + PCMFileDataSource pcmDataSource; -ma_result pcm_file_data_source_init(PCMFileDataSource *pPCMDataSource, UserData *pUserData) +ma_result initFirstDatasource(PCMFileDataSource *pPCMDataSource, UserData *pUserData) { char *filePath = NULL; filePath = (pPCMDataSource->currentFileIndex == 0) ? pUserData->songdataA->filePath : pUserData->songdataB->filePath; + pPCMDataSource->pUserData = pUserData; + pPCMDataSource->currentPCMFrame = 0; + if (hasBuiltinDecoder(filePath)) { prepareNextDecoder(filePath); @@ -29,7 +34,6 @@ pPCMDataSource->format = first->outputFormat; pPCMDataSource->channels = first->outputChannels; pPCMDataSource->sampleRate = first->outputSampleRate; - ma_data_source_get_length_in_pcm_frames(first, &pPCMDataSource->totalFrames); } else if (endsWith(filePath, "opus")) @@ -39,6 +43,8 @@ ma_channel channelMap[MA_MAX_CHANNELS]; ma_libopus_ds_get_data_format(first, &pPCMDataSource->format, &pPCMDataSource->channels, &pPCMDataSource->sampleRate, channelMap, MA_MAX_CHANNELS); ma_data_source_get_length_in_pcm_frames(first, &pPCMDataSource->totalFrames); + ma_data_source_base *base = (ma_data_source_base*)first; + base->pCurrent = first; first->pReadSeekTellUserData = pPCMDataSource; } else if (endsWith(filePath, "ogg")) @@ -48,24 +54,28 @@ ma_channel channelMap[MA_MAX_CHANNELS]; ma_libvorbis_ds_get_data_format(first, &pPCMDataSource->format, &pPCMDataSource->channels, &pPCMDataSource->sampleRate, channelMap, MA_MAX_CHANNELS); ma_data_source_get_length_in_pcm_frames(first, &pPCMDataSource->totalFrames); + ma_data_source_base *base = (ma_data_source_base*)first; + base->pCurrent = first; first->pReadSeekTellUserData = pPCMDataSource; } else { - if (pPCMDataSource->fileA == NULL) + if ((pPCMDataSource->currentFileIndex == 0) && pPCMDataSource->fileA == NULL) { pPCMDataSource->filenameA = pUserData->filenameA; pPCMDataSource->fileA = fopen(pUserData->filenameA, "rb"); } + else if ((pPCMDataSource->currentFileIndex == 1) && pPCMDataSource->fileB == NULL) + { + pPCMDataSource->filenameB = pUserData->filenameB; + pPCMDataSource->fileB = fopen(pUserData->filenameB, "rb"); + } pPCMDataSource->format = SAMPLE_FORMAT; pPCMDataSource->channels = CHANNELS; pPCMDataSource->sampleRate = SAMPLE_RATE; } - pPCMDataSource->pUserData = pUserData; - pPCMDataSource->currentPCMFrame = 0; - return MA_SUCCESS; } @@ -74,7 +84,7 @@ ma_result result; ma_data_source_uninit(&pcmDataSource); - pcm_file_data_source_init(&pcmDataSource, userData); + initFirstDatasource(&pcmDataSource, userData); pcmDataSource.base.vtable = vtable; @@ -103,37 +113,12 @@ createDevice(userData, device, context, vtable, pcm_on_audio_frames); } -ma_result vorbis_data_source_init(PCMFileDataSource *pPCMDataSource, ma_libvorbis *vorbis, char *filePath) -{ - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRate; - ma_channel channelMap[MA_MAX_CHANNELS]; - - ma_libvorbis_init_file(filePath, NULL, NULL, vorbis); - ma_libvorbis_ds_get_data_format(vorbis, &format, &channels, &sampleRate, channelMap, MA_MAX_CHANNELS); - pPCMDataSource->sampleRate = sampleRate; - pPCMDataSource->channels = channels; - pPCMDataSource->format = format; - - vorbis->format = format; - vorbis->onRead = ma_libvorbis_read_pcm_frames_wrapper; - vorbis->onSeek = ma_libvorbis_seek_to_pcm_frame_wrapper; - vorbis->onTell = ma_libvorbis_get_cursor_in_pcm_frames_wrapper; - vorbis->pReadSeekTellUserData = pPCMDataSource; - - return MA_SUCCESS; -} - void vorbis_createAudioDevice(UserData *userData, ma_device *device, ma_context *context, ma_data_source_vtable *vtable) { ma_result result; - pcm_file_data_source_init(&pcmDataSource, userData); - char *filePath = pcmDataSource.currentFileIndex == 0 ? userData->songdataA->filePath : userData->songdataB->filePath; + initFirstDatasource(&pcmDataSource, userData); ma_libvorbis *vorbis = getFirstVorbisDecoder(); - vorbis_data_source_init(&pcmDataSource, vorbis, filePath); - ma_device_config deviceConfig = ma_device_config_init(ma_device_type_playback); deviceConfig.playback.format = vorbis->format; @@ -158,36 +143,12 @@ } } -ma_result opus_data_source_init(PCMFileDataSource *pPCMDataSource, ma_libopus *opus, char *filePath) -{ - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRate; - ma_channel channelMap[MA_MAX_CHANNELS]; - - ma_libopus_init_file(filePath, NULL, NULL, opus); - ma_libopus_ds_get_data_format(opus, &format, &channels, &sampleRate, channelMap, MA_MAX_CHANNELS); - pPCMDataSource->sampleRate = sampleRate; - pPCMDataSource->channels = channels; - pPCMDataSource->format = format; - - opus->format = format; - opus->onRead = ma_libopus_read_pcm_frames_wrapper; - opus->onSeek = ma_libopus_seek_to_pcm_frame_wrapper; - opus->onTell = ma_libopus_get_cursor_in_pcm_frames_wrapper; - opus->pReadSeekTellUserData = pPCMDataSource; - - return MA_SUCCESS; -} - void opus_createAudioDevice(UserData *userData, ma_device *device, ma_context *context, ma_data_source_vtable *vtable) { ma_result result; - pcm_file_data_source_init(&pcmDataSource, userData); - char *filePath = pcmDataSource.currentFileIndex == 0 ? userData->songdataA->filePath : userData->songdataB->filePath; - ma_libopus *opus = getFirstOpusDecoder(); - opus_data_source_init(&pcmDataSource, opus, filePath); + initFirstDatasource(&pcmDataSource, userData); + ma_libopus *opus = getFirstOpusDecoder(); ma_device_config deviceConfig = ma_device_config_init(ma_device_type_playback); @@ -217,14 +178,27 @@ { enum AudioImplementation currentImplementation = getCurrentImplementationType(); - if (g_userData->currentSongData == NULL) + if (pcmDataSource.currentFileIndex == 0) + { + userData.currentSongData = userData.songdataA; + } + else + { + userData.currentSongData = userData.songdataB; + } + + if (userData.currentSongData == NULL) + { + setEOFNotReached(); return; + } - char *filePath = strdup(g_userData->currentSongData->filePath); + char *filePath = strdup(userData.currentSongData->filePath); if (filePath == NULL || filePath[0] == '\0' || filePath[0] == '\r') { free(filePath); + setEOFNotReached(); return; } @@ -244,14 +218,23 @@ if (isRepeatEnabled() || !(sameFormat && currentImplementation == BUILTIN)) { setImplSwitchReached(); + + pthread_mutex_lock(&dataSourceMutex); + setCurrentImplementationType(BUILTIN); + resetDecoders(); resetVorbisDecoders(); resetOpusDecoders(); resetAudioBuffer(); + cleanupPlaybackDevice(); + + builtin_createAudioDevice(&userData, getDevice(), &context, &builtin_file_data_source_vtable); + + pthread_mutex_unlock(&dataSourceMutex); + setImplSwitchNotReached(); - builtin_createAudioDevice(g_userData, getDevice(), &context, &builtin_file_data_source_vtable); } } else if (endsWith(filePath, "opus")) @@ -283,14 +266,23 @@ else { setImplSwitchReached(); - setCurrentImplementationType(OPUS); + + pthread_mutex_lock(&dataSourceMutex); + + setCurrentImplementationType(OPUS); + resetDecoders(); resetVorbisDecoders(); resetOpusDecoders(); resetAudioBuffer(); + cleanupPlaybackDevice(); - setImplSwitchNotReached(); - opus_createAudioDevice(g_userData, getDevice(), &context, &pcm_file_data_source_vtable); + + opus_createAudioDevice(&userData, getDevice(), &context, &pcm_file_data_source_vtable); + + pthread_mutex_unlock(&dataSourceMutex); + + setImplSwitchNotReached(); } } else if (endsWith(filePath, "ogg")) @@ -321,15 +313,24 @@ } else { - setImplSwitchReached(); + setImplSwitchReached(); + + pthread_mutex_lock(&dataSourceMutex); + setCurrentImplementationType(VORBIS); + resetDecoders(); resetVorbisDecoders(); resetOpusDecoders(); resetAudioBuffer(); - cleanupPlaybackDevice(); + + cleanupPlaybackDevice(); + + vorbis_createAudioDevice(&userData, getDevice(), &context, &pcm_file_data_source_vtable); + + pthread_mutex_unlock(&dataSourceMutex); + setImplSwitchNotReached(); - vorbis_createAudioDevice(g_userData, getDevice(), &context, &pcm_file_data_source_vtable); } } else @@ -337,14 +338,20 @@ if (isRepeatEnabled() || currentImplementation != PCM) { setImplSwitchReached(); + + pthread_mutex_lock(&dataSourceMutex); + setCurrentImplementationType(PCM); resetDecoders(); resetVorbisDecoders(); resetOpusDecoders(); resetAudioBuffer(); - cleanupPlaybackDevice(); + cleanupPlaybackDevice(); + pcm_createAudioDevice(&userData, getDevice(), &context, &pcm_file_data_source_vtable); + + pthread_mutex_unlock(&dataSourceMutex); + setImplSwitchNotReached(); - pcm_createAudioDevice(g_userData, getDevice(), &context, &pcm_file_data_source_vtable); } } free(filePath); @@ -358,7 +365,6 @@ void createAudioDevice(UserData *userData) { - g_userData = userData; ma_context_init(NULL, 0, NULL, &context); switchAudioImplementation(); } \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/soundgapless.h new/kew-1.8.1/src/soundgapless.h --- old/kew-1.7.3/src/soundgapless.h 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/soundgapless.h 2023-11-29 01:42:25.000000000 +0100 @@ -6,6 +6,7 @@ #include <stdbool.h> #include <unistd.h> #include <stdatomic.h> +#include <pthread.h> #include <fcntl.h> #include <stdio.h> #include <sys/wait.h> @@ -32,6 +33,8 @@ } UserData; #endif +extern UserData userData; + void setDecoders(bool usingA, char *filePath); void createAudioDevice(UserData *userData); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/soundopus.c new/kew-1.8.1/src/soundopus.c --- old/kew-1.7.3/src/soundopus.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/soundopus.c 2023-11-29 01:42:25.000000000 +0100 @@ -63,7 +63,7 @@ ma_uint64 seekPercent = getSeekPercentage(); if (seekPercent >= 100.0) seekPercent = 100.0; - ma_uint64 targetFrame = (totalFrames * seekPercent) / 100; + ma_uint64 targetFrame = (totalFrames * seekPercent) / 100 - 1; // Remove one frame or we get invalid args if we send in totalframes // Set the read pointer for the decoder ma_result seekResult = ma_libopus_seek_to_pcm_frame(decoder, targetFrame); @@ -82,12 +82,22 @@ ma_result result; ma_uint64 remainingFrames = frameCount - framesRead; ma_libopus *firstDecoder = getFirstOpusDecoder(); + + pthread_mutex_lock(&dataSourceMutex); + + if (firstDecoder == NULL) + { + return; + } + result = ma_data_source_read_pcm_frames(firstDecoder, (ma_int32 *)pFramesOut + framesRead * pPCMDataSource->channels, remainingFrames, &framesToRead); ma_uint64 cursor; ma_data_source_get_cursor_in_pcm_frames(decoder, &cursor); + pthread_mutex_unlock(&dataSourceMutex); + if (((cursor != 0 && cursor >= pPCMDataSource->totalFrames) || framesToRead == 0 || isSkipToNext() || result != MA_SUCCESS) && !isEOFReached()) { activateSwitch(pPCMDataSource); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/soundpcm.c new/kew-1.8.1/src/soundpcm.c --- old/kew-1.7.3/src/soundpcm.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/soundpcm.c 2023-11-29 01:42:25.000000000 +0100 @@ -68,11 +68,6 @@ if (currentFile != NULL) bytesRead = (ma_uint32)fread((char *)pFramesOut + (framesRead * bytesPerFrame), 1, bytesToRead, currentFile); - else if (pPCMDataSource->pUserData->currentSongData == NULL || - hasBuiltinDecoder(pPCMDataSource->pUserData->currentSongData->filePath) || - (endsWith(pPCMDataSource->pUserData->currentSongData->filePath, "opus")) || - (endsWith(pPCMDataSource->pUserData->currentSongData->filePath, "ogg"))) - return; // If file is empty, skip if ((bytesRead == 0 || isSkipToNext()) && !isEOFReached()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/soundvorbis.c new/kew-1.8.1/src/soundvorbis.c --- old/kew-1.7.3/src/soundvorbis.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/soundvorbis.c 2023-11-29 01:42:25.000000000 +0100 @@ -81,7 +81,18 @@ ma_uint64 framesToRead = 0; ma_result result; ma_uint64 remainingFrames = frameCount - framesRead; - result = ma_data_source_read_pcm_frames(getFirstVorbisDecoder(), (ma_int32 *)pFramesOut + framesRead * pPCMDataSource->channels, remainingFrames, &framesToRead); + ma_libvorbis *firstDecoder = getFirstVorbisDecoder(); + + pthread_mutex_lock(&dataSourceMutex); + + if (firstDecoder == NULL) + { + return; + } + + result = ma_data_source_read_pcm_frames(firstDecoder, (ma_int32 *)pFramesOut + framesRead * pPCMDataSource->channels, remainingFrames, &framesToRead); + + pthread_mutex_unlock(&dataSourceMutex); if ((getPercentageElapsed() >= 1.0 || isSkipToNext() || result != MA_SUCCESS) && !isEOFReached()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/visuals.c new/kew-1.8.1/src/visuals.c --- old/kew-1.7.3/src/visuals.c 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/visuals.c 2023-11-29 01:42:25.000000000 +0100 @@ -13,6 +13,8 @@ float magnitudeCeil = 120; float alpha = 0.2; float lastMax = 60; +bool unicodeSupport = false; + /* visuals.c @@ -25,6 +27,14 @@ float magnitudeBuffer[MAX_BUFFER_SIZE] = {0.0f}; float lastMagnitudes[MAX_BUFFER_SIZE] = {0.0f}; +void initVisuals() +{ + unicodeSupport = false; + char *locale = setlocale(LC_ALL, ""); + if (locale != NULL) + unicodeSupport = true; +} + void printBlankSpaces(int numSpaces) { for (int i = 0; i < numSpaces; i++) @@ -119,7 +129,7 @@ int beat = detectBeats(magnitudes, width); if (beat > 0) { - jumpFactor = jumpAmount; + jumpFactor = jumpAmount; } for (int i = 0; i < width; i++) @@ -130,7 +140,8 @@ { exponent = 2.0; } - else { + else + { exponent = 1.0; } float normalizedMagnitude = magnitudes[i] / maxMagnitude; @@ -182,7 +193,7 @@ int j = 0; for (int i = 0; i < bufferSize; i++) - { + { ma_int32 sample = audioBuffer[i]; float normalizedSample; @@ -224,12 +235,12 @@ { // Unsupported bit depth return; - } + } if (bitDepth == 32) { if (i % 3 != 0) - { + { continue; } } @@ -266,6 +277,29 @@ updateMagnitudes(height, numBars, maxMagnitude, magnitudes); } +wchar_t *getUpwardMotionChar(int level) { + switch (level) { + case 0: + return L" "; + case 1: + return L"â"; + case 2: + return L"â"; + case 3: + return L"â"; + case 4: + return L"â"; + case 5: + return L"â "; + case 6: + return L"â"; + case 7: + return L"â"; + default: + return L"â"; + } +} + void calcSpectrum(int height, int numBars, fftwf_complex *fftInput, fftwf_complex *fftOutput, float *magnitudes, fftwf_plan plan) { @@ -292,7 +326,7 @@ case ma_format_s24: bitDepth = 24; break; - + case ma_format_f32: case ma_format_s32: bitDepth = 32; @@ -330,6 +364,8 @@ printf("\n"); clearRestOfScreen(); + PixelData tmp; + for (int j = height; j > 0; j--) { printf("\r"); @@ -338,33 +374,46 @@ { if (!useProfileColors) { - if (j == height) - { - color = increaseLuminosity(color, 100); - printf("\033[38;2;%d;%d;%dm", color.r, color.g, color.b); - } - else - { - color = decreaseLuminosity(color, 100 / height); - printf("\033[38;2;%d;%d;%dm", color.r, color.g, color.b); - } + tmp = increaseLuminosity(color, round(j * height * 2)); + printf("\033[38;2;%d;%d;%dm", tmp.r, tmp.g, tmp.b); } } else { setDefaultTextColor(); } - for (int i = 0; i < width; i++) + if (isPaused()) { - if (j >= 0) + for (int i = 0; i < width; i++) { - if ((int)round(magnitudes[i]) >= j) - { - printf(" â"); - } - else + printf(" "); + } + } + else + { + for (int i = 0; i < width; i++) + { + if (j >= 0) { - printf(" "); + if (magnitudes[i] >= j) + { + if (unicodeSupport) + { + printf(" %S", getUpwardMotionChar(10)); + } + else { + printf(" â"); + } + } + else if (magnitudes[i] + 1 >= j && unicodeSupport) + { + int firstDecimalDigit = (int)(fmod(magnitudes[i] * 10, 10)); + printf(" %S", getUpwardMotionChar(firstDecimalDigit)); + } + else + { + printf(" "); + } } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-1.7.3/src/visuals.h new/kew-1.8.1/src/visuals.h --- old/kew-1.7.3/src/visuals.h 2023-11-25 23:57:24.000000000 +0100 +++ new/kew-1.8.1/src/visuals.h 2023-11-29 01:42:25.000000000 +0100 @@ -4,10 +4,13 @@ #include <stdio.h> #include <stdlib.h> #include <math.h> +#include <locale.h> #include "soundgapless.h" #include "term.h" #include "write_ascii.h" +void initVisuals(); + void drawSpectrumVisualizer(int height, int width, PixelData c); PixelData increaseLuminosity(PixelData pixel, int amount);