1 /* B.Harvestr 2 * LV2 Plugin 3 * 4 * Copyright (C) 2018 by Sven Jähnichen 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 3, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software Foundation, 18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 */ 20 21 #ifndef SAMPLE_HPP_ 22 #define SAMPLE_HPP_ 23 24 #include "sndfile.h" 25 #include <cstdlib> 26 #include <cstring> 27 #include <string> 28 #include <stdexcept> 29 30 #ifndef SF_FORMAT_MP3 31 #define MINIMP3_IMPLEMENTATION 32 #define MINIMP3_FLOAT_OUTPUT 33 #include "minimp3_ex.h" 34 #endif /* SF_FORMAT_MP3 */ 35 36 37 struct Sample 38 { 39 SF_INFO info; // Info about sample from sndfile 40 float* data; // Sample data in float 41 char* path; // Path of file 42 SampleSample43 Sample () : info {0, 0, 0, 0, 0, 0}, data (nullptr), path (nullptr) {} 44 SampleSample45 Sample (const char* samplepath) : info {0, 0, 0, 0, 0, 0}, data (nullptr), path (nullptr) 46 { 47 if (!samplepath) return; 48 49 int len = strlen (samplepath); 50 path = (char*) malloc (len + 1); 51 if (!path) throw std::bad_alloc(); 52 memcpy (path, samplepath, len + 1); 53 54 // Extract file extension 55 char* extptr = strrchr (path, '.'); 56 const int extsz = (extptr ? strlen (extptr) + 1 : 1); 57 char* ext = (char*) malloc (extsz); 58 if (!ext) throw std::bad_alloc(); 59 ext[0] = 0; 60 if (extsz > 1) memcpy (ext, extptr, extsz); 61 for (char* s = ext; *s; ++s) *s = tolower ((unsigned char)*s); 62 63 64 // Check for known non-sndfiles 65 #ifdef MINIMP3_IMPLEMENTATION 66 if (!strcmp (ext, ".mp3")) 67 { 68 mp3dec_t mp3dec; 69 mp3dec_file_info_t mp3info; 70 if (mp3dec_load (&mp3dec, path, &mp3info, NULL, NULL)) throw std::invalid_argument ("Can't open " + std::string (path) + "."); 71 72 info.samplerate = mp3info.hz; 73 info.channels = mp3info.channels; 74 info.frames = mp3info.samples / mp3info.channels; 75 76 data = (float*) malloc (sizeof(float) * info.frames * info.channels); 77 if (!data) throw std::bad_alloc(); 78 79 memcpy (data, mp3info.buffer, sizeof(float) * info.frames * info.channels); 80 } 81 82 else 83 #endif /* MINIMP3_IMPLEMENTATION */ 84 85 { 86 SNDFILE* sndfile = sf_open (samplepath, SFM_READ, &info); 87 88 if (!sndfile || !info.frames) throw std::invalid_argument ("Can't open " + std::string (path) + "."); 89 90 // Read & render data 91 data = (float*) malloc (sizeof(float) * info.frames * info.channels); 92 if (!data) 93 { 94 sf_close (sndfile); 95 throw std::bad_alloc(); 96 } 97 98 sf_seek (sndfile, 0, SEEK_SET); 99 sf_read_float (sndfile, data, info.frames * info.channels); 100 sf_close (sndfile); 101 } 102 } 103 ~SampleSample104 ~Sample() 105 { 106 if (data) free (data); 107 if (path) free (path); 108 } 109 getSample110 float get (const sf_count_t frame, const int channel, const int rate) 111 { 112 if (!data) return 0.0f; 113 114 // Direct access if same frame rate 115 if (info.samplerate == rate) 116 { 117 if (frame >= info.frames) return 0.0f; 118 else return data[frame * info.channels + channel]; 119 } 120 121 // Linear rendering (TODO) if frame rates differ 122 double f = (frame * info.samplerate) / rate; 123 sf_count_t f1 = f; 124 125 if (f1 + 1 >= info.frames) return 0.0f; 126 if (f1 == f) return data[f1 * info.channels + channel]; 127 128 float data1 = data[f1 * info.channels + channel]; 129 float data2 = data[(f1 + 1) * info.channels + channel]; 130 return data1 + (f - double (f1)) * (data2 - data1); 131 } 132 }; 133 134 #endif /* SAMPLE_HPP_ */ 135