summaryrefslogtreecommitdiff
path: root/plugins/adplug/adplug/u6m.h
blob: f09d0211bf3096918aec9ada4278217659278695 (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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
 * Adplug - Replayer for many OPL2/OPL3 audio file formats.
 * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * u6m.h - Ultima 6 Music Player by Marc Winterrowd.
 * This code extends the Adlib Winamp plug-in by Simon Peter <dn.tlp@gmx.net>
 */

#include <string.h>
#include "player.h"

#define default_dict_size 4096     // because maximum codeword size == 12 bits
#define max_codeword_length 12     // maximum codeword length in bits

class Cu6mPlayer: public CPlayer
{
 public:
  static CPlayer *factory(Copl *newopl);

  Cu6mPlayer(Copl *newopl) : CPlayer(newopl), song_data(0), subsong_stack_sz(0)
    {
    };


  ~Cu6mPlayer()
    {
      if(song_data) delete[] song_data;
    };

  bool load(const char *filename, const CFileProvider &fp);
  bool update();
  void rewind(int subsong);
  float getrefresh();

  const char * gettype()
    {
      return "Ultima 6 Music";
    };

 protected:

  struct byte_pair
  {
    unsigned char lo;
    unsigned char hi;
  };

  struct subsong_info   // information about a subsong
  {
    int continue_pos;
    int subsong_repetitions;
    int subsong_start;
  };

  struct dict_entry   // dictionary entry
  {
    unsigned char root;
    int codeword;
  };

  struct data_block   // 
  {
    long size;
    unsigned char *data;
  };

  class MyDict
    {
    private:
      // The actual number of dictionary entries allocated
      // is (dictionary_size-256), because there are 256 roots
      // that do not need to be stored.
      int contains; // number of entries currently in the dictionary
      int dict_size; // max number of entries that will fit into the dictionary
      dict_entry* dictionary;

    public:
      MyDict(); // use dictionary size of 4096
      MyDict(int); // let the caller specify a dictionary size
      ~MyDict();
      void reset(); // re-initializes the dictionary
      void add(unsigned char, int);
      unsigned char get_root(int);
      int get_codeword(int);
    };


  // class variables
  long played_ticks;

  unsigned char* song_data;   // the uncompressed .m file (the "song")
  bool driver_active;         // flag to prevent reentrancy
  bool songend;				// indicates song end
  int song_pos;               // current offset within the song
  int loop_position;          // position of the loop point
  int read_delay;             // delay (in timer ticks) before further song data is read
  enum {MAX_SUBSONG_STACK = 100};
  subsong_info subsong_stack[MAX_SUBSONG_STACK];
  int subsong_stack_sz;

  int instrument_offsets[9];  // offsets of the adlib instrument data
  // vibrato ("vb")
  unsigned char vb_current_value[9];
  unsigned char vb_double_amplitude[9];
  unsigned char vb_multiplier[9];
  unsigned char vb_direction_flag[9];
  // mute factor ("mf") = not(volume)
  unsigned char carrier_mf[9];
  signed char carrier_mf_signed_delta[9];
  unsigned char carrier_mf_mod_delay_backup[9];
  unsigned char carrier_mf_mod_delay[9];
  // frequency
  byte_pair channel_freq[9];  // adlib freq settings for each channel
  signed char channel_freq_signed_delta[9];

  // protected functions used by update()
  void command_loop();
  unsigned char read_song_byte();
  signed char read_signed_song_byte();
  void dec_clip(int&);
  byte_pair expand_freq_byte(unsigned char);
  void set_adlib_freq(int channel,byte_pair freq_word);
  void set_adlib_freq_no_update(int channel,byte_pair freq_word);
  void set_carrier_mf(int channel,unsigned char mute_factor);
  void set_modulator_mf(int channel,unsigned char mute_factor);
  void freq_slide(int channel);
  void vibrato(int channel);
  void mf_slide(int channel);

  void command_0(int channel);
  void command_1(int channel);
  void command_2(int channel);
  void command_3(int channel);
  void command_4(int channel);
  void command_5(int channel);
  void command_6(int channel);
  void command_7(int channel);
  void command_81();
  void command_82();
  void command_83();
  void command_85();
  void command_86();
  void command_E();
  void command_F();

  void out_adlib(unsigned char adlib_register, unsigned char adlib_data);
  void out_adlib_opcell(int channel, bool carrier, unsigned char adlib_register, unsigned char out_byte);

  // protected functions used by load()
  bool lzw_decompress(data_block source, data_block dest);
  int get_next_codeword (long& bits_read, unsigned char *source, int codeword_size);
  void output_root(unsigned char root, unsigned char *destination, long& position);
  //void get_string(int codeword, MyDict& dictionary, std::stack<unsigned char>& root_stack);
  void get_string(int codeword, MyDict& dictionary, unsigned char *root_stack, int &root_stack_size);
};