File: lfsr.cpp

package info (click to toggle)
csound 1%3A6.18.1%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 63,220 kB
  • sloc: ansic: 192,643; cpp: 14,149; javascript: 9,654; objc: 9,181; python: 3,376; java: 3,337; sh: 1,840; yacc: 1,255; xml: 985; perl: 635; lisp: 411; tcl: 341; lex: 217; makefile: 128
file content (139 lines) | stat: -rw-r--r-- 4,882 bytes parent folder | download | duplicates (2)
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
/*
  lsfr.cpp: Linear Feedback Shift Register opcode

  Copyright (C) 2020 Dave Seidel
  This file is part of Csound.

  Based on code by Patrick Dowling in the Ornament & Crime firmware;
  see original copyright notice below this one.

  Original code may be found at:
  https://github.com/mxmxmx/O_C/blob/master/software/o_c_REV/util/util_turing.h

  The Csound 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.

  Csound 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 Csound; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  02110-1301 USA
*/

// ORIGINAL COPYRIGHT NOTICE
//
// Copyright (c) 2016 Patrick Dowling
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/**
 * Linear Feedback Shift Register (LFSR) opcode.
 * 
 * Description
 * 
 *      Output is a series of pseudo-random positive integers. This is the technique
 *      used in so-called "Turing machine" synth modules and is usually used to
 *      generate melodic sequences. This implementation is adapted from the firmware
 *      for the Ornament & Crime module, as used in the Quantermain and Meta-Q apps.
 * 
 * Syntax
 *
 *      knum lfsr ilen, iprob [, iseed]
 *
 *      knum = lfsr(ilen, iprob [, iseed])
 *
 * Initialization
 * 
 *      ilen -- length of shift register, valid values are 1-31 (inclusive). The
 *      larger the length, the larger the resulting integers in the output. You
 *      can use this to constrain the output to a suitable range.
 * 
 *      iprob -- probability, valid values 1-255 (inclusive). Controls the spread
 *      of the output; larger values result in a wider spread of values.
 * 
 *      iseed (optional, default -1) -- initial state of the shift register, as a
 *      pattern of bits. The value is treated as an unsigned integer, so the default
 *      of -1 is effectively all bits on (0b11111111...).
 *  
 * Performance
 * 
 *      knum -- Integer output.
 */

#include <time.h>
#include <plugin.h>

struct LFSR : csnd::Plugin<1, 3> {
    static constexpr char const *otypes = "k";
    static constexpr char const *itypes = "iij";

    uint8_t length_;
    uint8_t probability_;
    uint32_t shift_register_;

    uint32_t _process() {
        uint32_t shift_register = shift_register_;

        // Toggle LSB; there might be better random options
        if (255 == probability_ || static_cast<uint8_t>((rand() % (255 + 1)) < probability_)) {
            shift_register ^= 0x1;
        }

        uint32_t lsb_mask = 0x1 << (length_ - 1);
        if (shift_register & 0x1) {
            shift_register = (shift_register >> 1) | lsb_mask;
        } else {
            shift_register = (shift_register >> 1) & ~lsb_mask;
        }

        // hack... don't turn all zero ...
        if (!shift_register) {
            shift_register |= ((rand() % (0x2 + 1)) << (length_ - 1));
        }

        shift_register_ = shift_register;
        return shift_register & ~(0xffffffff << length_);
    }

    int init() {
        srand(time(NULL));

        length_ = inargs[0];
        probability_ = inargs[1];
        shift_register_ = in_count() == 3 ? inargs[2] : 0xffffffff;

        return OK;
    }

    int kperf() {
        outargs[0] = (int) _process();
        return OK;
    }
};

#include <modload.h>
void csnd::on_load(Csound *csound) {
  csnd::plugin<LFSR>(csound, "lfsr", "k", "iij", csnd::thread::ik);
}