├── Makefile ├── README.md └── musicplayer.c /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-lsndfile 3 | 4 | musicmake: musicplayer.c 5 | $(CC) -o musicplayer musicplayer.c $(CFLAGS) 6 | 7 | clean: 8 | rm musicplayer 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # musicplayer 2 | 3 | Play .wav audio file via system bus. 4 | 5 | Based on the work of https://github.com/fulldecent/system-bus-radio 6 | 7 | We make use of Pulse Density Modulation (PDM) (see https://en.wikipedia.org/wiki/Pulse-density_modulation for more 8 | information). The Pulse Code Modulation (PCM) data from a .wav file is converted to a PDM bit stream. 9 | 10 | Each PDM bit, is output at the same sample rate as the audio. If we see a bit with a value of 1, we make use of the 11 | _mm_stream_si128 instructions, otherwise we simply use a busy-wait loop. We perform each of these operations for a duration 12 | of 1/samplerate seconds. 13 | 14 | You simply use sox to convert your audio to a high sample rate such as 1MHz, as seen below (This 15 | high rate is necessary for PDM). 16 | 17 | ``` 18 | make 19 | sox in.wav -r 1000000 out.wav 20 | ./musicplayer out.wav 21 | ``` 22 | 23 | ### Requirements 24 | 25 | * Sox 26 | * libsndfile - http://www.mega-nerd.com/libsndfile/ 27 | -------------------------------------------------------------------------------- /musicplayer.c: -------------------------------------------------------------------------------- 1 | // Music Player - Anfractuosity 2 | // https://github.com/anfractuosity/musicplayer 3 | // 4 | // based on the work from 5 | // https://github.com/fulldecent/system-bus-radio Copyright 2016 William Entriken 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | __m128i reg; 16 | __m128i reg_zero; 17 | __m128i reg_one; 18 | 19 | #define NSEC_PER_SEC 1000000000 /* nanoseconds per second */ 20 | 21 | uint64_t mach_absolute_time(){ 22 | struct timespec start, end; 23 | clock_gettime(CLOCK_MONOTONIC, &start); /* mark start time */ 24 | return (uint64_t)start.tv_sec * NSEC_PER_SEC + start.tv_nsec; 25 | } 26 | 27 | // Derrived from http://dlbeer.co.nz/articles/pdm.html 28 | unsigned int * pdm(unsigned int *x,int len){ 29 | unsigned *y=malloc(len*sizeof(int)); 30 | unsigned int n = 0; 31 | unsigned int quant_error = 0; 32 | 33 | for (n=0;n= 65535) { 36 | quant_error -= 65535; 37 | y[n] = 1; 38 | continue; 39 | } 40 | y[n] = 0; 41 | } 42 | 43 | return y; 44 | } 45 | 46 | static inline void pdm_signal(int *pdm,int len,int samplerate) { 47 | int i = 0; 48 | 49 | for (i=0;i 1.0) { v = 1.0; } 72 | else if (v < -1.0) { v = -1.0; } 73 | v += 1.0; // remap from [-1.0,1.0] to [0.0,2.0] 74 | v /= 2; // remap from [0.0,2.0] to [0.0,1.0] 75 | r = v * 65535; // remap from [0.0,1.0] to [0,65535] 76 | return r; 77 | } 78 | 79 | 80 | int main ( int argc, char **argv ) { 81 | 82 | if(argc != 2){ 83 | printf("Need to pass audio file sampled at around 1 000 000 Hz\n"); 84 | return 1; 85 | }else{ 86 | printf("Attempting to load file: %s\n",argv[1]); 87 | } 88 | 89 | SNDFILE *infile; 90 | SF_INFO sfinfo ; 91 | int readcount ; 92 | 93 | if (! (infile = sf_open (argv[1], SFM_READ, &sfinfo))){ 94 | /* Open failed so print an error message. */ 95 | printf ("Not able to open input file %s.\n", argv[1]) ; 96 | /* Print the error message from libsndfile. */ 97 | puts (sf_strerror (NULL)) ; 98 | return 1 ; 99 | } 100 | 101 | if (sfinfo.channels > 1){ 102 | printf ("Not able to process more than 1 channels\n") ; 103 | return 1 ; 104 | } 105 | 106 | 107 | double *data = malloc(sfinfo.frames*sizeof(double)) ; 108 | 109 | unsigned int c; 110 | 111 | readcount = sf_read_double (infile, data,sfinfo.frames); 112 | 113 | unsigned int *nout = malloc(sizeof(int)*readcount); 114 | 115 | for(c=0;c