diff options
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | deadbeef.h | 72 | ||||
-rw-r--r-- | main.c | 29 | ||||
-rw-r--r-- | playback.h | 34 | ||||
-rw-r--r-- | playlist.c | 1 | ||||
-rw-r--r-- | plugins.c | 10 | ||||
-rw-r--r-- | plugins/alsa/alsa.c | 197 | ||||
-rw-r--r-- | plugins/dumb/Makefile.am | 2 | ||||
-rw-r--r-- | plugins/dumb/cdumb.c | 28 | ||||
-rw-r--r-- | plugins/dumb/dumb-kode54/src/it/loadmod.c | 4 | ||||
-rw-r--r-- | plugins/dumb/dumb-kode54/src/it/loadmod2.c | 4 | ||||
-rw-r--r-- | plugins/dumb/dumb-kode54/src/it/readmod.c | 8 | ||||
-rw-r--r-- | plugins/dumb/dumb-kode54/src/it/readmod2.c | 4 | ||||
-rw-r--r-- | plugins/gtkui/gtkui.c | 14 | ||||
-rw-r--r-- | plugins/mpgmad/mpgmad.c | 49 | ||||
-rw-r--r-- | plugins/mpris/mpris.c | 20 | ||||
-rw-r--r-- | plugins/supereq/supereq.c | 2 | ||||
-rw-r--r-- | plugins/wavpack/wavpack.c | 125 | ||||
-rw-r--r-- | premix.c | 294 | ||||
-rw-r--r-- | premix.h | 27 | ||||
-rwxr-xr-x | scripts/configure_minimal.sh | 1 | ||||
-rw-r--r-- | scripts/pluginstall.sh | 37 | ||||
-rwxr-xr-x | scripts/quickinstall.sh | 37 | ||||
-rw-r--r-- | streamer.c | 225 |
25 files changed, 804 insertions, 426 deletions
diff --git a/Makefile.am b/Makefile.am index eb1eb738..cab4aa3b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,9 +21,9 @@ deadbeef_SOURCES =\ plugins.c plugins.h moduleconf.h\ playlist.c playlist.h \ streamer.c streamer.h\ + premix.c premix.h\ messagepump.c messagepump.h\ conf.c conf.h\ - playback.h\ threading_pthread.c threading.h\ volume.c volume.h\ junklib.h junklib.c utf8.c utf8.h u8_lc_map.h\ @@ -36,7 +36,7 @@ deadbeef_SOURCES =\ sdkdir = $(pkgincludedir) sdk_HEADERS = deadbeef.h -deadbeef_LDADD = $(LDADD) $(DEPS_LIBS) $(ICONV_LIB) -lm +deadbeef_LDADD = $(LDADD) $(DEPS_LIBS) $(ICONV_LIB) -lm -ldl -lpthread AM_CFLAGS = $(DEPS_CFLAGS) -std=c99 AM_CPPFLAGS = $(DEPS_CFLAGS) diff --git a/configure.ac b/configure.ac index 36f5b1b1..eacf3af7 100644 --- a/configure.ac +++ b/configure.ac @@ -491,7 +491,7 @@ fi fi if test "x$enable_mpris" != "xno" ; then - PKG_CHECK_MODULES(MPRIS_DEPS, gio-2.0 glib-2.0 >= 2.26.0, HAVE_MPRIS=yes, HAVE_MPRIS=no) + PKG_CHECK_MODULES(MPRIS_DEPS, indicate >= 0.4.4 glib-2.0 >= 2.26.0, HAVE_MPRIS=yes, HAVE_MPRIS=no) fi PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/dumb plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shn plugins/ao plugins/shellexec plugins/mpris" @@ -622,20 +622,63 @@ typedef struct DB_plugin_s { const char *configdialog; } DB_plugin_t; -typedef struct DB_fileinfo_s { - struct DB_decoder_s *plugin; +// file format stuff + +// channel mask - combine following flags to tell streamer which channels are +// present in input/output streams +enum { + DDB_SPEAKER_FRONT_LEFT = 0x1, + DDB_SPEAKER_FRONT_RIGHT = 0x2, + DDB_SPEAKER_FRONT_CENTER = 0x4, + DDB_SPEAKER_LOW_FREQUENCY = 0x8, + DDB_SPEAKER_BACK_LEFT = 0x10, + DDB_SPEAKER_BACK_RIGHT = 0x20, + DDB_SPEAKER_FRONT_LEFT_OF_CENTER = 0x40, + DDB_SPEAKER_FRONT_RIGHT_OF_CENTER = 0x80, + DDB_SPEAKER_BACK_CENTER = 0x100, + DDB_SPEAKER_SIDE_LEFT = 0x200, + DDB_SPEAKER_SIDE_RIGHT = 0x400, + DDB_SPEAKER_TOP_CENTER = 0x800, + DDB_SPEAKER_TOP_FRONT_LEFT = 0x1000, + DDB_SPEAKER_TOP_FRONT_CENTER = 0x2000, + DDB_SPEAKER_TOP_FRONT_RIGHT = 0x4000, + DDB_SPEAKER_TOP_BACK_LEFT = 0x8000, + DDB_SPEAKER_TOP_BACK_CENTER = 0x10000, + DDB_SPEAKER_TOP_BACK_RIGHT = 0x20000 +}; + +typedef struct { int bps; + int is_float; // bps must be 32 if this is true + int is_multichannel; // usually 0, in which case channels=1 is mono, and channels=2 is stereo int channels; int samplerate; + uint32_t channelmask; +} ddb_waveformat_t; + +typedef struct DB_fileinfo_s { + struct DB_decoder_s *plugin; + + // these parameters should be set in decoder->open + ddb_waveformat_t fmt; + + // readpos should be updated to current decoder time (in seconds) float readpos; + + // this is the (optional) file handle, that can be used by streamer to + // request interruption of current read operation DB_FILE *file; } DB_fileinfo_t; +enum { + DDB_DECODER_HINT_16BIT = 0x1, // that flag means streamer prefers 16 bit streams for performance reasons +}; + // decoder plugin typedef struct DB_decoder_s { DB_plugin_t plugin; - DB_fileinfo_t *(*open) (void); + DB_fileinfo_t *(*open) (uint32_t hints); // init is called to prepare song to be started int (*init) (DB_fileinfo_t *info, DB_playItem_t *it); @@ -645,12 +688,7 @@ typedef struct DB_decoder_s { // read is called by streamer to decode specified number of bytes // must return number of bytes that were successfully decoded (sample aligned) - - // read_int16 must always output 16 bit signed integer samples - int (*read_int16) (DB_fileinfo_t *info, char *buffer, int size); - - // read_float32 must always output 32 bit floating point samples - int (*read_float32) (DB_fileinfo_t *info, char *buffer, int size); + int (*read) (DB_fileinfo_t *info, char *buffer, int nbytes); int (*seek) (DB_fileinfo_t *info, float seconds); @@ -684,8 +722,8 @@ typedef struct DB_output_s { int (*init) (void); // free is called if output plugin was changed to another, or unload is about to happen int (*free) (void); - // reconfigure output to another samplerate, if supported - int (*change_rate) (int rate); + // reconfigure output to another format, if supported + void (*setformat) (ddb_waveformat_t *fmt); // play, stop, pause, unpause are called by deadbeef in response to user // events, or as part of streaming process int (*play) (void); @@ -694,15 +732,11 @@ typedef struct DB_output_s { int (*unpause) (void); // one of output_state_t enum values int (*state) (void); - // following functions must return output sampling rate, bits per sample and number - // of channels - int (*samplerate) (void); - int (*bitspersample) (void); - int (*channels) (void); - // must return 0 for little endian output, or 1 for big endian - int (*endianness) (void); // soundcard enumeration (can be NULL) void (*enum_soundcards) (void (*callback)(const char *name, const char *desc, void*), void *userdata); + + // parameters of current output + ddb_waveformat_t fmt; } DB_output_t; // dsp plugin @@ -711,7 +745,7 @@ typedef struct DB_dsp_s { // process gets called before SRC // stereo samples are stored in interleaved format // stereo sample is counted as 1 sample - int (*process_int16) (int16_t *samples, int nsamples, int nch, int bps, int srate); + int (*process) (char * restrict samples, ddb_waveformat_t * restrict fmt); void (*reset) (void); void (*enable) (int e); int (*enabled) (void); @@ -47,7 +47,6 @@ #include <unistd.h> #include "gettext.h" #include "playlist.h" -#include "playback.h" #include "threading.h" #include "messagepump.h" #include "streamer.h" @@ -368,6 +367,7 @@ player_mainloop (void) { uint32_t p1; uint32_t p2; while (messagepump_pop(&msg, &ctx, &p1, &p2) != -1) { + DB_output_t *output = plug_get_output (); switch (msg) { case M_REINIT_SOUND: plug_reinit_sound (); @@ -377,7 +377,7 @@ player_mainloop (void) { return; case M_PLAYSONG: if (p1) { - p_stop (); + output->stop (); pl_playqueue_clear (); streamer_set_nextsong (0, 1); } @@ -386,7 +386,7 @@ player_mainloop (void) { } break; case M_PLAYSONGNUM: - p_stop (); + output->stop (); pl_playqueue_clear (); streamer_set_nextsong (p1, 1); break; @@ -394,25 +394,25 @@ player_mainloop (void) { streamer_set_nextsong (-2, 0); break; case M_NEXTSONG: - p_stop (); + output->stop (); streamer_move_to_nextsong (1); break; case M_PREVSONG: - p_stop (); + output->stop (); streamer_move_to_prevsong (); break; case M_PAUSESONG: - if (p_get_state () == OUTPUT_STATE_PAUSED) { - p_unpause (); + if (output->state () == OUTPUT_STATE_PAUSED) { + output->unpause (); plug_trigger_event_paused (0); } else { - p_pause (); + output->pause (); plug_trigger_event_paused (1); } break; case M_PLAYRANDOM: - p_stop (); + output->stop (); streamer_move_to_randomsong (); break; case M_PLAYLISTREFRESH: @@ -488,10 +488,11 @@ sigsegv_handler (int sig) { void save_resume_state (void) { playItem_t *trk = streamer_get_playing_track (); + DB_output_t *output = plug_get_output (); float playpos = -1; int playtrack = -1; int playlist = streamer_get_current_playlist (); - int paused = (p_get_state () == OUTPUT_STATE_PAUSED); + int paused = (output->state () == OUTPUT_STATE_PAUSED); if (trk && playlist >= 0) { playtrack = str_get_idx_of (trk); playpos = streamer_get_playpos (); @@ -506,7 +507,8 @@ save_resume_state (void) { void restore_resume_state (void) { - if (conf_get_int ("resume_last_session", 0) && p_isstopped ()) { + DB_output_t *output = plug_get_output (); + if (conf_get_int ("resume_last_session", 0) && output->state () == OUTPUT_STATE_STOPPED) { int plt = conf_get_int ("resume.playlist", -1); int track = conf_get_int ("resume.track", -1); float pos = conf_get_float ("resume.position", -1); @@ -811,9 +813,10 @@ main (int argc, char *argv[]) { server_close (); // stop streaming and playback before unloading plugins - p_stop (); + DB_output_t *output = plug_get_output (); + output->stop (); streamer_free (); - p_free (); + output->free (); // plugins might still hood references to playitems, // and query configuration in background diff --git a/playback.h b/playback.h deleted file mode 100644 index 21ac74f1..00000000 --- a/playback.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - DeaDBeeF - ultimate music player for GNU/Linux systems with X11 - Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net> - - 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, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __PLAYBACK_H -#define __PLAYBACK_H - -#define p_init plug_get_output ()->init -#define p_free plug_get_output ()->free -#define p_play plug_get_output ()->play -#define p_stop plug_get_output ()->stop -#define p_pause plug_get_output ()->pause -#define p_unpause plug_get_output ()->unpause -#define p_get_rate plug_get_output ()->samplerate -#define p_get_state plug_get_output ()->state - -#define p_state() (plug_get_output ()->state ()) -#define p_isstopped() (p_state () == OUTPUT_STATE_STOPPED) -#define p_ispaused() (p_state () == OUTPUT_STATE_PAUSED) - -#endif // __PLAYBACK_H @@ -39,7 +39,6 @@ #include "playlist.h" #include "streamer.h" #include "messagepump.h" -#include "playback.h" #include "plugins.h" #include "junklib.h" #include "vfs.h" @@ -38,7 +38,6 @@ #include "playlist.h" #include "volume.h" #include "streamer.h" -#include "playback.h" #include "common.h" #include "conf.h" #include "junklib.h" @@ -933,9 +932,10 @@ plug_select_output (void) { void plug_reinit_sound (void) { - int state = p_get_state (); + DB_output_t *output = plug_get_output (); + int state = output->state (); - p_free (); + output->free (); DB_output_t *prev = plug_get_output (); if (plug_select_output () < 0) { @@ -944,13 +944,13 @@ plug_reinit_sound (void) { output_plugin = prev; } streamer_reset (1); - if (p_init () < 0) { + if (output->init () < 0) { streamer_set_nextsong (-2, 0); return; } if (state != OUTPUT_STATE_PAUSED && state != OUTPUT_STATE_STOPPED) { - if (p_play () < 0) { + if (output->play () < 0) { trace ("failed to reinit sound output\n"); streamer_set_nextsong (-2, 0); } diff --git a/plugins/alsa/alsa.c b/plugins/alsa/alsa.c index 65178e55..887bc205 100644 --- a/plugins/alsa/alsa.c +++ b/plugins/alsa/alsa.c @@ -23,8 +23,8 @@ #include "../../deadbeef.h" #include "../../config.h" -//#define trace(...) { fprintf(stderr, __VA_ARGS__); } -#define trace(fmt,...) +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) #define min(x,y) ((x)<(y)?(x):(y)) @@ -41,8 +41,7 @@ DB_functions_t *deadbeef; static snd_pcm_t *audio; static int alsa_terminate; -static int requested_rate = -1; -static int alsa_rate = 44100; +static ddb_waveformat_t requested_fmt; static int state; // one of output_state_t static uintptr_t mutex; static intptr_t alsa_tid; @@ -90,8 +89,8 @@ palsa_init (void); static int palsa_free (void); -static int -palsa_change_rate (int rate); +static void +palsa_setformat (ddb_waveformat_t *fmt); static int palsa_play (void); @@ -106,12 +105,6 @@ static int palsa_unpause (void); static int -palsa_get_rate (void); - -static int -palsa_get_bps (void); - -static int palsa_get_channels (void); static int @@ -121,9 +114,8 @@ static void palsa_enum_soundcards (void (*callback)(const char *name, const char *desc, void*), void *userdata); static int -palsa_set_hw_params (int samplerate) { +palsa_set_hw_params (ddb_waveformat_t *fmt) { snd_pcm_hw_params_t *hw_params = NULL; -// int alsa_resample = conf_get_int ("alsa.resample", 0); int err = 0; if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { @@ -144,22 +136,46 @@ palsa_set_hw_params (int samplerate) { goto error; } - snd_pcm_format_t fmt; + snd_pcm_format_t sample_fmt; + + switch (fmt->bps) { + case 8: + sample_fmt = SND_PCM_FORMAT_S8; + break; + case 16: +#if WORDS_BIGENDIAN + sample_fmt = SND_PCM_FORMAT_S16_BE; +#else + sample_fmt = SND_PCM_FORMAT_S16_LE; +#endif + break; + case 24: +#if WORDS_BIGENDIAN + sample_fmt = SND_PCM_FORMAT_S24_3BE; +#else + sample_fmt = SND_PCM_FORMAT_S24_3LE; +#endif + break; + case 32: #if WORDS_BIGENDIAN - fmt = SND_PCM_FORMAT_S16_BE; + sample_fmt = SND_PCM_FORMAT_S32_BE; #else - fmt = SND_PCM_FORMAT_S16_LE; + sample_fmt = SND_PCM_FORMAT_S32_LE; #endif - if ((err = snd_pcm_hw_params_set_format (audio, hw_params, fmt)) < 0) { + break; + }; + + //sample_fmt = SND_PCM_FORMAT_S16_LE; + if ((err = snd_pcm_hw_params_set_format (audio, hw_params, sample_fmt)) < 0) { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)); goto error; } - snd_pcm_hw_params_get_format (hw_params, &fmt); + snd_pcm_hw_params_get_format (hw_params, &sample_fmt); trace ("chosen sample format: %04Xh\n", (int)fmt); - int val = samplerate; + int val = fmt->samplerate; int ret = 0; if ((err = snd_pcm_hw_params_set_rate_resample (audio, hw_params, conf_alsa_resample)) < 0) { @@ -173,10 +189,10 @@ palsa_set_hw_params (int samplerate) { snd_strerror (err)); goto error; } - alsa_rate = val; - trace ("chosen samplerate: %d Hz\n", alsa_rate); + plugin.fmt.samplerate = val; + trace ("chosen samplerate: %d Hz\n", val); - if ((err = snd_pcm_hw_params_set_channels (audio, hw_params, 2)) < 0) { + if ((err = snd_pcm_hw_params_set_channels (audio, hw_params, fmt->channels)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); goto error; @@ -202,6 +218,60 @@ palsa_set_hw_params (int samplerate) { snd_strerror (err)); goto error; } + + plugin.fmt.is_float = 0; + switch (sample_fmt) { + case SND_PCM_FORMAT_S8: + plugin.fmt.bps = 8; + break; + case SND_PCM_FORMAT_S16_BE: + case SND_PCM_FORMAT_S16_LE: + plugin.fmt.bps = 16; + break; + case SND_PCM_FORMAT_S24_3BE: + case SND_PCM_FORMAT_S24_3LE: + plugin.fmt.bps = 24; + break; + case SND_PCM_FORMAT_S32_BE: + case SND_PCM_FORMAT_S32_LE: + plugin.fmt.bps = 32; + break; + case SND_PCM_FORMAT_FLOAT_LE: + case SND_PCM_FORMAT_FLOAT_BE: + plugin.fmt.bps = 32; + plugin.fmt.is_float = 1; + break; + } + + trace ("chosen bps: %d (%s)\n", plugin.fmt.bps, plugin.fmt.is_float ? "float" : "int"); + + plugin.fmt.channels = nchan; + plugin.fmt.is_multichannel = 0; + plugin.fmt.channelmask = 0; + if (nchan == 1) { + plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT; + } + if (nchan == 2) { + plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT; + } + if (nchan == 3) { + plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_LOW_FREQUENCY; + } + if (nchan == 4) { + plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT; + } + if (nchan == 5) { + plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER; + } + if (nchan == 6) { + plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER | DDB_SPEAKER_LOW_FREQUENCY; + } + if (nchan == 7) { + plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER | DDB_SPEAKER_SIDE_LEFT | DDB_SPEAKER_SIDE_RIGHT; + } + if (nchan == 8) { + plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER | DDB_SPEAKER_SIDE_LEFT | DDB_SPEAKER_SIDE_RIGHT | DDB_SPEAKER_LOW_FREQUENCY; + } error: if (hw_params) { snd_pcm_hw_params_free (hw_params); @@ -232,11 +302,11 @@ palsa_init (void) { mutex = deadbeef->mutex_create (); - if (requested_rate != -1) { - alsa_rate = requested_rate; + if (requested_fmt.samplerate != 0) { + memcpy (&plugin.fmt, &requested_fmt, sizeof (ddb_waveformat_t)); } - if (palsa_set_hw_params (alsa_rate) < 0) { + if (palsa_set_hw_params (&plugin.fmt) < 0) { goto open_error; } @@ -308,28 +378,27 @@ open_error: return -1; } -int -palsa_change_rate (int rate) { - trace ("palsa_change_rate: %d\n", rate); - requested_rate = rate; +void +palsa_setformat (ddb_waveformat_t *fmt) { + memcpy (&requested_fmt, fmt, sizeof (ddb_waveformat_t)); + trace ("palsa_setformat %dbit %s %s %dch %dHz channelmask=%X\n", fmt->bps, fmt->is_float ? "float" : "int", fmt->is_multichannel ? "multichannel" : "", fmt->channels, fmt->samplerate, fmt->channelmask); if (!audio) { - return alsa_rate; + return; } - if (rate == alsa_rate) { - trace ("palsa_change_rate %d: ignored\n", rate); - return rate; + if (!memcmp (fmt, &plugin.fmt, sizeof (ddb_waveformat_t))) { + trace ("palsa_setformat ignored\n"); + return; } state = OUTPUT_STATE_STOPPED; LOCK; snd_pcm_drop (audio); - int ret = palsa_set_hw_params (rate); + int ret = palsa_set_hw_params (fmt); UNLOCK; if (ret < 0) { - trace ("palsa_change_rate: impossible to set samplerate to %d\n", rate); - return alsa_rate; + trace ("palsa_change_rate: impossible to set requested format\n"); + return; } - trace ("chosen samplerate: %d\n", alsa_rate); - return alsa_rate; + trace ("new format %dbit %s %s %dch %dHz channelmask=%X\n", plugin.fmt.bps, plugin.fmt.is_float ? "float" : "int", plugin.fmt.is_multichannel ? "multichannel" : "", plugin.fmt.channels, plugin.fmt.samplerate, plugin.fmt.channelmask); } int @@ -453,33 +522,6 @@ palsa_unpause (void) { return 0; } -int -palsa_get_rate (void) { - if (!audio) { - palsa_init (); - } - return alsa_rate; -} - -int -palsa_get_bps (void) { - return 16; -} - -int -palsa_get_channels (void) { - return 2; -} - -static int -palsa_get_endianness (void) { -#if WORDS_BIGENDIAN - return 1; -#else - return 0; -#endif -} - static void palsa_thread (void *context) { prctl (PR_SET_NAME, "deadbeef-alsa", 0, 0, 0, 0); @@ -500,10 +542,10 @@ palsa_thread (void *context) { break; } err = 0; - char buf[period_size * 4]; - int bytes_to_write = palsa_callback (buf, period_size * 4); + char buf[period_size * (plugin.fmt.bps>>3) * plugin.fmt.channels]; + int bytes_to_write = palsa_callback (buf, period_size * (plugin.fmt.bps>>3) * plugin.fmt.channels); - if ( bytes_to_write >= 4 ) { + if (bytes_to_write >= (plugin.fmt.bps>>3) * plugin.fmt.channels) { err = snd_pcm_writei (audio, buf, snd_pcm_bytes_to_frames(audio, bytes_to_write)); } else { @@ -541,7 +583,7 @@ palsa_thread (void *context) { frames_to_deliver = snd_pcm_avail_update (audio); } UNLOCK; - usleep (period_size * 1000000 / alsa_rate / 2); + usleep (period_size * 1000000 / plugin.fmt.samplerate / 2); } } @@ -581,10 +623,10 @@ palsa_callback (char *stream, int len) { ); #else - int16_t ivolume = deadbeef->volume_get_amp () * 1000; - for (int i = 0; i < bytesread/2; i++) { - ((int16_t*)stream)[i] = (int16_t)(((int32_t)(((int16_t*)stream)[i])) * ivolume / 1000); - } +// int16_t ivolume = deadbeef->volume_get_amp () * 1000; +// for (int i = 0; i < bytesread/2; i++) { +// ((int16_t*)stream)[i] = (int16_t)(((int32_t)(((int16_t*)stream)[i])) * ivolume / 1000); +// } #endif return bytesread; } @@ -682,15 +724,12 @@ static DB_output_t plugin = { .plugin.configdialog = settings_dlg, .init = palsa_init, .free = palsa_free, - .change_rate = palsa_change_rate, + .setformat = palsa_setformat, .play = palsa_play, .stop = palsa_stop, .pause = palsa_pause, .unpause = palsa_unpause, .state = palsa_get_state, - .samplerate = palsa_get_rate, - .bitspersample = palsa_get_bps, - .channels = palsa_get_channels, - .endianness = palsa_get_endianness, .enum_soundcards = palsa_enum_soundcards, + .fmt = {.samplerate = 44100} }; diff --git a/plugins/dumb/Makefile.am b/plugins/dumb/Makefile.am index de165bdd..f3bb7f46 100644 --- a/plugins/dumb/Makefile.am +++ b/plugins/dumb/Makefile.am @@ -5,7 +5,7 @@ EXTRA_DIST = $(dumbpath)/readme.txt $(dumbpath)/ChangeLog $(dumbpath)/licence.tx pkglib_LTLIBRARIES = dumb.la -AM_CFLAGS = $(CFLAGS) -I$(dumbpath)/include +AM_CFLAGS = $(CFLAGS) -I$(dumbpath)/include -std=c99 dumb_la_LDFLAGS = -module -lm dumb_la_SOURCES =\ diff --git a/plugins/dumb/cdumb.c b/plugins/dumb/cdumb.c index b3f6bb2a..c7072fcc 100644 --- a/plugins/dumb/cdumb.c +++ b/plugins/dumb/cdumb.c @@ -51,7 +51,7 @@ static DUH* open_module(const char *fname, const char *ext, int *start_order, int *is_it, int *is_dos, const char **filetype); static DB_fileinfo_t * -cdumb_open (void) { +cdumb_open (uint32_t hints) { DB_fileinfo_t *_info = malloc (sizeof (dumb_info_t)); memset (_info, 0, sizeof (dumb_info_t)); return _info; @@ -75,10 +75,11 @@ cdumb_init (DB_fileinfo_t *_info, DB_playItem_t *it) { dumb_it_do_initial_runthrough (info->duh); _info->plugin = &plugin; - _info->bps = 16; - _info->channels = 2; - _info->samplerate = deadbeef->conf_get_int ("synth.samplerate", 44100); + _info->fmt.bps = deadbeef->conf_get_int ("dumb.8bitoutput", 0) ? 8 : 16; + _info->fmt.channels = 2; + _info->fmt.samplerate = deadbeef->conf_get_int ("synth.samplerate", 44100); _info->readpos = 0; + _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT); if (cdumb_startrenderer (_info) < 0) { return -1; @@ -139,12 +140,13 @@ static int cdumb_read (DB_fileinfo_t *_info, char *bytes, int size) { trace ("cdumb_read req %d\n", size); dumb_info_t *info = (dumb_info_t *)_info; - int length = size / 4; + int samplesize = (_info->fmt.bps >> 3) * _info->fmt.channels; + int length = size / samplesize; long ret; - ret = duh_render (info->renderer, 16, 0, 1, 65536.f / _info->samplerate, length, bytes); - _info->readpos += ret / (float)_info->samplerate; - trace ("cdumb_read %d\n", ret*4); - return ret*4; + ret = duh_render (info->renderer, _info->fmt.bps, 0, 1, 65536.f / _info->fmt.samplerate, length, bytes); + _info->readpos += ret / (float)_info->fmt.samplerate; + trace ("cdumb_read %d\n", ret*samplesize); + return ret*samplesize; } static int @@ -159,8 +161,8 @@ cdumb_seek (DB_fileinfo_t *_info, float time) { else { time -= _info->readpos; } - int pos = time * _info->samplerate; - duh_sigrenderer_generate_samples (info->renderer, 0, 65536.0f / _info->samplerate, pos, NULL); + int pos = time * _info->fmt.samplerate; + duh_sigrenderer_generate_samples (info->renderer, 0, 65536.0f / _info->fmt.samplerate, pos, NULL); _info->readpos = duh_sigrenderer_get_position (info->renderer) / 65536.f; return 0; } @@ -811,7 +813,9 @@ static const char *filetypes[] = { "IT", "XM", "S3M", "STM", "669", "PTM", "PSM" static const char settings_dlg[] = "property \"Resampling quality (0..2, higher is better)\" entry dumb.resampling_quality 2;\n" + "property \"8-bit output (default is 16)\" checkbox dumb.8bitoutput 0;\n" ; + // define plugin interface static DB_decoder_t plugin = { DB_PLUGIN_SET_API_VERSION @@ -830,7 +834,7 @@ static DB_decoder_t plugin = { .open = cdumb_open, .init = cdumb_init, .free = cdumb_free, - .read_int16 = cdumb_read, + .read = cdumb_read, .seek = cdumb_seek, .insert = cdumb_insert, .exts = exts, diff --git a/plugins/dumb/dumb-kode54/src/it/loadmod.c b/plugins/dumb/dumb-kode54/src/it/loadmod.c index 0b7dc618..dd43b611 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadmod.c +++ b/plugins/dumb/dumb-kode54/src/it/loadmod.c @@ -26,7 +26,7 @@ * pointer to the DUH struct. When you have finished with it, you must * pass the pointer to unload_duh() so that the memory can be freed. */ -DUH *dumb_load_mod_quick(const char *filename, int restrict) +DUH *dumb_load_mod_quick(const char *filename, int restr) { DUH *duh; DUMBFILE *f = dumbfile_open(filename); @@ -34,7 +34,7 @@ DUH *dumb_load_mod_quick(const char *filename, int restrict) if (!f) return NULL; - duh = dumb_read_mod_quick(f, restrict); + duh = dumb_read_mod_quick(f, restr); dumbfile_close(f); diff --git a/plugins/dumb/dumb-kode54/src/it/loadmod2.c b/plugins/dumb/dumb-kode54/src/it/loadmod2.c index 7847d19f..c1f46e4c 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadmod2.c +++ b/plugins/dumb/dumb-kode54/src/it/loadmod2.c @@ -21,9 +21,9 @@ -DUH *dumb_load_mod(const char *filename, int restrict) +DUH *dumb_load_mod(const char *filename, int restr) { - DUH *duh = dumb_load_mod_quick(filename, restrict); + DUH *duh = dumb_load_mod_quick(filename, restr); dumb_it_do_initial_runthrough(duh); return duh; } diff --git a/plugins/dumb/dumb-kode54/src/it/readmod.c b/plugins/dumb/dumb-kode54/src/it/readmod.c index a934af40..538d86ba 100644 --- a/plugins/dumb/dumb-kode54/src/it/readmod.c +++ b/plugins/dumb/dumb-kode54/src/it/readmod.c @@ -439,7 +439,7 @@ static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, long *remain) } -static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict) +static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restr) { DUMB_IT_SIGDATA *sigdata; int n_channels; @@ -554,7 +554,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict) } // moo - if ( restrict && sigdata->n_samples == 15 ) + if ( restr && sigdata->n_samples == 15 ) { free(sigdata); dumbfile_close(f); @@ -760,13 +760,13 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict) return sigdata; } -DUH *dumb_read_mod_quick(DUMBFILE *f, int restrict) +DUH *dumb_read_mod_quick(DUMBFILE *f, int restr) { sigdata_t *sigdata; DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - sigdata = it_mod_load_sigdata(f, restrict); + sigdata = it_mod_load_sigdata(f, restr); if (!sigdata) return NULL; diff --git a/plugins/dumb/dumb-kode54/src/it/readmod2.c b/plugins/dumb/dumb-kode54/src/it/readmod2.c index 102ead12..299c584e 100644 --- a/plugins/dumb/dumb-kode54/src/it/readmod2.c +++ b/plugins/dumb/dumb-kode54/src/it/readmod2.c @@ -21,9 +21,9 @@ -DUH *dumb_read_mod(DUMBFILE *f, int restrict) +DUH *dumb_read_mod(DUMBFILE *f, int restr) { - DUH *duh = dumb_read_mod_quick(f, restrict); + DUH *duh = dumb_read_mod_quick(f, restr); dumb_it_do_initial_runthrough(duh); return duh; } diff --git a/plugins/gtkui/gtkui.c b/plugins/gtkui/gtkui.c index 06ceb756..a2da9d74 100644 --- a/plugins/gtkui/gtkui.c +++ b/plugins/gtkui/gtkui.c @@ -45,8 +45,8 @@ #include "eq.h" #include "actions.h" -//#define trace(...) { fprintf(stderr, __VA_ARGS__); } -#define trace(fmt,...) +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) static DB_gui_t plugin; DB_functions_t *deadbeef; @@ -154,15 +154,15 @@ update_songinfo (gpointer ctx) { const char *mode; char temp[20]; - if (c->channels <= 2) { - mode = c->channels == 1 ? _("Mono") : _("Stereo"); + if (c->fmt.channels <= 2) { + mode = c->fmt.channels == 1 ? _("Mono") : _("Stereo"); } else { - snprintf (temp, sizeof (temp), "%dch Multichannel", c->channels); + snprintf (temp, sizeof (temp), "%dch Multichannel", c->fmt.channels); mode = temp; } - int samplerate = c->samplerate; - int bitspersample = c->bps; + int samplerate = c->fmt.samplerate; + int bitspersample = c->fmt.bps; songpos = playpos; // codec_unlock (); diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index 03ddbc91..6b4d96ea 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -567,7 +567,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { static DB_fileinfo_t * -cmp3_open (void) { +cmp3_open (uint32_t hints) { DB_fileinfo_t *_info = malloc (sizeof (mpgmad_info_t)); mpgmad_info_t *info = (mpgmad_info_t *)_info; memset (info, 0, sizeof (mpgmad_info_t)); @@ -651,9 +651,10 @@ cmp3_init (DB_fileinfo_t *_info, DB_playItem_t *it) { trace ("bad mpeg file: %f\n", it->fname); return -1; } - _info->bps = info->buffer.bitspersample; - _info->samplerate = info->buffer.samplerate; - _info->channels = info->buffer.channels; + _info->fmt.bps = info->buffer.bitspersample; + _info->fmt.samplerate = info->buffer.samplerate; + _info->fmt.channels = info->buffer.channels; + _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT); mad_stream_init(&info->stream); mad_stream_options (&info->stream, MAD_OPTION_IGNORECRC); @@ -748,12 +749,12 @@ cmp3_decode_requested_int16 (mpgmad_info_t *info) { *((int16_t*)info->buffer.out) = sample; info->buffer.readsize -= 2; info->buffer.out += 2; - if (MAD_NCHANNELS(&info->frame.header) == 2 && info->info.channels == 2) { + if (MAD_NCHANNELS(&info->frame.header) == 2 && info->info.fmt.channels == 2) { *((int16_t*)info->buffer.out) = MadFixedToSshort (info->synth.pcm.samples[1][idx]); info->buffer.readsize -= 2; info->buffer.out += 2; } - else if (MAD_NCHANNELS(&info->frame.header) == 1 && info->info.channels == 2) { + else if (MAD_NCHANNELS(&info->frame.header) == 1 && info->info.fmt.channels == 2) { *((int16_t*)info->buffer.out) = sample; info->buffer.readsize -= 2; info->buffer.out += 2; @@ -775,12 +776,12 @@ cmp3_decode_requested_float32 (mpgmad_info_t *info) { *((float*)info->buffer.out) = sample; info->buffer.readsize -= 4; info->buffer.out += 4; - if (MAD_NCHANNELS(&info->frame.header) == 2 && info->info.channels == 2) { + if (MAD_NCHANNELS(&info->frame.header) == 2 && info->info.fmt.channels == 2) { *((float*)info->buffer.out) = MadFixedToFloat (info->synth.pcm.samples[1][idx]); info->buffer.readsize -= 4; info->buffer.out += 4; } - else if (MAD_NCHANNELS(&info->frame.header) == 1 && info->info.channels == 2) { + else if (MAD_NCHANNELS(&info->frame.header) == 1 && info->info.fmt.channels == 2) { *((float*)info->buffer.out) = sample; info->buffer.readsize -= 4; info->buffer.out += 4; @@ -864,11 +865,11 @@ cmp3_stream_frame (mpgmad_info_t *info) { } } - info->info.samplerate = info->frame.header.samplerate; + info->info.fmt.samplerate = info->frame.header.samplerate; #if 0 // don't switch number of channels on the fly - if (info->info.channels == 0) { - info->info.channels = MAD_NCHANNELS(&info->frame.header); + if (info->info.fmt.channels == 0) { + info->info.fmt.channels = MAD_NCHANNELS(&info->frame.header); } #endif @@ -937,6 +938,28 @@ cmp3_free (DB_fileinfo_t *_info) { } static int +cmp3_read (DB_fileinfo_t *_info, char *bytes, int size) { +#if WRITE_DUMP + if (!out) { + out = fopen ("out.raw", "w+b"); + } +#endif + mpgmad_info_t *info = (mpgmad_info_t *)_info; + info->buffer.readsize = size; + info->buffer.out = bytes; + cmp3_decode_int16 (info); + info->buffer.currentsample += (size - info->buffer.readsize) / 4; + _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate; +#if WRITE_DUMP + if (size - info->buffer.readsize > 0) { + fwrite (bytes, 1, size - info->buffer.readsize, out); + } +#endif + return size - info->buffer.readsize; +} + +#if 0 +static int cmp3_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) { #if WRITE_DUMP if (!out) { @@ -968,6 +991,7 @@ cmp3_read_float32 (DB_fileinfo_t *_info, char *bytes, int size) { _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate; return size - info->buffer.readsize; } +#endif static int cmp3_seek_sample (DB_fileinfo_t *_info, int sample) { @@ -1246,8 +1270,7 @@ static DB_decoder_t plugin = { .open = cmp3_open, .init = cmp3_init, .free = cmp3_free, - .read_int16 = cmp3_read_int16, - .read_float32 = cmp3_read_float32, + .read = cmp3_read, .seek = cmp3_seek, .seek_sample = cmp3_seek_sample, .insert = cmp3_insert, diff --git a/plugins/mpris/mpris.c b/plugins/mpris/mpris.c index 040de84c..37b6e4c9 100644 --- a/plugins/mpris/mpris.c +++ b/plugins/mpris/mpris.c @@ -19,7 +19,7 @@ #include <time.h> #include <gio/gio.h> -//#include <libindicate/server.h> +#include <libindicate/server.h> #include <deadbeef/deadbeef.h> #include "../artwork/artwork.h" @@ -36,7 +36,7 @@ DB_functions_t *deadbeef; static short enabled = 0; DB_artwork_plugin_t *coverart_plugin = NULL; -//static IndicateServer *indicate_server; +static IndicateServer *indicate_server; static GDBusConnection *connection; static guint name_own_id; static guint root_id; @@ -1087,10 +1087,10 @@ name_lost_cb (GDBusConnection *connection, const char *name, gpointer *user_data static gboolean mpris_begin () { -// indicate_server = indicate_server_ref_default (); -// indicate_server_set_type (indicate_server, "music.deadbeef"); -// indicate_server_set_desktop_file (indicate_server, DESKTOP_FILE); -// indicate_server_show (indicate_server); + indicate_server = indicate_server_ref_default (); + indicate_server_set_type (indicate_server, "music.deadbeef"); + indicate_server_set_desktop_file (indicate_server, DESKTOP_FILE); + indicate_server_show (indicate_server); GError *error = NULL; GDBusInterfaceInfo *ifaceinfo; @@ -1201,7 +1201,7 @@ mpris_end () name_own_id = 0; } -// indicate_server_hide (indicate_server); + indicate_server_hide (indicate_server); deadbeef->mutex_lock(emit_id_mtx); if (player_property_emit_id != 0) { @@ -1291,9 +1291,9 @@ static DB_dsp_t plugin = { .plugin.api_vmajor = DB_API_VERSION_MAJOR, .plugin.api_vminor = DB_API_VERSION_MINOR, .plugin.type = DB_PLUGIN_MISC, - .plugin.id = "mpris", - .plugin.name = "MPRIS", - .plugin.descr = "MPRIS", + .plugin.id = "Sound Menu", + .plugin.name = "Sound Menu", + .plugin.descr = "Ubuntu Sound Menu plugin", .plugin.author = "Robert Y", .plugin.email = "Decatf@gmail.com", .plugin.website = "http://deadbeef.sf.net", diff --git a/plugins/supereq/supereq.c b/plugins/supereq/supereq.c index 577af84a..6ebf9b24 100644 --- a/plugins/supereq/supereq.c +++ b/plugins/supereq/supereq.c @@ -129,7 +129,7 @@ supereq_regen_table_thread (void *param) { } int -supereq_process_int16 (int16_t *samples, int nsamples, int nch, int bps, int srate) { +supereq_process (char * restrict samples, ddb_waveformat_t * restrict fmt) { if ((nch != 1 && nch != 2) || (bps != 8 && bps != 16 && bps != 24)) return nsamples; if (params_changed && !tid) { tid = deadbeef->thread_start (supereq_regen_table_thread, NULL); diff --git a/plugins/wavpack/wavpack.c b/plugins/wavpack/wavpack.c index 72cc7e3c..05130f87 100644 --- a/plugins/wavpack/wavpack.c +++ b/plugins/wavpack/wavpack.c @@ -31,8 +31,8 @@ #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) -//#define trace(...) { fprintf(stderr, __VA_ARGS__); } -#define trace(fmt,...) +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) static DB_decoder_t plugin; static DB_functions_t *deadbeef; @@ -106,7 +106,7 @@ static WavpackStreamReader wsr = { #endif static DB_fileinfo_t * -wv_open (void) { +wv_open (uint32_t hints) { DB_fileinfo_t *_info = malloc (sizeof (wvctx_t)); memset (_info, 0, sizeof (wvctx_t)); return _info; @@ -143,9 +143,11 @@ wv_init (DB_fileinfo_t *_info, DB_playItem_t *it) { return -1; } _info->plugin = &plugin; - _info->bps = WavpackGetBytesPerSample (info->ctx) * 8; - _info->channels = WavpackGetNumChannels (info->ctx); - _info->samplerate = WavpackGetSampleRate (info->ctx); + _info->fmt.bps = WavpackGetBytesPerSample (info->ctx) * 8; + _info->fmt.channels = WavpackGetNumChannels (info->ctx); + _info->fmt.samplerate = WavpackGetSampleRate (info->ctx); + _info->fmt.is_float = (WavpackGetMode (info->ctx) & MODE_FLOAT) ? 1 : 0; + _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT); _info->readpos = 0; if (it->endsample > 0) { info->startsample = it->startsample; @@ -184,49 +186,57 @@ wv_free (DB_fileinfo_t *_info) { } static int -wv_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) { +wv_read (DB_fileinfo_t *_info, char *bytes, int size) { wvctx_t *info = (wvctx_t *)_info; int currentsample = WavpackGetSampleIndex (info->ctx); - int nchannels = WavpackGetReducedChannels (info->ctx); - if (size / (2 * nchannels) + currentsample > info->endsample) { - size = (info->endsample - currentsample + 1) * 2 * nchannels; +// int nchannels = WavpackGetReducedChannels (info->ctx); + int samplesize = (_info->fmt.bps >> 3) * _info->fmt.channels; + if (size / samplesize + currentsample > info->endsample) { + size = (info->endsample - currentsample + 1) * samplesize; trace ("wv: size truncated to %d bytes, cursample=%d, endsample=%d\n", size, currentsample, info->endsample); if (size <= 0) { return 0; } } - int32_t buffer[size/2]; - int n = WavpackUnpackSamples (info->ctx, buffer, size/(2*nchannels)); - size = n * 2 * nchannels; - // convert to int16 - int32_t *p = buffer; - n *= nchannels; - + int n; if (WavpackGetMode (info->ctx) & MODE_FLOAT) { - while (n > 0) { - float val = *(float*)p; - if (val >= 1.0) - *((int16_t *)bytes) = 32767; - else if (val <= -1.0) - *((int16_t *)bytes) = -32768; - else - *((int16_t *)bytes) = floor (val * 32768.f); - bytes += sizeof (int16_t); - p++; - n--; - } + _info->fmt.is_float = 1; + } + if (_info->fmt.is_float || _info->fmt.bps == 32) { + n = WavpackUnpackSamples (info->ctx, (int32_t *)bytes, size / samplesize); + size = n * samplesize; } else { - while (n > 0) { - if (_info->bps >= 16) { - *((int16_t *)bytes) = (int16_t)((*p) >> (_info->bps-16)); + int32_t buffer[size/(_info->fmt.bps >> 3)]; + n = WavpackUnpackSamples (info->ctx, (int32_t *)buffer, size / samplesize); + size = n * samplesize; + n *= _info->fmt.channels; + + // convert from int32 to input (what???) + int32_t *p = buffer; + if (_info->fmt.bps == 16) { + while (n > 0) { + *((int16_t *)bytes) = (int16_t)(*p); + bytes += sizeof (int16_t); + p++; + n--; + } + } + else if (_info->fmt.bps == 8) { + while (n > 0) { + *bytes++ = (char)(*p); + p++; + n--; } - else { - *((int16_t *)bytes) = (int16_t)((*p) << (16-_info->bps)); + } + else if (_info->fmt.bps == 24) { + while (n > 0) { + *bytes++ = (*p)&0xff; + *bytes++ = ((*p)&0xff00)>>8; + *bytes++ = ((*p)&0xff0000)>>16; + p++; + n--; } - bytes += sizeof (int16_t); - p++; - n--; } } _info->readpos = (float)(WavpackGetSampleIndex (info->ctx)-info->startsample)/WavpackGetSampleRate (info->ctx); @@ -239,44 +249,6 @@ wv_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) { } static int -wv_read_float32 (DB_fileinfo_t *_info, char *bytes, int size) { - wvctx_t *info = (wvctx_t *)_info; - int nchannels = WavpackGetReducedChannels (info->ctx); - int currentsample = WavpackGetSampleIndex (info->ctx); - if (size / (4 * nchannels) + currentsample > info->endsample) { - size = (info->endsample - currentsample + 1) * 4 * nchannels; - trace ("wv: size truncated to %d bytes, cursample=%d, endsample=%d\n", size, currentsample, info->endsample); - if (size <= 0) { - return 0; - } - } - int32_t buffer[size/4]; - int n = WavpackUnpackSamples (info->ctx, buffer, size/(4*nchannels)); - size = n * 4 * nchannels; - // convert to float32 - n *= nchannels; - - if (WavpackGetMode (info->ctx) & MODE_FLOAT) { - memcpy (bytes, buffer, size); - } - else { - float mul = 1.f/ (1UL << (_info->bps-1)); - int32_t *p = buffer; - while (n > 0) { - *((float *)bytes) = (*p) * mul; - bytes += sizeof (float); - p++; - n--; - } - } - _info->readpos = (float)(WavpackGetSampleIndex (info->ctx)-info->startsample)/WavpackGetSampleRate (info->ctx); -#ifndef TINYWV - deadbeef->streamer_set_bitrate (WavpackGetInstantBitrate (info->ctx) / 1000); -#endif - return size; -} - -static int wv_seek_sample (DB_fileinfo_t *_info, int sample) { #ifndef TINYWV wvctx_t *info = (wvctx_t *)_info; @@ -454,8 +426,7 @@ static DB_decoder_t plugin = { .open = wv_open, .init = wv_init, .free = wv_free, - .read_int16 = wv_read_int16, - .read_float32 = wv_read_float32, + .read = wv_read, .seek = wv_seek, .seek_sample = wv_seek_sample, .insert = wv_insert, diff --git a/premix.c b/premix.c new file mode 100644 index 00000000..89cbef11 --- /dev/null +++ b/premix.c @@ -0,0 +1,294 @@ +/* + DeaDBeeF - ultimate music player for GNU/Linux systems with X11 + Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net> + + 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 <assert.h> +#include <string.h> +#include <stdlib.h> +#include "deadbeef.h" +#include "premix.h" + +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) + + +static inline void +pcm_write_samples_8_to_8 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + *(output + (outputfmt->bps >> 3) * channelmap[c]) = *input; + } + input++; + } + output += outputsamplesize; + } +} + +static inline void +pcm_write_samples_8_to_16 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + *((int16_t*)(output + (outputfmt->bps >> 3) * channelmap[c])) = (int16_t)(*input) << 8; + } + input++; + } + output += outputsamplesize; + } +} + +static inline void +pcm_write_samples_8_to_24 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + char *out = output + (outputfmt->bps >> 3) * channelmap[c]; + out[0] = 0; + out[1] = 0; + out[2] = input[0]; + } + input += 1; + } + output += outputsamplesize; + } +} + +static inline void +pcm_write_samples_8_to_32 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + char *out = output + (outputfmt->bps >> 3) * channelmap[c]; + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = input[0]; + } + input += 1; + } + output += outputsamplesize; + } +} + +static inline void +pcm_write_samples_8_to_float (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + float sample = (*input) / (float)0x7f; + *((float *)(output + (outputfmt->bps >> 3) * channelmap[c])) = sample; + } + input++; + } + output += outputsamplesize; + } +} + +static inline void +pcm_write_samples_16_to_16 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + *((int16_t*)(output + (outputfmt->bps >> 3) * channelmap[c])) = *((int16_t*)input); + } + input += 2; + } + output += outputsamplesize; + } +} + +static inline void +pcm_write_samples_16_to_8 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + *((int8_t*)(output + (outputfmt->bps >> 3) * channelmap[c])) = *((int16_t*)input) >> 8; + } + input += 2; + } + output += outputsamplesize; + } +} + +static inline void +pcm_write_samples_16_to_24 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + char *out = output + (outputfmt->bps >> 3) * channelmap[c]; + out[0] = 0; + out[1] = input[0]; + out[2] = input[1]; + } + input += 2; + } + output += outputsamplesize; + } +} + +static inline void +pcm_write_samples_16_to_32 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + char *out = output + (outputfmt->bps >> 3) * channelmap[c]; + out[0] = 0; + out[1] = 0; + out[2] = input[0]; + out[3] = input[1]; + } + input += 2; + } + output += outputsamplesize; + } +} + +static inline void +pcm_write_samples_16_to_float (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + float sample = (*((int16_t*)input)) / (float)0x7fff; + *((float *)(output + (outputfmt->bps >> 3) * channelmap[c])) = sample; + } + input += 2; + } + output += outputsamplesize; + } +} + +static inline void +pcm_write_samples_32_to_32 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + *((int32_t*)(output + (outputfmt->bps >> 3) * channelmap[c])) = *((int32_t*)input); + } + input += 4; + } + output += outputsamplesize; + } +} + +static inline void +pcm_write_samples_24_to_24 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) { + for (int s = 0; s < nsamples; s++) { + for (int c = 0; c < inputfmt->channels; c++) { + if (channelmap[c] != -1) { + char *out = output + (outputfmt->bps >> 3) * channelmap[c]; + out[0] = input[0]; + out[1] = input[1]; + out[2] = input[2]; + } + input += 3; + } + output += outputsamplesize; + } +} + +int +pcm_convert (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int inputsize) { + // calculate output size + int inputsamplesize = (inputfmt->bps >> 3) * inputfmt->channels; + int outputsamplesize = (outputfmt->bps >> 3) * outputfmt->channels; + int nsamples = inputsize / inputsamplesize; + + uint32_t outchannels = 0; + + if (output) { + // build channelmap + int channelmap[32] = {-1}; + uint32_t inputbitmask = 1; + for (int i = 0; i < inputfmt->channels; i++) { + // find next input channel + while (inputbitmask < 0x80000000 && !(inputfmt->channelmask & inputbitmask)) { + inputbitmask <<= 1; + } + if (!(inputfmt->channelmask & inputbitmask)) { + trace ("pcm_convert: channelmask doesn't correspond inputfmt (channels=%d, channelmask=%X)!\n", inputfmt->channels, inputfmt->channelmask); + break; + } + if (outputfmt->channelmask & inputbitmask) { + int o = 0; + uint32_t outputbitmask = 1; + while (outputbitmask < 0x80000000 && (outputfmt->channelmask & outputbitmask) != inputbitmask) { + outputbitmask <<= 1; + o++; + } + if (!(inputfmt->channelmask & outputbitmask)) { + // no corresponding output channel -- ignore + continue; + } + outchannels |= outputbitmask; + channelmap[i] = o; // input channel i going to output channel o + //trace ("channelmap[%d]=%d\n", i, o); + } + inputbitmask <<= 1; + } + + if (outchannels != outputfmt->channelmask) { + // some of the channels are not used + memset (output, 0, nsamples * outputsamplesize); + } + + // FIXME: access through function pointer table + //trace ("converting from %d to %d\n", inputfmt->bps, outputfmt->bps); + if (inputfmt->bps == 8 && outputfmt->bps == 8) { + pcm_write_samples_8_to_8 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else if (inputfmt->bps == 8 && outputfmt->bps == 16) { + pcm_write_samples_8_to_16 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else if (inputfmt->bps == 8 && outputfmt->bps == 24) { + pcm_write_samples_8_to_24 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else if (inputfmt->bps == 8 && outputfmt->bps == 32 && !outputfmt->is_float) { + pcm_write_samples_8_to_32 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else if (inputfmt->bps == 8 && outputfmt->bps == 32 && outputfmt->is_float) { + pcm_write_samples_8_to_float (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else if (inputfmt->bps == 16 && outputfmt->bps == 16) { + pcm_write_samples_16_to_16 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else if (inputfmt->bps == 16 && outputfmt->bps == 8) { + pcm_write_samples_16_to_8 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else if (inputfmt->bps == 16 && outputfmt->bps == 24) { + pcm_write_samples_16_to_24 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else if (inputfmt->bps == 16 && outputfmt->bps == 32 && !outputfmt->is_float) { + pcm_write_samples_16_to_32 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else if (inputfmt->bps == 16 && outputfmt->bps == 32 && outputfmt->is_float) { + pcm_write_samples_16_to_float (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else if (inputfmt->bps == 24 && outputfmt->bps == 24) { + pcm_write_samples_24_to_24 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else if (inputfmt->bps == 32 && outputfmt->bps == 32) { + pcm_write_samples_32_to_32 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize); + } + else { + trace ("no converter from %d to %d\n", inputfmt->bps, outputfmt->bps); + } + } + return nsamples * outputsamplesize; +} + diff --git a/premix.h b/premix.h new file mode 100644 index 00000000..e25707da --- /dev/null +++ b/premix.h @@ -0,0 +1,27 @@ +/* + DeaDBeeF - ultimate music player for GNU/Linux systems with X11 + Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net> + + 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. +*/ + +#ifndef __PREMIX_H +#define __PREMIX_H + +// @returns number of output bytes +int +pcm_convert (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int inputsize); + +#endif diff --git a/scripts/configure_minimal.sh b/scripts/configure_minimal.sh new file mode 100755 index 00000000..7ec8607d --- /dev/null +++ b/scripts/configure_minimal.sh @@ -0,0 +1 @@ +./configure --enable-maintainer-mode --disable-nullout --disable-oss --disable-sid --disable-ffap --disable-vtx --disable-adplug --disable-vorbis --disable-ffmpeg --disable-flac --disable-sndfile --disable-cdda --disable-gme --disable-musepack --disable-wildmidi --disable-tta --disable-dca --disable-aac --disable-mms --disable-shn --disable-ao --disable-supereq --disable-artwork --disable-lfm --disable-vfs-curl --disable-hotkeys --disable-notify --disable-shellexec diff --git a/scripts/pluginstall.sh b/scripts/pluginstall.sh index cb296fac..433a5d8d 100644 --- a/scripts/pluginstall.sh +++ b/scripts/pluginstall.sh @@ -1,36 +1,3 @@ -./scripts/portable_postbuild.sh +#./scripts/portable_postbuild.sh +sudo ./scripts/quickinstall.sh -#sudo cp ./deadbeef /usr/local/bin/ -#sudo cp ./plugins/nullout/.libs/nullout.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/cdda/.libs/cdda.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/flac/.libs/flac.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/alsa/.libs/alsa.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/mpgmad/.libs/mpgmad.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/hotkeys/.libs/hotkeys.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/vtx/.libs/vtx.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/ffap/.libs/ffap.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/wavpack/.libs/wavpack.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/vorbis/.libs/vorbis.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/oss/.libs/oss.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/vfs_curl/.libs/vfs_curl.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/ffmpeg/.libs/ffmpeg.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/lastfm/.libs/lastfm.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/sid/.libs/sid.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/adplug/.libs/adplug.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/gtkui/.libs/gtkui.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/sndfile/.libs/sndfile.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/pulse/.libs/pulse.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/artwork/.libs/artwork.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/supereq/.libs/supereq.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/gme/.libs/gme.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/dumb/.libs/dumb.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/notify/.libs/notify.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/musepack/.libs/musepack.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/wildmidi/.libs/wildmidi.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/tta/.libs/tta.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/dca/.libs/dca.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/aac/.libs/aac.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/mms/.libs/mms.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/shn/.libs/shn.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/ao/.libs/ao.so /usr/local/lib/deadbeef/ -#sudo cp ./plugins/shellexec/.libs/shellexec.so /usr/local/lib/deadbeef/ diff --git a/scripts/quickinstall.sh b/scripts/quickinstall.sh new file mode 100755 index 00000000..28fccb1c --- /dev/null +++ b/scripts/quickinstall.sh @@ -0,0 +1,37 @@ +#!/bin/sh +rm /usr/local/lib/deadbeef/* +cp ./deadbeef /usr/local/bin/ +cp ./plugins/nullout/.libs/nullout.so /usr/local/lib/deadbeef/ +cp ./plugins/cdda/.libs/cdda.so /usr/local/lib/deadbeef/ +cp ./plugins/flac/.libs/flac.so /usr/local/lib/deadbeef/ +cp ./plugins/alsa/.libs/alsa.so /usr/local/lib/deadbeef/ +cp ./plugins/mpgmad/.libs/mpgmad.so /usr/local/lib/deadbeef/ +cp ./plugins/hotkeys/.libs/hotkeys.so /usr/local/lib/deadbeef/ +cp ./plugins/vtx/.libs/vtx.so /usr/local/lib/deadbeef/ +cp ./plugins/ffap/.libs/ffap.so /usr/local/lib/deadbeef/ +cp ./plugins/wavpack/.libs/wavpack.so /usr/local/lib/deadbeef/ +cp ./plugins/vorbis/.libs/vorbis.so /usr/local/lib/deadbeef/ +cp ./plugins/oss/.libs/oss.so /usr/local/lib/deadbeef/ +cp ./plugins/vfs_curl/.libs/vfs_curl.so /usr/local/lib/deadbeef/ +cp ./plugins/ffmpeg/.libs/ffmpeg.so /usr/local/lib/deadbeef/ +cp ./plugins/lastfm/.libs/lastfm.so /usr/local/lib/deadbeef/ +cp ./plugins/sid/.libs/sid.so /usr/local/lib/deadbeef/ +cp ./plugins/adplug/.libs/adplug.so /usr/local/lib/deadbeef/ +cp ./plugins/gtkui/.libs/gtkui.so /usr/local/lib/deadbeef/ +cp ./plugins/sndfile/.libs/sndfile.so /usr/local/lib/deadbeef/ +cp ./plugins/pulse/.libs/pulse.so /usr/local/lib/deadbeef/ +cp ./plugins/artwork/.libs/artwork.so /usr/local/lib/deadbeef/ +cp ./plugins/supereq/.libs/supereq.so /usr/local/lib/deadbeef/ +cp ./plugins/gme/.libs/gme.so /usr/local/lib/deadbeef/ +cp ./plugins/dumb/.libs/dumb.so /usr/local/lib/deadbeef/ +cp ./plugins/notify/.libs/notify.so /usr/local/lib/deadbeef/ +cp ./plugins/musepack/.libs/musepack.so /usr/local/lib/deadbeef/ +cp ./plugins/wildmidi/.libs/wildmidi.so /usr/local/lib/deadbeef/ +cp ./plugins/tta/.libs/tta.so /usr/local/lib/deadbeef/ +cp ./plugins/dca/.libs/dca.so /usr/local/lib/deadbeef/ +cp ./plugins/aac/.libs/aac.so /usr/local/lib/deadbeef/ +cp ./plugins/mms/.libs/mms.so /usr/local/lib/deadbeef/ +cp ./plugins/shn/.libs/shn.so /usr/local/lib/deadbeef/ +cp ./plugins/ao/.libs/ao.so /usr/local/lib/deadbeef/ +cp ./plugins/shellexec/.libs/shellexec.so /usr/local/lib/deadbeef/ + @@ -29,18 +29,18 @@ #include "playlist.h" #include "common.h" #include "streamer.h" -#include "playback.h" #include "messagepump.h" #include "conf.h" #include "plugins.h" #include "optmath.h" #include "volume.h" #include "vfs.h" +#include "premix.h" -//#define trace(...) { fprintf(stderr, __VA_ARGS__); } -#define trace(fmt,...) +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) -// #define WRITE_DUMP 1 +#define WRITE_DUMP 1 #if WRITE_DUMP FILE *out; @@ -118,6 +118,18 @@ src_unlock (void) { mutex_unlock (srcmutex); } +void +adjust_waveformat (ddb_waveformat_t *fmt) { + if (!fmt->is_multichannel) { + if (fmt->channels == 1) { + fmt->channelmask = DDB_SPEAKER_FRONT_LEFT; + } + else if (fmt->channelmask == 2) { + fmt->channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT; + } + } +} + static void streamer_abort_files (void) { if (fileinfo && fileinfo->file) { @@ -539,6 +551,7 @@ streamer_song_removed_notify (playItem_t *it) { // that must be called after last sample from str_playing_song was done reading static int streamer_set_current (playItem_t *it) { + DB_output_t *output = plug_get_output (); int err = 0; playItem_t *from, *to; // need to add refs here, because streamer_start_playback can destroy items @@ -551,7 +564,7 @@ streamer_set_current (playItem_t *it) { pl_item_ref (to); } trace ("\033[0;35mstreamer_set_current from %p to %p\033[37;0m\n", from, it); - if (!playing_track || p_isstopped ()) { + if (!playing_track || output->state () == OUTPUT_STATE_STOPPED) { trace ("buffering = on\n"); streamer_buffering = 1; trace ("\033[0;35mstreamer_start_playback[1] from %p to %p\033[37;0m\n", from, it); @@ -633,12 +646,13 @@ streamer_set_current (playItem_t *it) { dec = plug_get_decoder_for_id (it->decoder_id); if (dec) { trace ("\033[0;33minit decoder for %s\033[37;0m\n", it->fname); - fileinfo = dec->open (); + fileinfo = dec->open (0); if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (it)) != 0) { trace ("\033[0;31mfailed to init decoder\033[37;0m\n") dec->free (fileinfo); fileinfo = NULL; } + adjust_waveformat (&fileinfo->fmt); } if (!dec || !fileinfo) { @@ -660,7 +674,7 @@ streamer_set_current (playItem_t *it) { streaming_track = it; pl_item_ref (streaming_track); mutex_unlock (decodemutex); - trace ("bps=%d, channels=%d, samplerate=%d\n", fileinfo->bps, fileinfo->channels, fileinfo->samplerate); + trace ("bps=%d, channels=%d, samplerate=%d\n", fileinfo->fmt.bps, fileinfo->fmt.channels, fileinfo->fmt.samplerate); } // FIXME: that might break streaming at boundaries between 2 different samplerates // streamer_reset (0); // reset SRC @@ -719,12 +733,13 @@ streamer_get_apx_bitrate (void) { void streamer_set_nextsong (int song, int pstate) { + DB_output_t *output = plug_get_output (); trace ("streamer_set_nextsong %d %d\n", song, pstate); streamer_lock (); streamer_abort_files (); nextsong = song; nextsong_pstate = pstate; - if (p_isstopped ()) { + if (output->state () == OUTPUT_STATE_STOPPED) { if (pstate == 1) { // means user initiated this streamer_playlist = plt_get_curr_ptr (); } @@ -748,6 +763,7 @@ static void streamer_start_new_song (void) { trace ("nextsong=%d\n", nextsong); streamer_lock (); + DB_output_t *output = plug_get_output (); int sng = nextsong; int initsng = nextsong; int pstate = nextsong_pstate; @@ -763,7 +779,7 @@ streamer_start_new_song (void) { playItem_t *try = str_get_for_idx (sng); if (!try) { // track is not in playlist trace ("track #%d is not in playlist; stopping playback\n", sng); - p_stop (); + output->stop (); mutex_lock (decodemutex); if (playing_track) { @@ -806,39 +822,41 @@ streamer_start_new_song (void) { try = NULL; badsong = -1; trace ("pstate = %d\n", pstate); - trace ("playback state = %d\n", p_state ()); + trace ("playback state = %d\n", output->state ()); if (pstate == 0) { - p_stop (); + output->stop (); } else if (pstate == 1 || pstate == 3) { last_bitrate = -1; avg_bitrate = -1; - if (p_state () != OUTPUT_STATE_PLAYING) { + if (output->state () != OUTPUT_STATE_PLAYING) { streamer_reset (1); if (fileinfo) { - plug_get_output ()->change_rate (fileinfo->samplerate); + plug_get_output ()->setformat (&fileinfo->fmt); + adjust_waveformat (&plug_get_output ()->fmt); } - if (p_play () < 0) { + if (output->play () < 0) { fprintf (stderr, "streamer: failed to start playback; output plugin doesn't work\n"); streamer_set_nextsong (-2, 0); } } } else if (pstate == 2) { - if (p_get_state () == OUTPUT_STATE_STOPPED) { + if (output->state () == OUTPUT_STATE_STOPPED) { last_bitrate = -1; avg_bitrate = -1; streamer_reset (1); if (fileinfo) { - plug_get_output ()->change_rate (fileinfo->samplerate); + plug_get_output ()->setformat (&fileinfo->fmt); + adjust_waveformat (&plug_get_output ()->fmt); } - if (p_play () < 0) { + if (output->play () < 0) { fprintf (stderr, "streamer: failed to start playback; output plugin doesn't work\n"); streamer_set_nextsong (-2, 0); return; } } - p_pause (); + output->pause (); } } @@ -851,6 +869,7 @@ streamer_thread (void *ctx) { while (!streaming_terminate) { struct timeval tm1; + DB_output_t *output = plug_get_output (); gettimeofday (&tm1, NULL); if (nextsong >= 0) { // start streaming next song trace ("\033[0;34mnextsong=%d\033[37;0m\n", nextsong); @@ -866,7 +885,7 @@ streamer_thread (void *ctx) { bytes_until_next_song = -1; trace ("nextsong=-2\n"); nextsong = -1; - p_stop (); + output->stop (); if (playing_track) { trace ("sending songfinished to plugins [1]\n"); plug_trigger_event (DB_EV_SONGFINISHED, 0); @@ -886,7 +905,7 @@ streamer_thread (void *ctx) { streamer_unlock (); continue; } - else if (p_isstopped ()) { + else if (output->state () == OUTPUT_STATE_STOPPED) { usleep (50000); continue; } @@ -896,7 +915,7 @@ streamer_thread (void *ctx) { if (!streaming_track) { // means last song was deleted during final drain nextsong = -1; - p_stop (); + output->stop (); streamer_set_current (NULL); streamer_unlock (); continue; @@ -924,23 +943,27 @@ streamer_thread (void *ctx) { if (conf_get_int ("playback.dynsamplerate", 0)) { // don't switch if unchanged - int prevtrack_samplerate = p_get_rate (); - if (prevtrack_samplerate != fileinfo->samplerate) { - int newrate = plug_get_output ()->change_rate (fileinfo->samplerate); - if (newrate != prevtrack_samplerate) { + ddb_waveformat_t prevfmt; + memcpy (&prevfmt, &output->fmt, sizeof (ddb_waveformat_t)); + if (memcmp (&output->fmt, &fileinfo->fmt, sizeof (ddb_waveformat_t))) { + output->setformat (&fileinfo->fmt); + adjust_waveformat (&output->fmt); + // check if the format actually changed + if (memcmp (&output->fmt, &prevfmt, sizeof (ddb_waveformat_t))) { // restart streaming of current track - trace ("streamer: output samplerate changed from %d to %d; restarting track\n", prevtrack_samplerate, newrate); + trace ("streamer: output samplerate changed from %d to %d; restarting track\n", prevfmt.samplerate, output->fmt.samplerate); mutex_lock (decodemutex); fileinfo->plugin->free (fileinfo); fileinfo = NULL; DB_decoder_t *dec = NULL; dec = plug_get_decoder_for_id (streaming_track->decoder_id); if (dec) { - fileinfo = dec->open (); + fileinfo = dec->open (0); if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (streaming_track)) < 0) { dec->free (fileinfo); fileinfo = NULL; } + adjust_waveformat (&fileinfo->fmt); } if (!dec || !fileinfo) { // FIXME: handle error @@ -949,18 +972,16 @@ streamer_thread (void *ctx) { bytes_until_next_song = -1; streamer_buffering = 1; streamer_reset (1); - if (fileinfo) { - prevtrack_samplerate = fileinfo->samplerate; - } } } // output plugin may stop playback before switching samplerate - if (p_state () != OUTPUT_STATE_PLAYING) { + if (output->state () != OUTPUT_STATE_PLAYING) { if (fileinfo) { - plug_get_output ()->change_rate (fileinfo->samplerate); + plug_get_output ()->setformat (&fileinfo->fmt); + adjust_waveformat (&plug_get_output ()->fmt); } - if (p_play () < 0) { + if (output->play () < 0) { fprintf (stderr, "streamer: failed to start playback after samplerate change; output plugin doesn't work\n"); streamer_set_nextsong (-2, 0); streamer_unlock (); @@ -1005,11 +1026,12 @@ streamer_thread (void *ctx) { DB_decoder_t *dec = NULL; dec = plug_get_decoder_for_id (streaming_track->decoder_id); if (dec) { - fileinfo = dec->open (); + fileinfo = dec->open (0); if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (streaming_track)) != 0) { dec->free (fileinfo); fileinfo = NULL; } + adjust_waveformat (&fileinfo->fmt); } mutex_unlock (decodemutex); @@ -1048,14 +1070,14 @@ streamer_thread (void *ctx) { } // read ahead at 2x speed of output samplerate, in 4k blocks - int rate = p_get_rate (); + int rate = output->fmt.samplerate; if (!rate) { trace ("str: got 0 output samplerate\n"); usleep(20000); continue; } - int channels = 2; // FIXME: needs to be queried from output plugin - int bytes_in_one_second = rate * sizeof (int16_t) * channels; + int channels = output->fmt.channels; + int bytes_in_one_second = rate * (output->fmt.bps>>3) * channels; const int blocksize = 4096; int alloc_time = 1000 / (bytes_in_one_second * 2 / blocksize); @@ -1073,6 +1095,13 @@ streamer_thread (void *ctx) { assert ((sz&3) == 0); char buf[sz]; streamer_unlock (); + + // ensure that size is possible with current format + int samplesize = output->fmt.channels * (output->fmt.bps>>3); + if (sz % samplesize) { + sz -= (sz % samplesize); + } + int bytesread = streamer_read_async (buf,sz); streamer_lock (); memcpy (streambuffer+streambuffer_fill, buf, sz); @@ -1187,7 +1216,7 @@ streamer_reset (int full) { // must be called when current song changes by exter src_reset (src); // reset dsp DB_dsp_t **dsp = deadbeef->plug_get_dsp_list (); - //int srate = p_get_rate (); + //int srate = output->fmt.samplerate; for (int i = 0; dsp[i]; i++) { if (dsp[i]->enabled ()) { dsp[i]->reset (); @@ -1357,9 +1386,10 @@ float32_to_int16 (float *in, int16_t *out, int nsamples) { */ +#if 0 static int streamer_read_data_for_src (int16_t *buffer, int frames) { - int channels = fileinfo->channels; + int channels = fileinfo->fmt.channels; if (channels > 2) { channels = 2; } @@ -1379,7 +1409,7 @@ streamer_read_data_for_src (int16_t *buffer, int frames) { static int streamer_read_data_for_src_float (float *buffer, int frames) { - int channels = fileinfo->channels; + int channels = fileinfo->fmt.channels; if (channels > 2) { channels = 2; } @@ -1410,16 +1440,17 @@ streamer_read_data_for_src_float (float *buffer, int frames) { static int streamer_decode_src_libsamplerate (uint8_t *bytes, int size) { + DB_output_t *output = plug_get_output (); int initsize = size; int16_t *out = (int16_t *)bytes; - int samplerate = fileinfo->samplerate; + int samplerate = fileinfo->fmt.samplerate; if (!samplerate) { return 0; } - float ratio = p_get_rate ()/(float)samplerate; + float ratio = output->fmt.samplerate/(float)samplerate; while (size > 0) { int n_output_frames = size / sizeof (int16_t) / 2; - int n_input_frames = n_output_frames * samplerate / p_get_rate () + 100; + int n_input_frames = n_output_frames * samplerate / output->fmt.samplerate + 100; // read data from decoder if (n_input_frames >= SRC_BUFFER - src_remaining ) { n_input_frames = SRC_BUFFER - src_remaining; @@ -1444,7 +1475,7 @@ streamer_decode_src_libsamplerate (uint8_t *bytes, int size) { srcdata.input_frames = src_remaining; srcdata.output_frames = size/4; srcdata.src_ratio = ratio; -// trace ("SRC from %d to %d\n", samplerate, p_get_rate ()); +// trace ("SRC from %d to %d\n", samplerate, output->fmt.samplerate); srcdata.end_of_input = 0;//(nread == n_input_frames) ? 0 : 1; //if (streamer_buffering) src_lock (); @@ -1478,54 +1509,13 @@ streamer_decode_src_libsamplerate (uint8_t *bytes, int size) { } return initsize-size; } - -#if 0 -static int -streamer_decode_src (uint8_t *bytes, int size) { - int initsize = size; - int16_t *out = (int16_t *)bytes; - DB_decoder_t *decoder = streaming_track->decoder; - int samplerate = decoder->info.samplerate; - float ratio = (float)samplerate / p_get_rate (); - while (size > 0) { - int n_output_frames = size / sizeof (int16_t) / 2; - int n_input_frames = n_output_frames * samplerate / p_get_rate () + 100; - // read data from decoder - if (n_input_frames > SRC_BUFFER - src_remaining ) { - n_input_frames = SRC_BUFFER - src_remaining; - } - int nread = streamer_read_data_for_src (&g_src_in_buffer[src_remaining*2], n_input_frames); - src_remaining += nread; - // resample - float idx = 0; - int i = 0; - while (i < n_output_frames && idx < src_remaining) { - int k = (int)idx; - out[0] = g_src_in_buffer[k*2+0]; - out[1] = g_src_in_buffer[k*2+1]; - i++; - idx += ratio; - out += 2; - } - size -= i*4; - src_remaining -= idx; - if (src_remaining < 0) { - src_remaining = 0; - } - else if (src_remaining > 0) { - memmove (g_src_in_buffer, &g_src_in_buffer[(SRC_BUFFER-src_remaining)*2], src_remaining*2*sizeof (int16_t)); - } - if (nread != n_input_frames) { - break; - } - } - return initsize-size; -} #endif +// decodes data and converts to current output format // returns number of bytes been read static int streamer_read_async (char *bytes, int size) { + DB_output_t *output = plug_get_output (); int initsize = size; for (;;) { int bytesread = 0; @@ -1535,13 +1525,36 @@ streamer_read_async (char *bytes, int size) { mutex_unlock (decodemutex); break; } - if (fileinfo->samplerate != -1) { - int nchannels = fileinfo->channels; + if (fileinfo->fmt.samplerate != -1) { + if (!memcmp (&fileinfo->fmt, &output->fmt, sizeof (ddb_waveformat_t)), 0) { + bytesread = fileinfo->plugin->read (fileinfo, bytes, size); + } + else { +// trace ("format mismatch, converting:\n"); +// trace ("input bps=%d, channels=%d, samplerate=%d, channelmask=%X\n", fileinfo->fmt.bps, fileinfo->fmt.channels, fileinfo->fmt.samplerate, fileinfo->fmt.channelmask); +// trace ("output bps=%d, channels=%d, samplerate=%d, channelmask=%X\n", output->fmt.bps, output->fmt.channels, output->fmt.samplerate, output->fmt.channelmask); + + int outputsamplesize = (output->fmt.bps>>3)*output->fmt.channels; + int inputsamplesize = (fileinfo->fmt.bps>>3)*fileinfo->fmt.channels; + int inputsize = size/outputsamplesize*inputsamplesize; + char input[inputsize]; + inputsize = fileinfo->plugin->read (fileinfo, input, inputsize); + bytesread = pcm_convert (&fileinfo->fmt, input, &output->fmt, bytes, inputsize); +// trace ("decoded %d bytes, writing %d bytes, requested %d bytes\n", inputsize, bytesread, size); + } +#if WRITE_DUMP + if (bytesread) { + fwrite (bytes, 1, bytesread, out); + } +#endif + +#if 0 + int nchannels = fileinfo->fmt.channels; if (nchannels > 2) { nchannels = 2; } - int samplerate = fileinfo->samplerate; - if (fileinfo->samplerate == p_get_rate ()) { + int samplerate = fileinfo->fmt.samplerate; + if (fileinfo->fmt.samplerate == output->fmt.samplerate) { // samplerate match if (nchannels == 2) { bytesread = fileinfo->plugin->read_int16 (fileinfo, bytes, size); @@ -1555,31 +1568,32 @@ streamer_read_async (char *bytes, int size) { bytesread *= 2; } } - else if (src_is_valid_ratio (p_get_rate ()/(double)samplerate)) { + else if (src_is_valid_ratio (output->fmt.samplerate/(double)samplerate)) { bytesread = streamer_decode_src_libsamplerate (bytes, size); } else { - fprintf (stderr, "error: invalid ratio! %d / %d (this indicates decoder or streamer bug)\n", p_get_rate (), samplerate); + fprintf (stderr, "error: invalid ratio! %d / %d (this indicates decoder or streamer bug)\n", output->fmt.samplerate, samplerate); fprintf (stderr, "error: file: %s\n", streaming_track ? streaming_track->fname : "(null)"); // immediately start streaming next track bytes_until_next_song = -1; } +#endif } - trace ("streamer: bytesread=%d\n", bytesread); +#if 0 if (bytesread > 0) { // apply dsp DB_dsp_t **dsp = deadbeef->plug_get_dsp_list (); - int srate = p_get_rate (); + int srate = output->fmt.samplerate; for (int i = 0; dsp[i]; i++) { if (dsp[i]->enabled ()) { - dsp[i]->process_int16 ((int16_t *)bytes, bytesread/4, 2, 16, srate); + dsp[i]->process (bytes, bytesread/4, &output->fmt); } } } +#endif mutex_unlock (decodemutex); bytes += bytesread; size -= bytesread; - trace ("streamer: size=%d\n", size); if (size == 0) { return initsize; } @@ -1612,14 +1626,15 @@ streamer_read (char *bytes, int size) { if (!playing_track) { return -1; } + DB_output_t *output = plug_get_output (); streamer_lock (); int sz = min (size, streambuffer_fill); if (sz) { memcpy (bytes, streambuffer, sz); memmove (streambuffer, streambuffer+sz, streambuffer_fill-sz); streambuffer_fill -= sz; - playpos += (float)sz/p_get_rate ()/4.f; - playing_track->playtime += (float)sz/p_get_rate ()/4.f; + playpos += (float)sz/output->fmt.samplerate/((output->fmt.bps>>3)*output->fmt.channels); + playing_track->playtime += (float)sz/output->fmt.samplerate/((output->fmt.bps>>3)*output->fmt.channels); if (playlist_track) { playing_track->filetype = playlist_track->filetype; } @@ -1667,9 +1682,6 @@ streamer_read (char *bytes, int size) { int ms = (tm2.tv_sec*1000+tm2.tv_usec/1000) - (tm1.tv_sec*1000+tm1.tv_usec/1000); printf ("streamer_read took %d ms\n", ms); #endif -#if WRITE_DUMP - fwrite (bytes, 1, sz, out); -#endif return sz; } @@ -1721,14 +1733,15 @@ streamer_configchanged (void) { void streamer_play_current_track (void) { playlist_t *plt = plt_get_curr_ptr (); - if (p_ispaused () && playing_track) { + DB_output_t *output = plug_get_output (); + if (output->state () == OUTPUT_STATE_PAUSED && playing_track) { // unpause currently paused track - p_unpause (); + output->unpause (); plug_trigger_event_paused (0); } else if (plt->current_row[PL_MAIN] != -1) { // play currently selected track in current playlist - p_stop (); + output->stop (); // get next song in queue int idx = -1; playItem_t *next = pl_playqueue_getnext (); @@ -1746,7 +1759,7 @@ streamer_play_current_track (void) { } else { // restart currently playing track - p_stop (); + output->stop (); streamer_set_nextsong (0, 1); } } |