~mkas/mixxx/mysql

« back to all changes in this revision

Viewing changes to mixxx/src/cachingreader.cpp

  • Committer: MKas
  • Date: 2012-11-03 12:55:54 UTC
  • Revision ID: mkas@tux.lt-20121103125554-ez5ajqyk7bwehrp2
merge with trunk + sql fixes

Show diffs side-by-side

added added

removed removed

Lines of Context:
72
72
 
73
73
    m_pSample = new SAMPLE[kSamplesPerChunk];
74
74
 
75
 
    Q_ASSERT(kSamplesPerChunk * sizeof(CSAMPLE) == kChunkLength);
76
 
 
77
75
    int total_chunks = memory_to_use / kChunkLength;
78
76
 
79
77
    //qDebug() << "CachingReader using" << memory_to_use << "bytes.";
105
103
 
106
104
// static
107
105
Chunk* CachingReader::removeFromLRUList(Chunk* chunk, Chunk* head) {
108
 
    Q_ASSERT(chunk);
 
106
    if (chunk == NULL) {
 
107
        qDebug() << "ERROR: NULL chunk argument to removeFromLRUList";
 
108
        return NULL;
 
109
    }
109
110
 
110
111
    // Remove chunk from the doubly-linked list.
111
112
    Chunk* next = chunk->next_lru;
130
131
 
131
132
// static
132
133
Chunk* CachingReader::insertIntoLRUList(Chunk* chunk, Chunk* head) {
133
 
    Q_ASSERT(chunk);
 
134
    if (chunk == NULL) {
 
135
        qDebug() << "ERROR: NULL chunk argument to insertIntoLRUList";
 
136
        return NULL;
 
137
    }
134
138
 
135
139
    // Chunk is the new head of the list, so connect the head as the next from
136
140
    // chunk.
153
157
 
154
158
    // We'll tolerate not being in allocatedChunks because sometime you free a
155
159
    // chunk right after you allocated it.
156
 
    Q_ASSERT(removed <= 1);
 
160
    if (removed > 1) {
 
161
        qDebug() << "ERROR: freeChunk free'd a chunk that was multiply-allocated.";
 
162
    }
157
163
 
158
164
    // If this is the LRU chunk then set its previous LRU chunk to the LRU
159
165
    if (m_lruChunk == pChunk) {
197
203
Chunk* CachingReader::allocateChunkExpireLRU() {
198
204
    Chunk* chunk = allocateChunk();
199
205
    if (chunk == NULL) {
200
 
        Q_ASSERT(m_lruChunk);
 
206
        if (m_lruChunk == NULL) {
 
207
            qDebug() << "ERROR: No LRU chunk to free in allocateChunkExpireLRU.";
 
208
            return NULL;
 
209
        }
201
210
        //qDebug() << "Expiring LRU" << m_lruChunk << m_lruChunk->chunk_number;
202
211
        freeChunk(m_lruChunk);
203
212
        chunk = allocateChunk();
204
 
        Q_ASSERT(chunk);
205
213
    }
206
214
    //qDebug() << "allocateChunkExpireLRU" << chunk;
207
215
    return chunk;
215
223
        chunk = m_allocatedChunks.value(chunk_number);
216
224
 
217
225
        // Make sure we're all in agreement here.
218
 
        Q_ASSERT(chunk_number == chunk->chunk_number);
219
 
 
 
226
        if (chunk_number != chunk->chunk_number) {
 
227
            qDebug() << "ERROR: Inconsistent chunk has chunk_number that doesn't match allocated-chunks key.";
 
228
        }
220
229
 
221
230
        // If this is the LRU chunk then set the previous LRU to the new LRU
222
231
        if (chunk == m_lruChunk && chunk->prev_lru != NULL) {
293
302
            m_iTrackNumSamplesCallbackSafe = status.trackNumSamples;
294
303
        } else if (status.status == CHUNK_READ_SUCCESS) {
295
304
            Chunk* pChunk = status.chunk;
296
 
            Q_ASSERT(pChunk != NULL);
 
305
            if (pChunk == NULL) {
 
306
                qDebug() << "ERROR: status.chunk is NULL in CHUNK_READ_SUCCESS ReaderStatusUpdate. Ignoring update.";
 
307
                continue;
 
308
            }
297
309
            Chunk* pChunk2 = m_chunksBeingRead.take(pChunk->chunk_number);
298
310
            if (pChunk2 != pChunk) {
299
311
                qDebug() << "Mismatch in requested chunk to read!";
320
332
            }
321
333
        } else if (status.status == CHUNK_READ_EOF) {
322
334
            Chunk* pChunk = status.chunk;
323
 
            Q_ASSERT(pChunk != NULL);
 
335
            if (pChunk == NULL) {
 
336
                qDebug() << "ERROR: status.chunk is NULL in CHUNK_READ_EOF ReaderStatusUpdate. Ignoring update.";
 
337
                continue;
 
338
            }
324
339
            Chunk* pChunk2 = m_chunksBeingRead.take(pChunk->chunk_number);
325
340
            if (pChunk2 != pChunk) {
326
341
                qDebug() << "Mismatch in requested chunk to read!";
329
344
        } else if (status.status == CHUNK_READ_INVALID) {
330
345
            qDebug() << "WARNING: READER THREAD RECEIVED INVALID CHUNK READ";
331
346
            Chunk* pChunk = status.chunk;
332
 
            Q_ASSERT(pChunk != NULL);
 
347
            if (pChunk == NULL) {
 
348
                qDebug() << "ERROR: status.chunk is NULL in CHUNK_READ_INVALID ReaderStatusUpdate. Ignoring update.";
 
349
                continue;
 
350
            }
333
351
            Chunk* pChunk2 = m_chunksBeingRead.take(pChunk->chunk_number);
334
352
            if (pChunk2 != pChunk) {
335
353
                qDebug() << "Mismatch in requested chunk to read!";
340
358
}
341
359
 
342
360
int CachingReader::read(int sample, int num_samples, CSAMPLE* buffer) {
343
 
    int zerosWritten = 0;
344
 
    // Check for bogus sample numbers
345
 
    //Q_ASSERT(sample >= 0);
346
 
    QString temp = QString("Sample = %1").arg(sample);
347
 
    QByteArray tempBA = QString(temp).toUtf8();
348
 
    Q_ASSERT_X(sample % 2 == 0,"CachingReader::read",tempBA);
349
 
    Q_ASSERT(num_samples >= 0);
 
361
    // Check for bad inputs
 
362
    if (sample % 2 != 0 || num_samples < 0 || !buffer) {
 
363
        QString temp = QString("Sample = %1").arg(sample);
 
364
        QByteArray tempBA = QString(temp).toUtf8();
 
365
        qDebug() << "CachingReader::read() invalid arguments sample:" << sample
 
366
                 << "num_samples:" << num_samples << "buffer:" << buffer;
 
367
        return 0;
 
368
    }
350
369
 
351
370
    // If asked to read 0 samples, don't do anything. (this is a perfectly
352
371
    // reasonable request that happens sometimes. If no track is loaded, don't
363
382
    // it makes preroll completely transparent to the rest of the code
364
383
 
365
384
    //if we're in preroll...
 
385
    int zerosWritten = 0;
366
386
    if (sample < 0) {
367
387
        if (sample + num_samples <= 0) {
368
388
            //everything is zeros, easy
390
410
    int current_sample = sample;
391
411
 
392
412
    // Sanity checks
393
 
    Q_ASSERT(start_chunk <= end_chunk);
 
413
    if (start_chunk > end_chunk) {
 
414
        qDebug() << "CachingReader::read() bad chunk range to read ["
 
415
                 << start_chunk << end_chunk << "]";
 
416
        return 0;
 
417
    }
394
418
 
395
419
    for (int chunk_num = start_chunk; chunk_num <= end_chunk; chunk_num++) {
396
420
        Chunk* current = lookupChunk(chunk_num);
411
435
        int chunk_remaining_samples = current->length - chunk_offset;
412
436
 
413
437
        // More sanity checks
414
 
        Q_ASSERT(current_sample >= chunk_start_sample);
415
 
        Q_ASSERT(current_sample % 2 == 0);
416
 
 
417
 
        if (start_chunk != chunk_num) {
418
 
            Q_ASSERT(chunk_start_sample == current_sample);
419
 
        }
420
 
 
421
 
        Q_ASSERT(samples_remaining >= 0);
 
438
        if (current_sample < chunk_start_sample || current_sample % 2 != 0) {
 
439
            qDebug() << "CachingReader::read() bad chunk parameters"
 
440
                     << "chunk_start_sample" << chunk_start_sample
 
441
                     << "current_sample" << current_sample;
 
442
            break;
 
443
        }
 
444
 
 
445
        // If we're past the start_chunk then current_sample should be
 
446
        // chunk_start_sample.
 
447
        if (start_chunk != chunk_num && chunk_start_sample != current_sample) {
 
448
            qDebug() << "CachingReader::read() bad chunk parameters"
 
449
                     << "chunk_num" << chunk_num
 
450
                     << "start_chunk" << start_chunk
 
451
                     << "chunk_start_sample" << chunk_start_sample
 
452
                     << "current_sample" << current_sample;
 
453
            break;
 
454
        }
 
455
 
 
456
        if (samples_remaining < 0) {
 
457
            qDebug() << "CachingReader::read() bad samples remaining"
 
458
                     << samples_remaining;
 
459
            break;
 
460
        }
 
461
 
422
462
        // It is completely possible that chunk_remaining_samples is less than
423
463
        // zero. If the caller is trying to read from beyond the end of the
424
464
        // file, then this can happen. We should tolerate it.
425
 
 
426
465
        int samples_to_read = math_max(0, math_min(samples_remaining,
427
466
                                                   chunk_remaining_samples));
428
467
 
429
 
        // samples_to_read should be non-negative and even
430
 
        Q_ASSERT(samples_to_read >= 0);
431
 
        Q_ASSERT(samples_to_read % 2 == 0);
432
 
 
433
 
        CSAMPLE *data = current->data + chunk_offset;
434
 
 
435
468
        // If we did not decide to read any samples from this chunk then that
436
469
        // means we have exhausted all the samples in the song.
437
470
        if (samples_to_read == 0) {
438
471
            break;
439
472
        }
440
473
 
 
474
        // samples_to_read should be non-negative and even
 
475
        if (samples_to_read < 0 || samples_to_read % 2 != 0) {
 
476
            qDebug() << "CachingReader::read() samples_to_read invalid"
 
477
                     << samples_to_read;
 
478
            break;
 
479
        }
 
480
 
441
481
        // TODO(rryan) do a test and see if using memcpy is faster than gcc
442
482
        // optimizing the for loop
 
483
        CSAMPLE *data = current->data + chunk_offset;
443
484
        memcpy(buffer, data, sizeof(*buffer) * samples_to_read);
444
485
        // for (int i=0; i < samples_to_read; i++) {
445
486
        //     buffer[i] = data[i];
459
500
    }
460
501
    samples_remaining = 0;
461
502
 
462
 
    Q_ASSERT(samples_remaining == 0);
 
503
    if (samples_remaining != 0) {
 
504
        qDebug() << "CachingReader::read() did read all requested samples.";
 
505
    }
463
506
    return zerosWritten + num_samples - samples_remaining;
464
507
}
465
508
 
496
539
                hint.sample = 0;
497
540
            }
498
541
        }
499
 
        Q_ASSERT(hint.length >= 0);
 
542
        if (hint.length < 0) {
 
543
            qDebug() << "ERROR: Negative hint length. Ignoring.";
 
544
            continue;
 
545
        }
500
546
        int start_sample = math_max(0, math_min(
501
547
            m_iTrackNumSamplesCallbackSafe, hint.sample));
502
548
        int start_chunk = chunkForSample(start_sample);
521
567
        if (!m_chunksBeingRead.contains(chunk) && lookupChunk(chunk) == NULL) {
522
568
            shouldWake = true;
523
569
            Chunk* pChunk = allocateChunkExpireLRU();
524
 
            Q_ASSERT(pChunk != NULL);
525
 
 
 
570
            if (pChunk == NULL) {
 
571
                qDebug() << "ERROR: Couldn't allocate spare Chunk to make ChunkReadRequest.";
 
572
                continue;
 
573
            }
526
574
            m_chunksBeingRead.insert(chunk, pChunk);
527
575
            ChunkReadRequest request;
528
576
            pChunk->chunk_number = chunk;