summaryrefslogtreecommitdiff
path: root/apps/plugins/lua/lzio.c
blob: 293edd59b08f1e57b361b4cfb9ad63e384f14b1b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/*
** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
** a generic input stream interface
** See Copyright Notice in lua.h
*/


#include <string.h>

#define lzio_c
#define LUA_CORE

#include "lua.h"

#include "llimits.h"
#include "lmem.h"
#include "lstate.h"
#include "lzio.h"


int luaZ_fill (ZIO *z) {
  size_t size;
  lua_State *L = z->L;
  const char *buff;
  lua_unlock(L);
  buff = z->reader(L, z->data, &size);
  lua_lock(L);
  if (buff == NULL || size == 0) return EOZ;
  z->n = size - 1;
  z->p = buff;
  return char2int(*(z->p++));
}


int luaZ_lookahead (ZIO *z) {
  if (z->n == 0) {
    if (luaZ_fill(z) == EOZ)
      return EOZ;
    else {
      z->n++;  /* luaZ_fill removed first byte; put back it */
      z->p--;
    }
  }
  return char2int(*z->p);
}


void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) {
  z->L = L;
  z->reader = reader;
  z->data = data;
  z->n = 0;
  z->p = NULL;
}


/* --------------------------------------------------------------- read --- */
size_t luaZ_read (ZIO *z, void *b, size_t n) {
  while (n) {
    size_t m;
    if (luaZ_lookahead(z) == EOZ)
      return n;  /* return number of missing bytes */
    m = (n <= z->n) ? n : z->n;  /* min. between n and z->n */
    memcpy(b, z->p, m);
    z->n -= m;
    z->p += m;
    b = (char *)b + m;
    n -= m;
  }
  return 0;
}

/* ------------------------------------------------------------------------ */
char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) {
  if (n > buff->buffsize) {
    if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
    luaZ_resizebuffer(L, buff, n);
  }
  return buff->buffer;
}


="hl kwb">struct codec_api *)data; return ci->filesize; } static mpc_bool_t canseek_impl(void *data) { (void)data; /* doesn't much matter, libmusepack ignores this anyway */ return true; } MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH] IBSS_ATTR_MPC_SAMPLE_BUF; /* this is the codec entry point */ enum codec_status codec_main(void) { mpc_int64_t samplesdone; uint32_t frequency; /* 0.1 kHz accuracy */ uint32_t elapsed_time; /* milliseconds */ unsigned status; mpc_reader reader; mpc_streaminfo info; int retval = CODEC_OK; /* musepack's sample representation is 18.14 * DSP_SET_SAMPLE_DEPTH = 14 (FRACT) + 16 (NATIVE) - 1 (SIGN) = 29 */ ci->configure(DSP_SET_SAMPLE_DEPTH, 29); /* Create a decoder instance */ reader.read = read_impl; reader.seek = seek_impl; reader.tell = tell_impl; reader.get_size = get_size_impl; reader.canseek = canseek_impl; reader.data = ci; next_track: if (codec_init()) { retval = CODEC_ERROR; goto exit; } while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); samplesdone = ci->id3->offset; /* read file's streaminfo data */ mpc_streaminfo_init(&info); if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) { retval = CODEC_ERROR; goto done; } frequency = info.sample_freq / 100; /* 0.1 kHz accuracy */ ci->configure(DSP_SWITCH_FREQUENCY, info.sample_freq); /* set playback engine up for correct number of channels */ /* NOTE: current musepack format only allows for stereo files but code is here to handle other configurations anyway */ if (info.channels == 2) ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); else if (info.channels == 1) ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); else { retval = CODEC_ERROR; goto done; } codec_set_replaygain(ci->id3); /* instantiate a decoder with our file reader */ mpc_decoder_setup(&decoder, &reader); if (!mpc_decoder_initialize(&decoder, &info)) { retval = CODEC_ERROR; goto done; } /* Resume to saved sample offset. */ if (samplesdone > 0) { /* hack to improve seek time if filebuf goes empty */ if (mpc_decoder_seek_sample(&decoder, samplesdone)) { elapsed_time = (samplesdone*10)/frequency; ci->set_elapsed(elapsed_time); } else { samplesdone = 0; } /* reset chunksize */ } /* This is the decoding loop. */ do { /* Complete seek handler. */ if (ci->seek_time) { /* hack to improve seek time if filebuf goes empty */ mpc_int64_t new_offset = ((ci->seek_time - 1)/10)*frequency; if (mpc_decoder_seek_sample(&decoder, new_offset)) { samplesdone = new_offset; ci->set_elapsed(ci->seek_time); } ci->seek_complete(); /* reset chunksize */ } if (ci->stop_codec || ci->new_track) break; status = mpc_decoder_decode(&decoder, sample_buffer, NULL, NULL); ci->yield(); if (status == 0) /* end of file reached */ goto done; if (status == (unsigned)(-1)) { /* decode error */ retval = CODEC_ERROR; goto done; } else { ci->pcmbuf_insert(sample_buffer, sample_buffer + MPC_FRAME_LENGTH, status); samplesdone += status; elapsed_time = (samplesdone*10)/frequency; ci->set_elapsed(elapsed_time); ci->set_offset(samplesdone); } } while (status != 0); retval = CODEC_OK; done: if (ci->request_next_track()) goto next_track; exit: return retval; }