annotate thread/BlockAllocator.h @ 298:255e431ae3d4

* Key detector: when returning key strengths, use the peak value of the three underlying chromagram correlations (from 36-bin chromagram) corresponding to each key, instead of the mean. Rationale: This is the same method as used when returning the key value, and it's nice to have the same results in both returned value and plot. The peak performed better than the sum with a simple test set of triads, so it seems reasonable to change the plot to match the key output rather than the other way around. * FFT: kiss_fftr returns only the non-conjugate bins, synthesise the rest rather than leaving them (perhaps dangerously) undefined. Fixes an uninitialised data error in chromagram that could cause garbage results from key detector. * Constant Q: remove precalculated values again, I reckon they're not proving such a good tradeoff.
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 05 Jun 2009 15:12:39 +0000
parents b97f4f926f48
children 701233f8ed41
rev   line source
c@292 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@292 2
c@292 3 /*
c@292 4 QM DSP Library
c@292 5
c@292 6 Centre for Digital Music, Queen Mary, University of London.
c@292 7
c@292 8 This file is derived from the FSB Allocator by Juha Nieminen. The
c@292 9 underlying method is unchanged, but the class has been refactored
c@292 10 to permit multiple separate allocators (e.g. one per thread)
c@292 11 rather than use a single global one (and to fit house style).
c@292 12
c@292 13 Copyright (c) 2008 Juha Nieminen
c@292 14
c@292 15 Permission is hereby granted, free of charge, to any person obtaining a copy
c@292 16 of this software and associated documentation files (the "Software"), to deal
c@292 17 in the Software without restriction, including without limitation the rights
c@292 18 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
c@292 19 copies of the Software, and to permit persons to whom the Software is
c@292 20 furnished to do so, subject to the following conditions:
c@292 21
c@292 22 The above copyright notice and this permission notice shall be included in
c@292 23 all copies or substantial portions of the Software.
c@292 24
c@292 25 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
c@292 26 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
c@292 27 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
c@292 28 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
c@292 29 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
c@292 30 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
c@292 31 THE SOFTWARE.
c@292 32 */
c@292 33
c@292 34 #ifndef _BLOCK_ALLOCATOR_H_
c@292 35 #define _BLOCK_ALLOCATOR_H_
c@292 36
c@292 37 #include <cstdlib>
c@292 38
c@292 39 /**
c@292 40 * BlockAllocator is a simple allocator for fixed-size (usually small)
c@292 41 * chunks of memory. The size of an element is specified in the
c@292 42 * BlockAllocator constructor, and the functions allocate() and
c@292 43 * deallocate() are used to obtain and release a single element at a
c@292 44 * time.
c@292 45 *
c@292 46 * BlockAllocator may be an appropriate class to use in situations
c@292 47 * involving a very large number of allocations and deallocations of
c@292 48 * simple, identical objects across multiple threads (a hard situation
c@292 49 * for a generic system malloc implementation to handle well). Retain
c@292 50 * one BlockAllocator per thread (the class itself is not
c@292 51 * thread-safe), and ensure that each thread uses its own allocator
c@292 52 * exclusively.
c@292 53 *
c@292 54 * BlockAllocator is based on Juha Nieminen's more general
c@292 55 * FSBAllocator.
c@292 56 */
c@292 57 class BlockAllocator
c@292 58 {
c@292 59 public:
c@292 60 typedef std::size_t data_t;
c@292 61
c@292 62 BlockAllocator(int elementSize) : m_sz(elementSize) { }
c@292 63
c@292 64 void *
c@292 65 allocate()
c@292 66 {
c@292 67 if (m_freelist.empty()) {
c@292 68 m_freelist.push_back(m_blocks.data.size());
c@292 69 m_blocks.data.push_back(Block(this));
c@292 70 }
c@292 71
c@292 72 const data_t index = m_freelist.back();
c@292 73 Block &block = m_blocks.data[index];
c@292 74 void *retval = block.allocate(index);
c@292 75 if (block.isFull()) m_freelist.pop_back();
c@292 76
c@292 77 return retval;
c@292 78 }
c@292 79
c@292 80 void
c@292 81 deallocate(void *ptr)
c@292 82 {
c@292 83 if (!ptr) return;
c@292 84
c@292 85 data_t *unitPtr = (data_t *)ptr;
c@292 86 const data_t blockIndex = unitPtr[elementSizeInDataUnits()];
c@292 87 Block& block = m_blocks.data[blockIndex];
c@292 88
c@292 89 if (block.isFull()) m_freelist.push_back(blockIndex);
c@292 90 block.deallocate(unitPtr);
c@292 91 }
c@292 92
c@292 93 private:
c@292 94 inline data_t elementsPerBlock() const {
c@292 95 return 512;
c@292 96 }
c@292 97 inline data_t dataSize() const {
c@292 98 return sizeof(data_t);
c@292 99 }
c@292 100 inline data_t elementSizeInDataUnits() const {
c@292 101 return (m_sz + (dataSize() - 1)) / dataSize();
c@292 102 }
c@292 103 inline data_t unitSizeInDataUnits() const {
c@292 104 return elementSizeInDataUnits() + 1;
c@292 105 }
c@292 106 inline data_t blockSizeInDataUnits() const {
c@292 107 return elementsPerBlock() * unitSizeInDataUnits();
c@292 108 }
c@292 109
c@292 110 class Block
c@292 111 {
c@292 112 public:
c@292 113 Block(BlockAllocator *a) :
c@292 114 m_a(a),
c@292 115 m_block(0),
c@292 116 m_firstFreeUnit(data_t(-1)),
c@292 117 m_allocated(0),
c@292 118 m_end(0)
c@292 119 {}
c@292 120
c@292 121 ~Block() {
c@292 122 delete[] m_block;
c@292 123 }
c@292 124
c@292 125 bool isFull() const {
c@292 126 return m_allocated == m_a->elementsPerBlock();
c@292 127 }
c@292 128
c@292 129 void clear() {
c@292 130 delete[] m_block;
c@292 131 m_block = 0;
c@292 132 m_firstFreeUnit = data_t(-1);
c@292 133 }
c@292 134
c@292 135 void *allocate(data_t index) {
c@292 136
c@292 137 if (m_firstFreeUnit == data_t(-1)) {
c@292 138
c@292 139 if (!m_block) {
c@292 140 m_block = new data_t[m_a->blockSizeInDataUnits()];
c@292 141 m_end = 0;
c@292 142 }
c@292 143
c@292 144 data_t *retval = m_block + m_end;
c@292 145 m_end += m_a->unitSizeInDataUnits();
c@292 146 retval[m_a->elementSizeInDataUnits()] = index;
c@292 147 ++m_allocated;
c@292 148 return retval;
c@292 149
c@292 150 } else {
c@292 151
c@292 152 data_t *retval = m_block + m_firstFreeUnit;
c@292 153 m_firstFreeUnit = *retval;
c@292 154 ++m_allocated;
c@292 155 return retval;
c@292 156 }
c@292 157 }
c@292 158
c@292 159 void deallocate(data_t *ptr) {
c@292 160
c@292 161 *ptr = m_firstFreeUnit;
c@292 162 m_firstFreeUnit = ptr - m_block;
c@292 163
c@292 164 if (--m_allocated == 0) clear();
c@292 165 }
c@292 166
c@292 167 private:
c@292 168 const BlockAllocator *m_a;
c@292 169 data_t *m_block;
c@292 170 data_t m_firstFreeUnit;
c@292 171 data_t m_allocated;
c@292 172 data_t m_end;
c@292 173 };
c@292 174
c@292 175 struct Blocks
c@292 176 {
c@292 177 std::vector<Block> data;
c@292 178
c@292 179 Blocks() {
c@292 180 data.reserve(1024);
c@292 181 }
c@292 182 };
c@292 183
c@292 184 const int m_sz;
c@292 185 Blocks m_blocks;
c@292 186 std::vector<data_t> m_freelist;
c@292 187 };
c@292 188
c@292 189 #endif